Merge pull request #188 from jakalkhalili/cr-removal-bug

#176 Add owner reference to seed job agent deployment
This commit is contained in:
Tomasz Sęk 2019-11-06 16:32:51 +01:00 committed by GitHub
commit ab65db22d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 150 additions and 130 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/go-logr/logr" "github.com/go-logr/logr"
"github.com/pkg/errors" "github.com/pkg/errors"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
@ -27,7 +28,36 @@ type backupTrigger struct {
ticker *time.Ticker ticker *time.Ticker
} }
var backupTriggers = map[string]backupTrigger{} type backupTriggers struct {
triggers map[string]backupTrigger
}
func (t *backupTriggers) stop(logger logr.Logger, namespace string, name string) {
key := t.key(namespace, name)
trigger, found := t.triggers[key]
if found {
logger.Info(fmt.Sprintf("Stopping backup trigger for '%s'", key))
trigger.ticker.Stop()
delete(t.triggers, key)
} else {
logger.V(log.VWarn).Info(fmt.Sprintf("Can't stop backup trigger for '%s', not found, skipping", key))
}
}
func (t *backupTriggers) get(namespace, name string) (backupTrigger, bool) {
trigger, found := t.triggers[t.key(namespace, name)]
return trigger, found
}
func (t *backupTriggers) key(namespace, name string) string {
return namespace + "/" + name
}
func (t *backupTriggers) add(namespace string, name string, trigger backupTrigger) {
t.triggers[t.key(namespace, name)] = trigger
}
var triggers = backupTriggers{triggers: make(map[string]backupTrigger)}
// BackupAndRestore represents Jenkins backup and restore client // BackupAndRestore represents Jenkins backup and restore client
type BackupAndRestore struct { type BackupAndRestore struct {
@ -169,7 +199,10 @@ func triggerBackup(ticker *time.Ticker, k8sClient k8s.Client, logger logr.Logger
for range ticker.C { for range ticker.C {
jenkins := &v1alpha2.Jenkins{} jenkins := &v1alpha2.Jenkins{}
err := k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: name}, jenkins) err := k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: name}, jenkins)
if err != nil { if err != nil && apierrors.IsNotFound(err) {
triggers.stop(logger, namespace, name)
return // abort
} else if err != nil {
logger.V(log.VWarn).Info(fmt.Sprintf("backup trigger, error when fetching CR: %s", err)) logger.V(log.VWarn).Info(fmt.Sprintf("backup trigger, error when fetching CR: %s", err))
} }
if jenkins.Status.LastBackup == jenkins.Status.PendingBackup { if jenkins.Status.LastBackup == jenkins.Status.PendingBackup {
@ -184,21 +217,22 @@ func triggerBackup(ticker *time.Ticker, k8sClient k8s.Client, logger logr.Logger
// EnsureBackupTrigger creates or update trigger which update CR to make backup // EnsureBackupTrigger creates or update trigger which update CR to make backup
func (bar *BackupAndRestore) EnsureBackupTrigger() error { func (bar *BackupAndRestore) EnsureBackupTrigger() error {
jenkins := bar.jenkins trigger, found := triggers.get(bar.jenkins.Namespace, bar.jenkins.Name)
trigger, found := backupTriggers[jenkins.Name]
if len(jenkins.Spec.Backup.ContainerName) == 0 || jenkins.Spec.Backup.Interval == 0 { isBackupConfigured := len(bar.jenkins.Spec.Backup.ContainerName) > 0 && bar.jenkins.Spec.Backup.Interval > 0
bar.logger.V(log.VDebug).Info("Skipping create backup trigger") if found && !isBackupConfigured {
if found { bar.StopBackupTrigger()
bar.stopBackupTrigger(trigger)
}
return nil return nil
} }
if !found { // configured backup has no trigger
if !found && isBackupConfigured {
bar.startBackupTrigger() bar.startBackupTrigger()
return nil
} }
if found && jenkins.Spec.Backup.Interval != trigger.interval {
bar.stopBackupTrigger(trigger) if found && isBackupConfigured && bar.jenkins.Spec.Backup.Interval != trigger.interval {
bar.StopBackupTrigger()
bar.startBackupTrigger() bar.startBackupTrigger()
} }
@ -207,28 +241,19 @@ func (bar *BackupAndRestore) EnsureBackupTrigger() error {
// StopBackupTrigger stops trigger which update CR to make backup // StopBackupTrigger stops trigger which update CR to make backup
func (bar *BackupAndRestore) StopBackupTrigger() { func (bar *BackupAndRestore) StopBackupTrigger() {
trigger, found := backupTriggers[bar.jenkins.Name] triggers.stop(bar.logger, bar.jenkins.Namespace, bar.jenkins.Name)
if found {
bar.stopBackupTrigger(trigger)
}
} }
func (bar *BackupAndRestore) startBackupTrigger() { func (bar *BackupAndRestore) startBackupTrigger() {
bar.logger.Info("Starting backup trigger") bar.logger.Info("Starting backup trigger")
ticker := time.NewTicker(time.Duration(bar.jenkins.Spec.Backup.Interval) * time.Second) ticker := time.NewTicker(time.Duration(bar.jenkins.Spec.Backup.Interval) * time.Second)
backupTriggers[bar.jenkins.Name] = backupTrigger{ triggers.add(bar.jenkins.Namespace, bar.jenkins.Name, backupTrigger{
interval: bar.jenkins.Spec.Backup.Interval, interval: bar.jenkins.Spec.Backup.Interval,
ticker: ticker, ticker: ticker,
} })
go triggerBackup(ticker, bar.k8sClient, bar.logger, bar.jenkins.Namespace, bar.jenkins.Name) go triggerBackup(ticker, bar.k8sClient, bar.logger, bar.jenkins.Namespace, bar.jenkins.Name)
} }
func (bar *BackupAndRestore) stopBackupTrigger(trigger backupTrigger) {
bar.logger.Info("Stopping backup trigger")
trigger.ticker.Stop()
delete(backupTriggers, bar.jenkins.Name)
}
func (bar *BackupAndRestore) exec(podName, containerName string, command []string) (stdout, stderr bytes.Buffer, err error) { func (bar *BackupAndRestore) exec(podName, containerName string, command []string) (stdout, stderr bytes.Buffer, err error) {
req := bar.clientSet.CoreV1().RESTClient().Post(). req := bar.clientSet.CoreV1().RESTClient().Post().
Resource("pods"). Resource("pods").

View File

@ -28,7 +28,6 @@ import (
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
@ -42,17 +41,15 @@ const (
// ReconcileJenkinsBaseConfiguration defines values required for Jenkins base configuration // ReconcileJenkinsBaseConfiguration defines values required for Jenkins base configuration
type ReconcileJenkinsBaseConfiguration struct { type ReconcileJenkinsBaseConfiguration struct {
configuration.Configuration configuration.Configuration
scheme *runtime.Scheme
logger logr.Logger logger logr.Logger
local, minikube bool local, minikube bool
config *rest.Config config *rest.Config
} }
// New create structure which takes care of base configuration // New create structure which takes care of base configuration
func New(config configuration.Configuration, scheme *runtime.Scheme, logger logr.Logger, local, minikube bool, restConfig *rest.Config) *ReconcileJenkinsBaseConfiguration { func New(config configuration.Configuration, logger logr.Logger, local, minikube bool, restConfig *rest.Config) *ReconcileJenkinsBaseConfiguration {
return &ReconcileJenkinsBaseConfiguration{ return &ReconcileJenkinsBaseConfiguration{
Configuration: config, Configuration: config,
scheme: scheme,
logger: logger, logger: logger,
local: local, local: local,
minikube: minikube, minikube: minikube,
@ -255,7 +252,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta
err := r.Configuration.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Configuration.Jenkins), Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, found) err := r.Configuration.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Configuration.Jenkins), Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, found)
if err != nil && apierrors.IsNotFound(err) { if err != nil && apierrors.IsNotFound(err) {
return stackerr.WithStack(r.createResource(resources.NewOperatorCredentialsSecret(meta, r.Configuration.Jenkins))) return stackerr.WithStack(r.CreateResource(resources.NewOperatorCredentialsSecret(meta, r.Configuration.Jenkins)))
} else if err != nil && !apierrors.IsNotFound(err) { } else if err != nil && !apierrors.IsNotFound(err) {
return stackerr.WithStack(err) return stackerr.WithStack(err)
} }
@ -265,7 +262,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta
return nil return nil
} }
return stackerr.WithStack(r.updateResource(resources.NewOperatorCredentialsSecret(meta, r.Configuration.Jenkins))) return stackerr.WithStack(r.UpdateResource(resources.NewOperatorCredentialsSecret(meta, r.Configuration.Jenkins)))
} }
func (r *ReconcileJenkinsBaseConfiguration) createScriptsConfigMap(meta metav1.ObjectMeta) error { func (r *ReconcileJenkinsBaseConfiguration) createScriptsConfigMap(meta metav1.ObjectMeta) error {
@ -273,7 +270,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createScriptsConfigMap(meta metav1.O
if err != nil { if err != nil {
return err return err
} }
return stackerr.WithStack(r.createOrUpdateResource(configMap)) return stackerr.WithStack(r.CreateOrUpdateResource(configMap))
} }
func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(meta metav1.ObjectMeta) error { func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(meta metav1.ObjectMeta) error {
@ -281,12 +278,12 @@ func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(met
if err != nil { if err != nil {
return err return err
} }
return stackerr.WithStack(r.createOrUpdateResource(configMap)) return stackerr.WithStack(r.CreateOrUpdateResource(configMap))
} }
func (r *ReconcileJenkinsBaseConfiguration) createBaseConfigurationConfigMap(meta metav1.ObjectMeta) error { func (r *ReconcileJenkinsBaseConfiguration) createBaseConfigurationConfigMap(meta metav1.ObjectMeta) error {
configMap := resources.NewBaseConfigurationConfigMap(meta, r.Configuration.Jenkins) configMap := resources.NewBaseConfigurationConfigMap(meta, r.Configuration.Jenkins)
return stackerr.WithStack(r.createOrUpdateResource(configMap)) return stackerr.WithStack(r.CreateOrUpdateResource(configMap))
} }
func (r *ReconcileJenkinsBaseConfiguration) addLabelForWatchesResources(customization v1alpha2.Customization) error { func (r *ReconcileJenkinsBaseConfiguration) addLabelForWatchesResources(customization v1alpha2.Customization) error {
@ -339,19 +336,19 @@ func (r *ReconcileJenkinsBaseConfiguration) addLabelForWatchesResources(customiz
func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) error { func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) error {
serviceAccount := resources.NewServiceAccount(meta) serviceAccount := resources.NewServiceAccount(meta)
err := r.createResource(serviceAccount) err := r.CreateResource(serviceAccount)
if err != nil && !errors.IsAlreadyExists(err) { if err != nil && !errors.IsAlreadyExists(err) {
return stackerr.WithStack(err) return stackerr.WithStack(err)
} }
role := resources.NewRole(meta) role := resources.NewRole(meta)
err = r.createOrUpdateResource(role) err = r.CreateOrUpdateResource(role)
if err != nil { if err != nil {
return stackerr.WithStack(err) return stackerr.WithStack(err)
} }
roleBinding := resources.NewRoleBinding(meta) roleBinding := resources.NewRoleBinding(meta)
err = r.createOrUpdateResource(roleBinding) err = r.CreateOrUpdateResource(roleBinding)
if err != nil { if err != nil {
return stackerr.WithStack(err) return stackerr.WithStack(err)
} }
@ -373,7 +370,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createService(meta metav1.ObjectMeta
Selector: meta.Labels, Selector: meta.Labels,
}, },
}, config) }, config)
if err = r.createResource(&service); err != nil { if err = r.CreateResource(&service); err != nil {
return stackerr.WithStack(err) return stackerr.WithStack(err)
} }
} else if err != nil { } else if err != nil {
@ -381,7 +378,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createService(meta metav1.ObjectMeta
} }
service = resources.UpdateService(service, config) service = resources.UpdateService(service, config)
return stackerr.WithStack(r.updateResource(&service)) return stackerr.WithStack(r.UpdateResource(&service))
} }
func (r *ReconcileJenkinsBaseConfiguration) getJenkinsMasterPod() (*corev1.Pod, error) { func (r *ReconcileJenkinsBaseConfiguration) getJenkinsMasterPod() (*corev1.Pod, error) {
@ -416,7 +413,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsMasterPod(meta metav1.O
Reason: reason.NewPodCreation(reason.OperatorSource, []string{"Creating a new Jenkins Master Pod"}), Reason: reason.NewPodCreation(reason.OperatorSource, []string{"Creating a new Jenkins Master Pod"}),
} }
r.logger.Info(fmt.Sprintf("Creating a new Jenkins Master Pod %s/%s", jenkinsMasterPod.Namespace, jenkinsMasterPod.Name)) r.logger.Info(fmt.Sprintf("Creating a new Jenkins Master Pod %s/%s", jenkinsMasterPod.Namespace, jenkinsMasterPod.Name))
err = r.createResource(jenkinsMasterPod) err = r.CreateResource(jenkinsMasterPod)
if err != nil { if err != nil {
return reconcile.Result{}, stackerr.WithStack(err) return reconcile.Result{}, stackerr.WithStack(err)
} }
@ -827,7 +824,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsClient(meta metav1.Obje
credentialsSecret.Data[resources.OperatorCredentialsSecretTokenKey] = []byte(token.GetToken()) credentialsSecret.Data[resources.OperatorCredentialsSecretTokenKey] = []byte(token.GetToken())
now, _ := time.Now().UTC().MarshalText() now, _ := time.Now().UTC().MarshalText()
credentialsSecret.Data[resources.OperatorCredentialsSecretTokenCreationKey] = now credentialsSecret.Data[resources.OperatorCredentialsSecretTokenCreationKey] = now
err = r.updateResource(credentialsSecret) err = r.UpdateResource(credentialsSecret)
if err != nil { if err != nil {
return nil, stackerr.WithStack(err) return nil, stackerr.WithStack(err)
} }

View File

@ -234,7 +234,7 @@ func TestCompareVolumes(t *testing.T) {
Volumes: resources.GetJenkinsMasterPodBaseVolumes(jenkins), Volumes: resources.GetJenkinsMasterPodBaseVolumes(jenkins),
}, },
} }
reconciler := New(configuration.Configuration{Jenkins: jenkins}, nil, nil, false, false, nil) reconciler := New(configuration.Configuration{Jenkins: jenkins}, nil, false, false, nil)
got := reconciler.compareVolumes(pod) got := reconciler.compareVolumes(pod)
@ -258,7 +258,7 @@ func TestCompareVolumes(t *testing.T) {
Volumes: resources.GetJenkinsMasterPodBaseVolumes(jenkins), Volumes: resources.GetJenkinsMasterPodBaseVolumes(jenkins),
}, },
} }
reconciler := New(configuration.Configuration{Jenkins: jenkins}, nil, nil, false, false, nil) reconciler := New(configuration.Configuration{Jenkins: jenkins}, nil, false, false, nil)
got := reconciler.compareVolumes(pod) got := reconciler.compareVolumes(pod)
@ -282,7 +282,7 @@ func TestCompareVolumes(t *testing.T) {
Volumes: append(resources.GetJenkinsMasterPodBaseVolumes(jenkins), corev1.Volume{Name: "added"}), Volumes: append(resources.GetJenkinsMasterPodBaseVolumes(jenkins), corev1.Volume{Name: "added"}),
}, },
} }
reconciler := New(configuration.Configuration{Jenkins: jenkins}, nil, nil, false, false, nil) reconciler := New(configuration.Configuration{Jenkins: jenkins}, nil, false, false, nil)
got := reconciler.compareVolumes(pod) got := reconciler.compareVolumes(pod)

View File

@ -1,56 +0,0 @@
package base
import (
"context"
stackerr "github.com/pkg/errors"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
func (r *ReconcileJenkinsBaseConfiguration) createResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// Set Jenkins instance as the owner and controller
if err := controllerutil.SetControllerReference(r.Configuration.Jenkins, obj, r.scheme); err != nil {
return stackerr.WithStack(err)
}
return r.Client.Create(context.TODO(), runtimeObj) // don't wrap error
}
func (r *ReconcileJenkinsBaseConfiguration) updateResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// set Jenkins instance as the owner and controller, don't check error(can be already set)
_ = controllerutil.SetControllerReference(r.Configuration.Jenkins, obj, r.scheme)
return r.Client.Update(context.TODO(), runtimeObj) // don't wrap error
}
func (r *ReconcileJenkinsBaseConfiguration) createOrUpdateResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// set Jenkins instance as the owner and controller, don't check error(can be already set)
_ = controllerutil.SetControllerReference(r.Configuration.Jenkins, obj, r.scheme)
err := r.Client.Create(context.TODO(), runtimeObj)
if err != nil && errors.IsAlreadyExists(err) {
return r.updateResource(obj)
} else if err != nil && !errors.IsAlreadyExists(err) {
return stackerr.WithStack(err)
}
return nil
}

View File

@ -23,7 +23,7 @@ import (
func TestValidatePlugins(t *testing.T) { func TestValidatePlugins(t *testing.T) {
log.SetupLogger(true) log.SetupLogger(true)
baseReconcileLoop := New(configuration.Configuration{}, nil, log.Log, false, false, nil) baseReconcileLoop := New(configuration.Configuration{}, log.Log, false, false, nil)
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
var requiredBasePlugins []plugins.Plugin var requiredBasePlugins []plugins.Plugin
var basePlugins []v1alpha2.Plugin var basePlugins []v1alpha2.Plugin
@ -166,7 +166,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, err := baseReconcileLoop.validateImagePullSecrets() got, err := baseReconcileLoop.validateImagePullSecrets()
fmt.Println(got) fmt.Println(got)
@ -190,7 +190,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, nil, false, false, nil) }, nil, false, false, nil)
got, _ := baseReconcileLoop.validateImagePullSecrets() got, _ := baseReconcileLoop.validateImagePullSecrets()
@ -226,7 +226,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, nil, false, false, nil) }, nil, false, false, nil)
got, _ := baseReconcileLoop.validateImagePullSecrets() got, _ := baseReconcileLoop.validateImagePullSecrets()
@ -262,7 +262,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, _ := baseReconcileLoop.validateImagePullSecrets() got, _ := baseReconcileLoop.validateImagePullSecrets()
@ -298,7 +298,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, _ := baseReconcileLoop.validateImagePullSecrets() got, _ := baseReconcileLoop.validateImagePullSecrets()
@ -334,7 +334,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, _ := baseReconcileLoop.validateImagePullSecrets() got, _ := baseReconcileLoop.validateImagePullSecrets()
@ -367,7 +367,7 @@ func TestValidateJenkinsMasterPodEnvs(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateJenkinsMasterPodEnvs() got := baseReconcileLoop.validateJenkinsMasterPodEnvs()
assert.Nil(t, got) assert.Nil(t, got)
}) })
@ -394,7 +394,7 @@ func TestValidateJenkinsMasterPodEnvs(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateJenkinsMasterPodEnvs() got := baseReconcileLoop.validateJenkinsMasterPodEnvs()
assert.Equal(t, got, []string{"Jenkins Master container env 'JENKINS_HOME' cannot be overridden"}) assert.Equal(t, got, []string{"Jenkins Master container env 'JENKINS_HOME' cannot be overridden"})
@ -418,7 +418,7 @@ func TestValidateJenkinsMasterPodEnvs(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateJenkinsMasterPodEnvs() got := baseReconcileLoop.validateJenkinsMasterPodEnvs()
assert.Equal(t, got, []string{"Jenkins Master container env 'JAVA_OPTS' doesn't have required flag '-Djava.awt.headless=true'"}) assert.Equal(t, got, []string{"Jenkins Master container env 'JAVA_OPTS' doesn't have required flag '-Djava.awt.headless=true'"})
@ -442,7 +442,7 @@ func TestValidateJenkinsMasterPodEnvs(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateJenkinsMasterPodEnvs() got := baseReconcileLoop.validateJenkinsMasterPodEnvs()
assert.Equal(t, got, []string{"Jenkins Master container env 'JAVA_OPTS' doesn't have required flag '-Djenkins.install.runSetupWizard=false'"}) assert.Equal(t, got, []string{"Jenkins Master container env 'JAVA_OPTS' doesn't have required flag '-Djenkins.install.runSetupWizard=false'"})
@ -464,7 +464,7 @@ func TestValidateReservedVolumes(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateReservedVolumes() got := baseReconcileLoop.validateReservedVolumes()
assert.Nil(t, got) assert.Nil(t, got)
}) })
@ -482,7 +482,7 @@ func TestValidateReservedVolumes(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateReservedVolumes() got := baseReconcileLoop.validateReservedVolumes()
assert.Equal(t, got, []string{"Jenkins Master pod volume 'jenkins-home' is reserved please choose different one"}) assert.Equal(t, got, []string{"Jenkins Master pod volume 'jenkins-home' is reserved please choose different one"})
@ -498,7 +498,7 @@ func TestValidateContainerVolumeMounts(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateContainerVolumeMounts(v1alpha2.Container{}) got := baseReconcileLoop.validateContainerVolumeMounts(v1alpha2.Container{})
assert.Nil(t, got) assert.Nil(t, got)
}) })
@ -526,7 +526,7 @@ func TestValidateContainerVolumeMounts(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Containers[0]) got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Containers[0])
assert.Nil(t, got) assert.Nil(t, got)
}) })
@ -554,7 +554,7 @@ func TestValidateContainerVolumeMounts(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Containers[0]) got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Containers[0])
assert.Equal(t, got, []string{"mountPath not set for 'example' volume mount in container ''"}) assert.Equal(t, got, []string{"mountPath not set for 'example' volume mount in container ''"})
}) })
@ -577,7 +577,7 @@ func TestValidateContainerVolumeMounts(t *testing.T) {
} }
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: &jenkins, Jenkins: &jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Containers[0]) got := baseReconcileLoop.validateContainerVolumeMounts(jenkins.Spec.Master.Containers[0])
assert.Equal(t, got, []string{"Not found volume for 'missing-volume' volume mount in container ''"}) assert.Equal(t, got, []string{"Not found volume for 'missing-volume' volume mount in container ''"})
@ -599,7 +599,7 @@ func TestValidateConfigMapVolume(t *testing.T) {
fakeClient := fake.NewFakeClient() fakeClient := fake.NewFakeClient()
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, err := baseReconcileLoop.validateConfigMapVolume(volume) got, err := baseReconcileLoop.validateConfigMapVolume(volume)
@ -627,7 +627,7 @@ func TestValidateConfigMapVolume(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: jenkins, Jenkins: jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, err := baseReconcileLoop.validateConfigMapVolume(volume) got, err := baseReconcileLoop.validateConfigMapVolume(volume)
@ -653,7 +653,7 @@ func TestValidateConfigMapVolume(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: jenkins, Jenkins: jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, err := baseReconcileLoop.validateConfigMapVolume(volume) got, err := baseReconcileLoop.validateConfigMapVolume(volume)
@ -678,7 +678,7 @@ func TestValidateSecretVolume(t *testing.T) {
fakeClient := fake.NewFakeClient() fakeClient := fake.NewFakeClient()
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, err := baseReconcileLoop.validateSecretVolume(volume) got, err := baseReconcileLoop.validateSecretVolume(volume)
@ -704,7 +704,7 @@ func TestValidateSecretVolume(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: jenkins, Jenkins: jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, err := baseReconcileLoop.validateSecretVolume(volume) got, err := baseReconcileLoop.validateSecretVolume(volume)
@ -728,7 +728,7 @@ func TestValidateSecretVolume(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Client: fakeClient, Client: fakeClient,
Jenkins: jenkins, Jenkins: jenkins,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, err := baseReconcileLoop.validateSecretVolume(volume) got, err := baseReconcileLoop.validateSecretVolume(volume)
assert.NoError(t, err) assert.NoError(t, err)
@ -752,7 +752,7 @@ func TestValidateCustomization(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: jenkins, Jenkins: jenkins,
Client: fakeClient, Client: fakeClient,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
got, err := baseReconcileLoop.validateCustomization(customization, "spec.groovyScripts") got, err := baseReconcileLoop.validateCustomization(customization, "spec.groovyScripts")
@ -774,7 +774,7 @@ func TestValidateCustomization(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: jenkins, Jenkins: jenkins,
Client: fakeClient, Client: fakeClient,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
err := fakeClient.Create(context.TODO(), secret) err := fakeClient.Create(context.TODO(), secret)
require.NoError(t, err) require.NoError(t, err)
@ -805,7 +805,7 @@ func TestValidateCustomization(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: jenkins, Jenkins: jenkins,
Client: fakeClient, Client: fakeClient,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
err := fakeClient.Create(context.TODO(), secret) err := fakeClient.Create(context.TODO(), secret)
require.NoError(t, err) require.NoError(t, err)
err = fakeClient.Create(context.TODO(), configMap) err = fakeClient.Create(context.TODO(), configMap)
@ -832,7 +832,7 @@ func TestValidateCustomization(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: jenkins, Jenkins: jenkins,
Client: fakeClient, Client: fakeClient,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
err := fakeClient.Create(context.TODO(), configMap) err := fakeClient.Create(context.TODO(), configMap)
require.NoError(t, err) require.NoError(t, err)
@ -857,7 +857,7 @@ func TestValidateCustomization(t *testing.T) {
baseReconcileLoop := New(configuration.Configuration{ baseReconcileLoop := New(configuration.Configuration{
Jenkins: jenkins, Jenkins: jenkins,
Client: fakeClient, Client: fakeClient,
}, nil, logf.ZapLogger(false), false, false, nil) }, logf.ZapLogger(false), false, false, nil)
err := fakeClient.Create(context.TODO(), secret) err := fakeClient.Create(context.TODO(), secret)
require.NoError(t, err) require.NoError(t, err)

View File

@ -10,9 +10,13 @@ import (
stackerr "github.com/pkg/errors" stackerr "github.com/pkg/errors"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
) )
// Configuration holds required for Jenkins configuration // Configuration holds required for Jenkins configuration
@ -21,6 +25,7 @@ type Configuration struct {
ClientSet kubernetes.Clientset ClientSet kubernetes.Clientset
Notifications *chan event.Event Notifications *chan event.Event
Jenkins *v1alpha2.Jenkins Jenkins *v1alpha2.Jenkins
Scheme *runtime.Scheme
} }
// RestartJenkinsMasterPod terminate Jenkins master pod and notifies about it // RestartJenkinsMasterPod terminate Jenkins master pod and notifies about it
@ -49,3 +54,51 @@ func (c *Configuration) getJenkinsMasterPod() (*corev1.Pod, error) {
} }
return currentJenkinsMasterPod, nil return currentJenkinsMasterPod, nil
} }
// CreateResource is creating kubernetes resource and references it to Jenkins CR
func (c *Configuration) CreateResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// Set Jenkins instance as the owner and controller
if err := controllerutil.SetControllerReference(c.Jenkins, obj, c.Scheme); err != nil {
return stackerr.WithStack(err)
}
return c.Client.Create(context.TODO(), runtimeObj) // don't wrap error
}
// UpdateResource is updating kubernetes resource and references it to Jenkins CR
func (c *Configuration) UpdateResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// set Jenkins instance as the owner and controller, don't check error(can be already set)
_ = controllerutil.SetControllerReference(c.Jenkins, obj, c.Scheme)
return c.Client.Update(context.TODO(), runtimeObj) // don't wrap error
}
// CreateOrUpdateResource is creating or updating kubernetes resource and references it to Jenkins CR
func (c *Configuration) CreateOrUpdateResource(obj metav1.Object) error {
runtimeObj, ok := obj.(runtime.Object)
if !ok {
return stackerr.Errorf("is not a %T a runtime.Object", obj)
}
// set Jenkins instance as the owner and controller, don't check error(can be already set)
_ = controllerutil.SetControllerReference(c.Jenkins, obj, c.Scheme)
err := c.Client.Create(context.TODO(), runtimeObj)
if err != nil && errors.IsAlreadyExists(err) {
return c.UpdateResource(obj)
} else if err != nil && !errors.IsAlreadyExists(err) {
return stackerr.WithStack(err)
}
return nil
}

View File

@ -214,10 +214,11 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request, logger logr.Logg
ClientSet: r.clientSet, ClientSet: r.clientSet,
Notifications: r.notificationEvents, Notifications: r.notificationEvents,
Jenkins: jenkins, Jenkins: jenkins,
Scheme: r.scheme,
} }
// Reconcile base configuration // Reconcile base configuration
baseConfiguration := base.New(config, r.scheme, logger, r.local, r.minikube, &r.config) baseConfiguration := base.New(config, logger, r.local, r.minikube, &r.config)
baseMessages, err := baseConfiguration.Validate(jenkins) baseMessages, err := baseConfiguration.Validate(jenkins)
if err != nil { if err != nil {

View File

@ -39,12 +39,12 @@ func TestUndefined_HasMessages(t *testing.T) {
podRestart := NewUndefined(KubernetesSource, []string{"test", "another-test"}) podRestart := NewUndefined(KubernetesSource, []string{"test", "another-test"})
assert.True(t, podRestart.HasMessages()) assert.True(t, podRestart.HasMessages())
}) })
t.Run("verbose full", func(t *testing.T) { t.Run("verbose full", func(t *testing.T) {
podRestart := NewUndefined(KubernetesSource, []string{}, []string{"test", "another-test"}...) podRestart := NewUndefined(KubernetesSource, []string{}, []string{"test", "another-test"}...)
assert.True(t, podRestart.HasMessages()) assert.True(t, podRestart.HasMessages())
}) })
t.Run("short empty", func(t *testing.T) { t.Run("short empty", func(t *testing.T) {
podRestart := NewUndefined(KubernetesSource, []string{}) podRestart := NewUndefined(KubernetesSource, []string{})
assert.False(t, podRestart.HasMessages()) assert.False(t, podRestart.HasMessages())