Refactoring for jenkins client (#366)
This commit is contained in:
parent
12ecfaa2b3
commit
eb8b2e32e8
2
go.mod
2
go.mod
|
|
@ -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
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -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=
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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{
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ package configuration
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications/reason"
|
||||
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/client"
|
||||
stackerr "github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
|
|
@ -25,17 +27,18 @@ import (
|
|||
|
||||
// Configuration holds required for Jenkins configuration
|
||||
type Configuration struct {
|
||||
Client client.Client
|
||||
ClientSet kubernetes.Clientset
|
||||
Notifications *chan event.Event
|
||||
Jenkins *v1alpha2.Jenkins
|
||||
Scheme *runtime.Scheme
|
||||
Config *rest.Config
|
||||
Client client.Client
|
||||
ClientSet kubernetes.Clientset
|
||||
Notifications *chan event.Event
|
||||
Jenkins *v1alpha2.Jenkins
|
||||
Scheme *runtime.Scheme
|
||||
Config *rest.Config
|
||||
JenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings
|
||||
}
|
||||
|
||||
// RestartJenkinsMasterPod terminate Jenkins master pod and notifies about it
|
||||
func (c *Configuration) RestartJenkinsMasterPod(reason reason.Reason) error {
|
||||
currentJenkinsMasterPod, err := c.getJenkinsMasterPod()
|
||||
currentJenkinsMasterPod, err := c.GetJenkinsMasterPod()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -54,7 +57,8 @@ func (c *Configuration) RestartJenkinsMasterPod(reason reason.Reason) error {
|
|||
return stackerr.WithStack(c.Client.Delete(context.TODO(), currentJenkinsMasterPod))
|
||||
}
|
||||
|
||||
func (c *Configuration) getJenkinsMasterPod() (*corev1.Pod, error) {
|
||||
// GetJenkinsMasterPod gets the jenkins master pod
|
||||
func (c *Configuration) GetJenkinsMasterPod() (*corev1.Pod, error) {
|
||||
jenkinsMasterPodName := resources.GetJenkinsMasterPodName(*c.Jenkins)
|
||||
currentJenkinsMasterPod := &corev1.Pod{}
|
||||
err := c.Client.Get(context.TODO(), types.NamespacedName{Name: jenkinsMasterPodName, Namespace: c.Jenkins.Namespace}, currentJenkinsMasterPod)
|
||||
|
|
@ -159,3 +163,130 @@ func (c *Configuration) GetJenkinsMasterContainer() *v1alpha2.Container {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetJenkinsClient gets jenkins client from a configuration
|
||||
func (c *Configuration) GetJenkinsClient() (jenkinsclient.Jenkins, error) {
|
||||
switch c.Jenkins.Spec.JenkinsAPISettings.AuthorizationStrategy {
|
||||
case v1alpha2.ServiceAccountAuthorizationStrategy:
|
||||
return c.GetJenkinsClientFromServiceAccount()
|
||||
case v1alpha2.CreateUserAuthorizationStrategy:
|
||||
return c.GetJenkinsClientFromSecret()
|
||||
default:
|
||||
return nil, stackerr.Errorf("unrecognized '%s' spec.jenkinsAPISettings.authorizationStrategy", c.Jenkins.Spec.JenkinsAPISettings.AuthorizationStrategy)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Configuration) getJenkinsAPIUrl() (string, error) {
|
||||
var service corev1.Service
|
||||
|
||||
err := c.Client.Get(context.TODO(), types.NamespacedName{
|
||||
Namespace: c.Jenkins.ObjectMeta.Namespace,
|
||||
Name: resources.GetJenkinsHTTPServiceName(c.Jenkins),
|
||||
}, &service)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
jenkinsURL := c.JenkinsAPIConnectionSettings.BuildJenkinsAPIUrl(service.Name, service.Namespace, service.Spec.Ports[0].Port, service.Spec.Ports[0].NodePort)
|
||||
if prefix, ok := GetJenkinsOpts(*c.Jenkins)["prefix"]; ok {
|
||||
jenkinsURL = jenkinsURL + prefix
|
||||
}
|
||||
return jenkinsURL, nil
|
||||
}
|
||||
|
||||
// GetJenkinsClientFromServiceAccount gets jenkins client from a serviceAccount
|
||||
func (c *Configuration) GetJenkinsClientFromServiceAccount() (jenkinsclient.Jenkins, error) {
|
||||
jenkinsAPIUrl, err := c.getJenkinsAPIUrl()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
podName := resources.GetJenkinsMasterPodName(*c.Jenkins)
|
||||
token, _, err := c.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())
|
||||
}
|
||||
|
||||
// GetJenkinsClientFromSecret gets jenkins client from a secret
|
||||
func (c *Configuration) GetJenkinsClientFromSecret() (jenkinsclient.Jenkins, error) {
|
||||
jenkinsURL, err := c.getJenkinsAPIUrl()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
credentialsSecret := &corev1.Secret{}
|
||||
err = c.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(c.Jenkins), Namespace: c.Jenkins.ObjectMeta.Namespace}, credentialsSecret)
|
||||
if err != nil {
|
||||
return nil, stackerr.WithStack(err)
|
||||
}
|
||||
currentJenkinsMasterPod, err := c.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()) {
|
||||
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 = c.UpdateResource(credentialsSecret)
|
||||
if err != nil {
|
||||
return nil, stackerr.WithStack(err)
|
||||
}
|
||||
}
|
||||
return jenkinsclient.NewUserAndPasswordAuthorization(
|
||||
jenkinsURL,
|
||||
string(credentialsSecret.Data[resources.OperatorCredentialsSecretUserNameKey]),
|
||||
string(credentialsSecret.Data[resources.OperatorCredentialsSecretTokenKey]))
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
package configuration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
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")
|
||||
})
|
||||
}
|
||||
|
|
@ -381,7 +381,7 @@ func agentDeployment(jenkins *v1alpha2.Jenkins, namespace string, agentName stri
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jenkinsHttpServiceFQDN, err := resources.GetJenkinsHTTPServiceFQDN(jenkins)
|
||||
jenkinsHTTPServiceFQDN, err := resources.GetJenkinsHTTPServiceFQDN(jenkins)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -428,7 +428,7 @@ func agentDeployment(jenkins *v1alpha2.Jenkins, namespace string, agentName stri
|
|||
{
|
||||
Name: "JENKINS_URL",
|
||||
Value: fmt.Sprintf("http://%s:%d",
|
||||
jenkinsHttpServiceFQDN,
|
||||
jenkinsHTTPServiceFQDN,
|
||||
jenkins.Spec.Service.Port,
|
||||
),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -227,12 +227,13 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request, logger logr.Logg
|
|||
}
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: r.client,
|
||||
ClientSet: r.clientSet,
|
||||
Notifications: r.notificationEvents,
|
||||
Jenkins: jenkins,
|
||||
Scheme: r.scheme,
|
||||
Config: &r.config,
|
||||
Client: r.client,
|
||||
ClientSet: r.clientSet,
|
||||
Notifications: r.notificationEvents,
|
||||
Jenkins: jenkins,
|
||||
Scheme: r.scheme,
|
||||
Config: &r.config,
|
||||
JenkinsAPIConnectionSettings: r.jenkinsAPIConnectionSettings,
|
||||
}
|
||||
|
||||
// Reconcile base configuration
|
||||
|
|
|
|||
Loading…
Reference in New Issue