Skip to content

Commit

Permalink
Refactoring for jenkins client (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkhelil authored May 6, 2020
1 parent 12ecfaa commit eb8b2e3
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 295 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require (
go.uber.org/zap v1.14.1
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
golang.org/x/tools v0.0.0-20200504022951-6b6965ac5dd1 // indirect
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
k8s.io/api v0.17.4
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,8 @@ golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b h1:zSzQJAznWxAh9fZxiPy2FZo
golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200504022951-6b6965ac5dd1 h1:C8rdnd6KieI73Z2Av0sS0t4kW+geIH/M8kNX8Hmvn9E=
golang.org/x/tools v0.0.0-20200504022951-6b6965ac5dd1/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8 h1:BMFHd4OFnFtWX46Xj4DN6vvT1btiBxyq+s0orYBqcQY=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/jenkins/configuration/base/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsMasterPod(meta metav1.O
}

// Check if this Pod already exists
currentJenkinsMasterPod, err := r.getJenkinsMasterPod()
currentJenkinsMasterPod, err := r.Configuration.GetJenkinsMasterPod()
if err != nil && apierrors.IsNotFound(err) {
jenkinsMasterPod := resources.NewJenkinsMasterPod(meta, r.Configuration.Jenkins)
*r.Notifications <- event.Event{
Expand Down
146 changes: 5 additions & 141 deletions pkg/controller/jenkins/configuration/base/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenki
}
r.logger.V(log.VDebug).Info("Jenkins master pod is ready")

jenkinsClient, err := r.ensureJenkinsClient()
jenkinsClient, err := r.Configuration.GetJenkinsClient()
if err != nil {
return reconcile.Result{}, nil, err
}
Expand All @@ -110,32 +110,6 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenki
return result, jenkinsClient, err
}

// GetJenkinsOpts gets JENKINS_OPTS env parameter, parses it's values and returns it as a map`
func GetJenkinsOpts(jenkins v1alpha2.Jenkins) map[string]string {
envs := jenkins.Spec.Master.Containers[0].Env
jenkinsOpts := make(map[string]string)

for key, value := range envs {
if value.Name == "JENKINS_OPTS" {
jenkinsOptsEnv := envs[key]
jenkinsOptsWithDashes := jenkinsOptsEnv.Value
if len(jenkinsOptsWithDashes) == 0 {
return nil
}

jenkinsOptsWithEqOperators := strings.Split(jenkinsOptsWithDashes, " ")

for _, vx := range jenkinsOptsWithEqOperators {
opt := strings.Split(vx, "=")
jenkinsOpts[strings.ReplaceAll(opt[0], "--", "")] = opt[1]
}

return jenkinsOpts
}
}
return nil
}

func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod(metaObject metav1.ObjectMeta) error {
if err := r.createOperatorCredentialsSecret(metaObject); err != nil {
return err
Expand Down Expand Up @@ -216,16 +190,6 @@ func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta
return stackerr.WithStack(r.UpdateResource(resources.NewOperatorCredentialsSecret(meta, r.Configuration.Jenkins)))
}

func (r *ReconcileJenkinsBaseConfiguration) getJenkinsMasterPod() (*corev1.Pod, error) {
jenkinsMasterPodName := resources.GetJenkinsMasterPodName(*r.Configuration.Jenkins)
currentJenkinsMasterPod := &corev1.Pod{}
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: jenkinsMasterPodName, Namespace: r.Configuration.Jenkins.Namespace}, currentJenkinsMasterPod)
if err != nil {
return nil, err // don't wrap error
}
return currentJenkinsMasterPod, nil
}

func (r *ReconcileJenkinsBaseConfiguration) calculateUserAndPasswordHash() (string, error) {
credentialsSecret := &corev1.Secret{}
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Configuration.Jenkins), Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, credentialsSecret)
Expand Down Expand Up @@ -309,7 +273,7 @@ func (r *ReconcileJenkinsBaseConfiguration) compareVolumes(actualPod corev1.Pod)
}

func (r *ReconcileJenkinsBaseConfiguration) detectJenkinsMasterPodStartingIssues() (stopReconcileLoop bool, err error) {
jenkinsMasterPod, err := r.getJenkinsMasterPod()
jenkinsMasterPod, err := r.Configuration.GetJenkinsMasterPod()
if err != nil {
return false, err
}
Expand Down Expand Up @@ -360,7 +324,7 @@ func (r *ReconcileJenkinsBaseConfiguration) filterEvents(source corev1.EventList
}

func (r *ReconcileJenkinsBaseConfiguration) waitForJenkins() (reconcile.Result, error) {
jenkinsMasterPod, err := r.getJenkinsMasterPod()
jenkinsMasterPod, err := r.Configuration.GetJenkinsMasterPod()
if err != nil {
return reconcile.Result{}, err
}
Expand Down Expand Up @@ -400,106 +364,6 @@ func (r *ReconcileJenkinsBaseConfiguration) waitForJenkins() (reconcile.Result,
return reconcile.Result{}, nil
}

func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsClient() (jenkinsclient.Jenkins, error) {
switch r.Configuration.Jenkins.Spec.JenkinsAPISettings.AuthorizationStrategy {
case v1alpha2.ServiceAccountAuthorizationStrategy:
return r.ensureJenkinsClientFromServiceAccount()
case v1alpha2.CreateUserAuthorizationStrategy:
return r.ensureJenkinsClientFromSecret()
default:
return nil, stackerr.Errorf("unrecognized '%s' spec.jenkinsAPISettings.authorizationStrategy", r.Configuration.Jenkins.Spec.JenkinsAPISettings.AuthorizationStrategy)
}
}

func (r *ReconcileJenkinsBaseConfiguration) getJenkinsAPIUrl() (string, error) {
var service corev1.Service

err := r.Client.Get(context.TODO(), types.NamespacedName{
Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace,
Name: resources.GetJenkinsHTTPServiceName(r.Configuration.Jenkins),
}, &service)

if err != nil {
return "", err
}
jenkinsURL := r.jenkinsAPIConnectionSettings.BuildJenkinsAPIUrl(service.Name, service.Namespace, service.Spec.Ports[0].Port, service.Spec.Ports[0].NodePort)
if prefix, ok := GetJenkinsOpts(*r.Configuration.Jenkins)["prefix"]; ok {
jenkinsURL = jenkinsURL + prefix
}
return jenkinsURL, nil
}

func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsClientFromServiceAccount() (jenkinsclient.Jenkins, error) {
jenkinsAPIUrl, err := r.getJenkinsAPIUrl()
if err != nil {
return nil, err
}

podName := resources.GetJenkinsMasterPodName(*r.Configuration.Jenkins)
token, _, err := r.Configuration.Exec(podName, resources.JenkinsMasterContainerName, []string{"cat", "/var/run/secrets/kubernetes.io/serviceaccount/token"})
if err != nil {
return nil, err
}

return jenkinsclient.NewBearerTokenAuthorization(jenkinsAPIUrl, token.String())
}

func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsClientFromSecret() (jenkinsclient.Jenkins, error) {
jenkinsURL, err := r.getJenkinsAPIUrl()
if err != nil {
return nil, err
}
r.logger.V(log.VDebug).Info(fmt.Sprintf("Jenkins API URL '%s'", jenkinsURL))
credentialsSecret := &corev1.Secret{}
err = r.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Configuration.Jenkins), Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, credentialsSecret)
if err != nil {
return nil, stackerr.WithStack(err)
}
currentJenkinsMasterPod, err := r.getJenkinsMasterPod()
if err != nil {
return nil, err
}
var tokenCreationTime *time.Time
tokenCreationTimeBytes := credentialsSecret.Data[resources.OperatorCredentialsSecretTokenCreationKey]
if tokenCreationTimeBytes != nil {
tokenCreationTime = &time.Time{}
err = tokenCreationTime.UnmarshalText(tokenCreationTimeBytes)
if err != nil {
tokenCreationTime = nil
}
}
if credentialsSecret.Data[resources.OperatorCredentialsSecretTokenKey] == nil ||
tokenCreationTimeBytes == nil || tokenCreationTime == nil ||
currentJenkinsMasterPod.ObjectMeta.CreationTimestamp.Time.UTC().After(tokenCreationTime.UTC()) {
r.logger.Info("Generating Jenkins API token for operator")
userName := string(credentialsSecret.Data[resources.OperatorCredentialsSecretUserNameKey])
jenkinsClient, err := jenkinsclient.NewUserAndPasswordAuthorization(
jenkinsURL,
userName,
string(credentialsSecret.Data[resources.OperatorCredentialsSecretPasswordKey]))
if err != nil {
return nil, err
}

token, err := jenkinsClient.GenerateToken(userName, "token")
if err != nil {
return nil, err
}

credentialsSecret.Data[resources.OperatorCredentialsSecretTokenKey] = []byte(token.GetToken())
now, _ := time.Now().UTC().MarshalText()
credentialsSecret.Data[resources.OperatorCredentialsSecretTokenCreationKey] = now
err = r.UpdateResource(credentialsSecret)
if err != nil {
return nil, stackerr.WithStack(err)
}
}
return jenkinsclient.NewUserAndPasswordAuthorization(
jenkinsURL,
string(credentialsSecret.Data[resources.OperatorCredentialsSecretUserNameKey]),
string(credentialsSecret.Data[resources.OperatorCredentialsSecretTokenKey]))
}

func (r *ReconcileJenkinsBaseConfiguration) ensureBaseConfiguration(jenkinsClient jenkinsclient.Jenkins) (reconcile.Result, error) {
customization := v1alpha2.GroovyScripts{
Customization: v1alpha2.Customization{
Expand All @@ -517,14 +381,14 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureBaseConfiguration(jenkinsClien
}

func (r *ReconcileJenkinsBaseConfiguration) waitUntilCreateJenkinsMasterPod() (currentJenkinsMasterPod *corev1.Pod, err error) {
currentJenkinsMasterPod, err = r.getJenkinsMasterPod()
currentJenkinsMasterPod, err = r.Configuration.GetJenkinsMasterPod()
for {
if err != nil && !apierrors.IsNotFound(err) {
return nil, stackerr.WithStack(err)
} else if err == nil {
break
}
currentJenkinsMasterPod, err = r.getJenkinsMasterPod()
currentJenkinsMasterPod, err = r.Configuration.GetJenkinsMasterPod()
time.Sleep(time.Millisecond * 10)
}
return
Expand Down
135 changes: 0 additions & 135 deletions pkg/controller/jenkins/configuration/base/reconcile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources"
"github.com/jenkinsci/kubernetes-operator/pkg/log"

"github.com/bndr/gojenkins"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
Expand All @@ -22,140 +21,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestGetJenkinsOpts(t *testing.T) {
t.Run("JENKINS_OPTS is uninitialized", func(t *testing.T) {
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
{
Env: []corev1.EnvVar{
{Name: "", Value: ""},
},
},
},
},
},
}

opts := GetJenkinsOpts(jenkins)
assert.Equal(t, 0, len(opts))
})

t.Run("JENKINS_OPTS is empty", func(t *testing.T) {
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
{
Env: []corev1.EnvVar{
{Name: "JENKINS_OPTS", Value: ""},
},
},
},
},
},
}

opts := GetJenkinsOpts(jenkins)
assert.Equal(t, 0, len(opts))
})

t.Run("JENKINS_OPTS have --prefix argument ", func(t *testing.T) {
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
{
Env: []corev1.EnvVar{
{Name: "JENKINS_OPTS", Value: "--prefix=/jenkins"},
},
},
},
},
},
}

opts := GetJenkinsOpts(jenkins)

assert.Equal(t, 1, len(opts))
assert.NotContains(t, opts, "httpPort")
assert.Contains(t, opts, "prefix")
assert.Equal(t, opts["prefix"], "/jenkins")
})

t.Run("JENKINS_OPTS have --prefix and --httpPort argument", func(t *testing.T) {
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
{
Env: []corev1.EnvVar{
{Name: "JENKINS_OPTS", Value: "--prefix=/jenkins --httpPort=8080"},
},
},
},
},
},
}

opts := GetJenkinsOpts(jenkins)

assert.Equal(t, 2, len(opts))

assert.Contains(t, opts, "prefix")
assert.Equal(t, opts["prefix"], "/jenkins")

assert.Contains(t, opts, "httpPort")
assert.Equal(t, opts["httpPort"], "8080")
})

t.Run("JENKINS_OPTS have --httpPort argument", func(t *testing.T) {
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
{
Env: []corev1.EnvVar{
{Name: "JENKINS_OPTS", Value: "--httpPort=8080"},
},
},
},
},
},
}

opts := GetJenkinsOpts(jenkins)

assert.Equal(t, 1, len(opts))
assert.NotContains(t, opts, "prefix")
assert.Contains(t, opts, "httpPort")
assert.Equal(t, opts["httpPort"], "8080")
})

t.Run("JENKINS_OPTS have --httpPort=--8080 argument", func(t *testing.T) {
jenkins := v1alpha2.Jenkins{
Spec: v1alpha2.JenkinsSpec{
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
{
Env: []corev1.EnvVar{
{Name: "JENKINS_OPTS", Value: "--httpPort=--8080"},
},
},
},
},
},
}

opts := GetJenkinsOpts(jenkins)

assert.Equal(t, 1, len(opts))
assert.NotContains(t, opts, "prefix")
assert.Contains(t, opts, "httpPort")
assert.Equal(t, opts["httpPort"], "--8080")
})
}

func TestCompareContainerVolumeMounts(t *testing.T) {
t.Run("happy with service account", func(t *testing.T) {
Expand Down
Loading

0 comments on commit eb8b2e3

Please sign in to comment.