From dd04c0cf5b2a11e82905b7a798425965afb2f769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20S=C4=99k?= Date: Thu, 14 Feb 2019 19:36:55 +0100 Subject: [PATCH] Remove backup mechanism --- Gopkg.lock | 64 +---- pkg/apis/jenkinsio/v1alpha1/jenkins_types.go | 27 +- .../v1alpha1/zz_generated.deepcopy.go | 17 -- pkg/controller/jenkins/backup/aws/s3.go | 240 ------------------ pkg/controller/jenkins/backup/aws/s3_test.go | 165 ------------ pkg/controller/jenkins/backup/backup.go | 157 ------------ .../jenkins/backup/nobackup/nobackup.go | 52 ---- .../jenkins/configuration/base/reconcile.go | 61 +---- .../configuration/base/reconcile_test.go | 116 --------- .../resources/backup_credentials_secret.go | 30 --- .../resources/base_configuration_configmap.go | 2 +- .../configuration/base/resources/pod.go | 29 --- .../base/resources/scripts_configmap.go | 66 ----- .../jenkins/configuration/base/validate.go | 56 ---- .../configuration/base/validate_test.go | 90 ------- .../jenkins/configuration/user/reconcile.go | 21 +- .../jenkins/configuration/user/validate.go | 8 +- pkg/controller/jenkins/constants/constants.go | 8 - pkg/controller/jenkins/jenkins_controller.go | 6 - test/e2e/aws_s3_backup_test.go | 157 ------------ test/e2e/main_test.go | 9 +- 21 files changed, 11 insertions(+), 1370 deletions(-) delete mode 100644 pkg/controller/jenkins/backup/aws/s3.go delete mode 100644 pkg/controller/jenkins/backup/aws/s3_test.go delete mode 100644 pkg/controller/jenkins/backup/backup.go delete mode 100644 pkg/controller/jenkins/backup/nobackup/nobackup.go delete mode 100644 pkg/controller/jenkins/configuration/base/reconcile_test.go delete mode 100644 pkg/controller/jenkins/configuration/base/resources/backup_credentials_secret.go delete mode 100644 test/e2e/aws_s3_backup_test.go diff --git a/Gopkg.lock b/Gopkg.lock index c836b1cc..70e330fb 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -33,49 +33,6 @@ pruneopts = "NT" revision = "de5bf2ad457846296e2031421a34e2568e304e35" -[[projects]] - digest = "1:d6d8c5e82a2ac7f2d44a9cd37412f72c4c0342b61ed5fa57e0c6c53bf3f1a4cc" - name = "github.com/aws/aws-sdk-go" - packages = [ - "aws", - "aws/awserr", - "aws/awsutil", - "aws/client", - "aws/client/metadata", - "aws/corehandlers", - "aws/credentials", - "aws/credentials/ec2rolecreds", - "aws/credentials/endpointcreds", - "aws/credentials/processcreds", - "aws/credentials/stscreds", - "aws/csm", - "aws/defaults", - "aws/ec2metadata", - "aws/endpoints", - "aws/request", - "aws/session", - "aws/signer/v4", - "internal/ini", - "internal/s3err", - "internal/sdkio", - "internal/sdkrand", - "internal/sdkuri", - "internal/shareddefaults", - "private/protocol", - "private/protocol/eventstream", - "private/protocol/eventstream/eventstreamapi", - "private/protocol/query", - "private/protocol/query/queryutil", - "private/protocol/rest", - "private/protocol/restxml", - "private/protocol/xml/xmlutil", - "service/s3", - "service/sts", - ] - pruneopts = "NT" - revision = "a2484497433aa110263c045df2f1d49336b38cfd" - version = "v1.16.22" - [[projects]] digest = "1:8d13c70d5898b091728540686c696baee0d64013b8e43089da80621a49410391" name = "github.com/bndr/gojenkins" @@ -292,13 +249,6 @@ revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4" version = "v0.3.6" -[[projects]] - digest = "1:1234e31f3de67447e344dabcdf72c4588d31b8eed2d28f1889377ec006a086a9" - name = "github.com/jmespath/go-jmespath" - packages = ["."] - pruneopts = "NT" - revision = "c2b33e84" - [[projects]] digest = "1:f5b9328966ccea0970b1d15075698eff0ddb3e75889560aad2e9f76b289b536a" name = "github.com/joho/godotenv" @@ -468,10 +418,7 @@ [[projects]] digest = "1:4af061277c04a7660e082acc2020f4c66d2c21dfc62e0242ffa1d2120cdfb4ec" name = "github.com/stretchr/testify" - packages = [ - "assert", - "require", - ] + packages = ["assert"] pruneopts = "NT" revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" version = "v1.2.2" @@ -517,7 +464,7 @@ [[projects]] branch = "master" - digest = "1:a7fcf4f3e5247a06ad4c28108f0bc1d4ab980a1a0567e7790260cf2d3d77f37d" + digest = "1:922c0bb9dc59af35400f6725ed08582f99f710ffc1a1075e8914c73515bb269e" name = "golang.org/x/net" packages = [ "context", @@ -530,7 +477,7 @@ "idna", ] pruneopts = "NT" - revision = "c10e9556a7bc0e7c942242b606f0acf024ad5d6a" + revision = "3a22650c66bd7f4fb6d1e8072ffd7b75c8a27898" [[projects]] branch = "master" @@ -914,10 +861,6 @@ analyzer-name = "dep" analyzer-version = 1 input-imports = [ - "github.com/aws/aws-sdk-go/aws", - "github.com/aws/aws-sdk-go/aws/credentials", - "github.com/aws/aws-sdk-go/aws/session", - "github.com/aws/aws-sdk-go/service/s3", "github.com/bndr/gojenkins", "github.com/docker/distribution/reference", "github.com/go-logr/logr", @@ -930,7 +873,6 @@ "github.com/operator-framework/operator-sdk/version", "github.com/pkg/errors", "github.com/stretchr/testify/assert", - "github.com/stretchr/testify/require", "k8s.io/api/core/v1", "k8s.io/api/rbac/v1", "k8s.io/apimachinery/pkg/api/errors", diff --git a/pkg/apis/jenkinsio/v1alpha1/jenkins_types.go b/pkg/apis/jenkinsio/v1alpha1/jenkins_types.go index a3738130..e4dd8cda 100644 --- a/pkg/apis/jenkinsio/v1alpha1/jenkins_types.go +++ b/pkg/apis/jenkinsio/v1alpha1/jenkins_types.go @@ -12,30 +12,8 @@ import ( type JenkinsSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file - Backup JenkinsBackup `json:"backup,omitempty"` - BackupAmazonS3 JenkinsBackupAmazonS3 `json:"backupAmazonS3,omitempty"` - Master JenkinsMaster `json:"master,omitempty"` - SeedJobs []SeedJob `json:"seedJobs,omitempty"` -} - -// JenkinsBackup defines type of Jenkins backup -type JenkinsBackup string - -const ( - // JenkinsBackupTypeNoBackup tells that Jenkins won't backup jobs - JenkinsBackupTypeNoBackup = "NoBackup" - // JenkinsBackupTypeAmazonS3 tells that Jenkins will backup jobs into AWS S3 bucket - JenkinsBackupTypeAmazonS3 = "AmazonS3" -) - -// AllowedJenkinsBackups consists allowed Jenkins backup types -var AllowedJenkinsBackups = []JenkinsBackup{JenkinsBackupTypeNoBackup, JenkinsBackupTypeAmazonS3} - -// JenkinsBackupAmazonS3 defines backup configuration to AWS S3 bucket -type JenkinsBackupAmazonS3 struct { - BucketName string `json:"bucketName,omitempty"` - BucketPath string `json:"bucketPath,omitempty"` - Region string `json:"region,omitempty"` + Master JenkinsMaster `json:"master,omitempty"` + SeedJobs []SeedJob `json:"seedJobs,omitempty"` } // JenkinsMaster defines the Jenkins master pod attributes and plugins, @@ -51,7 +29,6 @@ type JenkinsMaster struct { type JenkinsStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file - BackupRestored bool `json:"backupRestored,omitempty"` BaseConfigurationCompletedTime *metav1.Time `json:"baseConfigurationCompletedTime,omitempty"` UserConfigurationCompletedTime *metav1.Time `json:"userConfigurationCompletedTime,omitempty"` Builds []Build `json:"builds,omitempty"` diff --git a/pkg/apis/jenkinsio/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/jenkinsio/v1alpha1/zz_generated.deepcopy.go index 06cb4f48..f283db4f 100644 --- a/pkg/apis/jenkinsio/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/jenkinsio/v1alpha1/zz_generated.deepcopy.go @@ -77,22 +77,6 @@ func (in *Jenkins) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *JenkinsBackupAmazonS3) DeepCopyInto(out *JenkinsBackupAmazonS3) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsBackupAmazonS3. -func (in *JenkinsBackupAmazonS3) DeepCopy() *JenkinsBackupAmazonS3 { - if in == nil { - return nil - } - out := new(JenkinsBackupAmazonS3) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *JenkinsList) DeepCopyInto(out *JenkinsList) { *out = *in @@ -168,7 +152,6 @@ func (in *JenkinsMaster) DeepCopy() *JenkinsMaster { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) { *out = *in - out.BackupAmazonS3 = in.BackupAmazonS3 in.Master.DeepCopyInto(&out.Master) if in.SeedJobs != nil { in, out := &in.SeedJobs, &out.SeedJobs diff --git a/pkg/controller/jenkins/backup/aws/s3.go b/pkg/controller/jenkins/backup/aws/s3.go deleted file mode 100644 index c307ed8c..00000000 --- a/pkg/controller/jenkins/backup/aws/s3.go +++ /dev/null @@ -1,240 +0,0 @@ -package aws - -import ( - "context" - "fmt" - - "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins" - "github.com/jenkinsci/kubernetes-operator/pkg/log" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - k8s "sigs.k8s.io/controller-runtime/pkg/client" -) - -// AmazonS3Backup is a backup strategy where backup is stored in AWS S3 bucket -// credentials required to make calls to AWS API are provided by user in backup credentials Kubernetes secret -type AmazonS3Backup struct{} - -// GetRestoreJobXML returns Jenkins restore backup job config XML -func (b *AmazonS3Backup) GetRestoreJobXML(jenkins v1alpha1.Jenkins) (string, error) { - return ` - - - - false - - - - - - - false - - - false -`, nil -} - -// GetBackupJobXML returns Jenkins backup job config XML -func (b *AmazonS3Backup) GetBackupJobXML(jenkins v1alpha1.Jenkins) (string, error) { - return ` - - - - false - - - - - - - H/60 * * * * - - - - - - - false - - - false -`, nil -} - -// IsConfigurationValidForBasePhase validates if user provided valid configuration of backup for base phase -func (b *AmazonS3Backup) IsConfigurationValidForBasePhase(jenkins v1alpha1.Jenkins, logger logr.Logger) bool { - if len(jenkins.Spec.BackupAmazonS3.BucketName) == 0 { - logger.V(log.VWarn).Info("Bucket name not set in 'spec.backupAmazonS3.bucketName'") - return false - } - - if len(jenkins.Spec.BackupAmazonS3.BucketPath) == 0 { - logger.V(log.VWarn).Info("Bucket path not set in 'spec.backupAmazonS3.bucketPath'") - return false - } - - if len(jenkins.Spec.BackupAmazonS3.Region) == 0 { - logger.V(log.VWarn).Info("Region not set in 'spec.backupAmazonS3.region'") - return false - } - - return true -} - -// IsConfigurationValidForUserPhase validates if user provided valid configuration of backup for user phase -func (b *AmazonS3Backup) IsConfigurationValidForUserPhase(k8sClient k8s.Client, jenkins v1alpha1.Jenkins, logger logr.Logger) (bool, error) { - backupSecretName := resources.GetBackupCredentialsSecretName(&jenkins) - backupSecret := &corev1.Secret{} - err := k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: jenkins.Namespace, Name: backupSecretName}, backupSecret) - if err != nil { - return false, err - } - - if len(backupSecret.Data[constants.BackupAmazonS3SecretSecretKey]) == 0 { - logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' doesn't contains key: %s", backupSecretName, constants.BackupAmazonS3SecretSecretKey)) - return false, nil - } - - if len(backupSecret.Data[constants.BackupAmazonS3SecretAccessKey]) == 0 { - logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' doesn't contains key: %s", backupSecretName, constants.BackupAmazonS3SecretAccessKey)) - return false, nil - } - - return true, nil -} - -// GetRequiredPlugins returns all required Jenkins plugins by this backup strategy -func (b *AmazonS3Backup) GetRequiredPlugins() map[string][]plugins.Plugin { - return map[string][]plugins.Plugin{ - "aws-java-sdk:1.11.457": { - plugins.Must(plugins.New(plugins.ApacheComponentsClientPlugin)), - plugins.Must(plugins.New(plugins.Jackson2ADIPlugin)), - }, - } -} diff --git a/pkg/controller/jenkins/backup/aws/s3_test.go b/pkg/controller/jenkins/backup/aws/s3_test.go deleted file mode 100644 index c8443e31..00000000 --- a/pkg/controller/jenkins/backup/aws/s3_test.go +++ /dev/null @@ -1,165 +0,0 @@ -package aws - -import ( - "context" - "testing" - - "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" - - "github.com/stretchr/testify/assert" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" -) - -func TestAmazonS3Backup_IsConfigurationValidForBasePhase(t *testing.T) { - tests := []struct { - name string - jenkins v1alpha1.Jenkins - want bool - }{ - { - name: "happy", - jenkins: v1alpha1.Jenkins{ - Spec: v1alpha1.JenkinsSpec{ - BackupAmazonS3: v1alpha1.JenkinsBackupAmazonS3{ - BucketName: "some-value", - BucketPath: "some-value", - Region: "some-value", - }, - }, - }, - want: true, - }, - { - name: "fail, no bucket name", - jenkins: v1alpha1.Jenkins{ - Spec: v1alpha1.JenkinsSpec{ - BackupAmazonS3: v1alpha1.JenkinsBackupAmazonS3{ - BucketName: "", - BucketPath: "some-value", - Region: "some-value", - }, - }, - }, - want: false, - }, - { - name: "fail, no bucket path", - jenkins: v1alpha1.Jenkins{ - Spec: v1alpha1.JenkinsSpec{ - BackupAmazonS3: v1alpha1.JenkinsBackupAmazonS3{ - BucketName: "some-value", - BucketPath: "", - Region: "some-value", - }, - }, - }, - want: false, - }, - { - name: "fail, no region", - jenkins: v1alpha1.Jenkins{ - Spec: v1alpha1.JenkinsSpec{ - BackupAmazonS3: v1alpha1.JenkinsBackupAmazonS3{ - BucketName: "some-value", - BucketPath: "some-value", - Region: "", - }, - }, - }, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := &AmazonS3Backup{} - got := r.IsConfigurationValidForBasePhase(tt.jenkins, logf.ZapLogger(false)) - assert.Equal(t, tt.want, got) - }) - } -} - -func TestAmazonS3Backup_IsConfigurationValidForUserPhase(t *testing.T) { - tests := []struct { - name string - jenkins *v1alpha1.Jenkins - secret *corev1.Secret - want bool - wantErr bool - }{ - { - name: "happy", - jenkins: &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-cr-name"}, - }, - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-operator-backup-credentials-jenkins-cr-name"}, - Data: map[string][]byte{ - constants.BackupAmazonS3SecretSecretKey: []byte("some-value"), - constants.BackupAmazonS3SecretAccessKey: []byte("some-value"), - }, - }, - want: true, - wantErr: false, - }, - { - name: "fail, no secret", - jenkins: &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-cr-name"}, - }, - want: false, - wantErr: true, - }, - { - name: "fail, no secret key in secret", - jenkins: &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-cr-name"}, - }, - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-operator-backup-credentials-jenkins-cr-name"}, - Data: map[string][]byte{ - constants.BackupAmazonS3SecretSecretKey: []byte(""), - constants.BackupAmazonS3SecretAccessKey: []byte("some-value"), - }, - }, - want: false, - wantErr: false, - }, - { - name: "fail, no access key in secret", - jenkins: &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-cr-name"}, - }, - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-operator-backup-credentials-jenkins-cr-name"}, - Data: map[string][]byte{ - constants.BackupAmazonS3SecretSecretKey: []byte("some-value"), - constants.BackupAmazonS3SecretAccessKey: []byte(""), - }, - }, - want: false, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - k8sClient := fake.NewFakeClient() - logger := logf.ZapLogger(false) - b := &AmazonS3Backup{} - if tt.secret != nil { - e := k8sClient.Create(context.TODO(), tt.secret) - assert.NoError(t, e) - } - got, err := b.IsConfigurationValidForUserPhase(k8sClient, *tt.jenkins, logger) - if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/pkg/controller/jenkins/backup/backup.go b/pkg/controller/jenkins/backup/backup.go deleted file mode 100644 index 83a080e4..00000000 --- a/pkg/controller/jenkins/backup/backup.go +++ /dev/null @@ -1,157 +0,0 @@ -package backup - -import ( - "context" - "fmt" - "time" - - "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/backup/aws" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/backup/nobackup" - jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/client" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/jobs" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins" - - "github.com/go-logr/logr" - "github.com/pkg/errors" - k8s "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/reconcile" -) - -const ( - restoreJobName = constants.OperatorName + "-restore-backup" -) - -// Provider defines API of backup providers -type Provider interface { - GetRestoreJobXML(jenkins v1alpha1.Jenkins) (string, error) - GetBackupJobXML(jenkins v1alpha1.Jenkins) (string, error) - IsConfigurationValidForBasePhase(jenkins v1alpha1.Jenkins, logger logr.Logger) bool - IsConfigurationValidForUserPhase(k8sClient k8s.Client, jenkins v1alpha1.Jenkins, logger logr.Logger) (bool, error) - GetRequiredPlugins() map[string][]plugins.Plugin -} - -// Backup defines backup manager which is responsible of backup of jobs history -type Backup struct { - jenkins *v1alpha1.Jenkins - k8sClient k8s.Client - logger logr.Logger - jenkinsClient jenkinsclient.Jenkins -} - -// New returns instance of backup manager -func New(jenkins *v1alpha1.Jenkins, k8sClient k8s.Client, logger logr.Logger, jenkinsClient jenkinsclient.Jenkins) *Backup { - return &Backup{jenkins: jenkins, k8sClient: k8sClient, logger: logger, jenkinsClient: jenkinsClient} -} - -// EnsureRestoreJob creates and updates Jenkins job used to restore backup -func (b *Backup) EnsureRestoreJob() error { - if b.jenkins.Status.UserConfigurationCompletedTime == nil { - provider, err := GetBackupProvider(b.jenkins.Spec.Backup) - if err != nil { - return err - } - restoreJobXML, err := provider.GetRestoreJobXML(*b.jenkins) - if err != nil { - return err - } - _, created, err := b.jenkinsClient.CreateOrUpdateJob(restoreJobXML, restoreJobName) - if err != nil { - return err - } - if created { - b.logger.Info(fmt.Sprintf("'%s' job has been created", restoreJobName)) - } - - return nil - } - - return nil -} - -// RestoreBackup restores backup -func (b *Backup) RestoreBackup() (reconcile.Result, error) { - if !b.jenkins.Status.BackupRestored && b.jenkins.Status.UserConfigurationCompletedTime == nil { - jobsClient := jobs.New(b.jenkinsClient, b.k8sClient, b.logger) - - hash := "hash-restore" // it can be hardcoded because restore job can be run only once - done, err := jobsClient.EnsureBuildJob(restoreJobName, hash, map[string]string{}, b.jenkins, true) - if err != nil { - // build failed and can be recovered - retry build and requeue reconciliation loop with timeout - if err == jobs.ErrorBuildFailed { - return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 10}, nil - } - // build failed and cannot be recovered - if err == jobs.ErrorUnrecoverableBuildFailed { - b.logger.Info(fmt.Sprintf("Restore backup can not be performed. Please check backup configuration in CR and credentials in secret '%s'.", resources.GetBackupCredentialsSecretName(b.jenkins))) - b.logger.Info(fmt.Sprintf("You can also check '%s' job logs in Jenkins", constants.BackupJobName)) - return reconcile.Result{}, nil - } - // unexpected error - requeue reconciliation loop - return reconcile.Result{}, err - } - // build not finished yet - requeue reconciliation loop with timeout - if !done { - return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 10}, nil - } - - b.jenkins.Status.BackupRestored = true - err = b.k8sClient.Update(context.TODO(), b.jenkins) - return reconcile.Result{}, err - } - - return reconcile.Result{}, nil -} - -// EnsureBackupJob creates and updates Jenkins job used to backup -func (b *Backup) EnsureBackupJob() error { - provider, err := GetBackupProvider(b.jenkins.Spec.Backup) - if err != nil { - return err - } - backupJobXML, err := provider.GetBackupJobXML(*b.jenkins) - if err != nil { - return err - } - _, created, err := b.jenkinsClient.CreateOrUpdateJob(backupJobXML, constants.BackupJobName) - if err != nil { - return err - } - if created { - b.logger.Info(fmt.Sprintf("'%s' job has been created", constants.BackupJobName)) - } - - return nil -} - -// GetBackupProvider returns backup provider by type -func GetBackupProvider(backupType v1alpha1.JenkinsBackup) (Provider, error) { - switch backupType { - case v1alpha1.JenkinsBackupTypeNoBackup: - return &nobackup.NoBackup{}, nil - case v1alpha1.JenkinsBackupTypeAmazonS3: - return &aws.AmazonS3Backup{}, nil - default: - return nil, errors.Errorf("Invalid BackupManager type '%s'", backupType) - } -} - -// GetPluginsRequiredByAllBackupProviders returns plugins required by all backup providers -func GetPluginsRequiredByAllBackupProviders() map[string][]plugins.Plugin { - allPlugins := map[string][]plugins.Plugin{} - for _, provider := range getAllProviders() { - for key, value := range provider.GetRequiredPlugins() { - allPlugins[key] = value - } - } - - return allPlugins -} - -func getAllProviders() []Provider { - return []Provider{ - &nobackup.NoBackup{}, &aws.AmazonS3Backup{}, - } -} diff --git a/pkg/controller/jenkins/backup/nobackup/nobackup.go b/pkg/controller/jenkins/backup/nobackup/nobackup.go deleted file mode 100644 index 7885cdea..00000000 --- a/pkg/controller/jenkins/backup/nobackup/nobackup.go +++ /dev/null @@ -1,52 +0,0 @@ -package nobackup - -import ( - "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins" - - "github.com/go-logr/logr" - k8s "sigs.k8s.io/controller-runtime/pkg/client" -) - -// NoBackup is a backup strategy where there is no backup -type NoBackup struct{} - -var emptyJob = ` - - - - false - - - - false - - - false - -` - -// GetRestoreJobXML returns Jenkins restore backup job config XML -func (b *NoBackup) GetRestoreJobXML(jenkins v1alpha1.Jenkins) (string, error) { - return emptyJob, nil -} - -// GetBackupJobXML returns Jenkins backup job config XML -func (b *NoBackup) GetBackupJobXML(jenkins v1alpha1.Jenkins) (string, error) { - return emptyJob, nil -} - -// IsConfigurationValidForBasePhase validates if user provided valid configuration of backup for base phase -func (b *NoBackup) IsConfigurationValidForBasePhase(jenkins v1alpha1.Jenkins, logger logr.Logger) bool { - return true -} - -// IsConfigurationValidForUserPhase validates if user provided valid configuration of backup for user phase -func (b *NoBackup) IsConfigurationValidForUserPhase(k8sClient k8s.Client, jenkins v1alpha1.Jenkins, logger logr.Logger) (bool, error) { - return true, nil -} - -// GetRequiredPlugins returns all required Jenkins plugins by this backup strategy -func (b *NoBackup) GetRequiredPlugins() map[string][]plugins.Plugin { - return map[string][]plugins.Plugin{} -} diff --git a/pkg/controller/jenkins/configuration/base/reconcile.go b/pkg/controller/jenkins/configuration/base/reconcile.go index 9baff75b..0ecb2099 100644 --- a/pkg/controller/jenkins/configuration/base/reconcile.go +++ b/pkg/controller/jenkins/configuration/base/reconcile.go @@ -7,7 +7,6 @@ import ( "time" "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/backup" jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/client" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" @@ -62,16 +61,7 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenki return reconcile.Result{}, nil, err } - pluginsRequiredByAllBackupProviders := backup.GetPluginsRequiredByAllBackupProviders() - result, err := r.ensurePluginsRequiredByAllBackupProviders(pluginsRequiredByAllBackupProviders) - if err != nil { - return reconcile.Result{}, nil, err - } - if result.Requeue { - return result, nil, nil - } - - result, err = r.ensureJenkinsMasterPod(metaObject) + result, err := r.ensureJenkinsMasterPod(metaObject) if err != nil { return reconcile.Result{}, nil, err } @@ -95,7 +85,7 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenki } r.logger.V(log.VDebug).Info("Jenkins API client set") - ok, err := r.verifyPlugins(jenkinsClient, plugins.BasePluginsMap, pluginsRequiredByAllBackupProviders) + ok, err := r.verifyPlugins(jenkinsClient, plugins.BasePluginsMap) if err != nil { return reconcile.Result{}, nil, err } @@ -144,11 +134,6 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod } r.logger.V(log.VDebug).Info("Service is present") - if err := r.createBackupCredentialsSecret(metaObject); err != nil { - return err - } - r.logger.V(log.VDebug).Info("Backup credentials secret is present") - return nil } @@ -473,23 +458,6 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureBaseConfiguration(jenkinsClien return reconcile.Result{}, nil } -func (r *ReconcileJenkinsBaseConfiguration) createBackupCredentialsSecret(meta metav1.ObjectMeta) error { - currentSecret := &corev1.Secret{} - err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: resources.GetBackupCredentialsSecretName(r.jenkins), Namespace: r.jenkins.Namespace}, currentSecret) - if err != nil && errors.IsNotFound(err) { - return r.k8sClient.Create(context.TODO(), resources.NewBackupCredentialsSecret(r.jenkins)) - } else if err != nil { - return err - } - valid := r.verifyLabelsForWatchedResource(currentSecret) - if !valid { - currentSecret.ObjectMeta.Labels = resources.BuildLabelsForWatchedResources(r.jenkins) - return r.k8sClient.Update(context.TODO(), currentSecret) - } - - return nil -} - func (r *ReconcileJenkinsBaseConfiguration) verifyLabelsForWatchedResource(object metav1.Object) bool { requiredLabels := resources.BuildLabelsForWatchedResources(r.jenkins) for key, value := range requiredLabels { @@ -500,28 +468,3 @@ func (r *ReconcileJenkinsBaseConfiguration) verifyLabelsForWatchedResource(objec return true } - -func (r *ReconcileJenkinsBaseConfiguration) ensurePluginsRequiredByAllBackupProviders(requiredPlugins map[string][]plugins.Plugin) (reconcile.Result, error) { - copiedPlugins := map[string][]string{} - for key, value := range r.jenkins.Spec.Master.Plugins { - copiedPlugins[key] = value - } - for key, value := range requiredPlugins { - copiedPlugins[key] = func() []string { - var pluginsWithVersion []string - for _, plugin := range value { - pluginsWithVersion = append(pluginsWithVersion, plugin.String()) - } - return pluginsWithVersion - }() - } - - if !reflect.DeepEqual(r.jenkins.Spec.Master.Plugins, copiedPlugins) { - r.logger.Info("Adding plugins required by backup providers to '.spec.master.plugins'") - r.jenkins.Spec.Master.Plugins = copiedPlugins - err := r.k8sClient.Update(context.TODO(), r.jenkins) - return reconcile.Result{Requeue: true}, err - } - - return reconcile.Result{}, nil -} diff --git a/pkg/controller/jenkins/configuration/base/reconcile_test.go b/pkg/controller/jenkins/configuration/base/reconcile_test.go deleted file mode 100644 index f4744683..00000000 --- a/pkg/controller/jenkins/configuration/base/reconcile_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package base - -import ( - "context" - "testing" - - "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins" - - "github.com/stretchr/testify/assert" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" -) - -func TestReconcileJenkinsBaseConfiguration_ensurePluginsRequiredByAllBackupProviders(t *testing.T) { - tests := []struct { - name string - jenkins *v1alpha1.Jenkins - requiredPlugins map[string][]plugins.Plugin - want reconcile.Result - wantErr bool - }{ - { - name: "happy, no required plugins", - jenkins: &v1alpha1.Jenkins{ - Spec: v1alpha1.JenkinsSpec{ - Master: v1alpha1.JenkinsMaster{ - Plugins: map[string][]string{ - "first-plugin:0.0.1": {"second-plugin:0.0.1"}, - }, - }, - }, - }, - want: reconcile.Result{Requeue: false}, - wantErr: false, - }, - { - name: "happy, required plugins are set", - jenkins: &v1alpha1.Jenkins{ - Spec: v1alpha1.JenkinsSpec{ - Master: v1alpha1.JenkinsMaster{ - Plugins: map[string][]string{ - "first-plugin:0.0.1": {"second-plugin:0.0.1"}, - }, - }, - }, - }, - requiredPlugins: map[string][]plugins.Plugin{ - "first-plugin:0.0.1": {plugins.Must(plugins.New("second-plugin:0.0.1"))}, - }, - want: reconcile.Result{Requeue: false}, - wantErr: false, - }, - { - name: "happy, jenkins CR must be updated", - jenkins: &v1alpha1.Jenkins{ - Spec: v1alpha1.JenkinsSpec{ - Master: v1alpha1.JenkinsMaster{ - Plugins: map[string][]string{ - "first-plugin:0.0.1": {"second-plugin:0.0.1"}, - }, - }, - }, - }, - requiredPlugins: map[string][]plugins.Plugin{ - "first-plugin:0.0.1": {plugins.Must(plugins.New("second-plugin:0.0.1"))}, - "third-plugin:0.0.1": {}, - }, - want: reconcile.Result{Requeue: true}, - wantErr: false, - }, - { - name: "happy, jenkins CR must be updated", - jenkins: &v1alpha1.Jenkins{ - Spec: v1alpha1.JenkinsSpec{ - Master: v1alpha1.JenkinsMaster{ - Plugins: map[string][]string{ - "first-plugin:0.0.1": {"second-plugin:0.0.1"}, - }, - }, - }, - }, - requiredPlugins: map[string][]plugins.Plugin{ - "first-plugin:0.0.1": {plugins.Must(plugins.New("second-plugin:0.0.1"))}, - "third-plugin:0.0.1": {plugins.Must(plugins.New("fourth-plugin:0.0.1"))}, - }, - want: reconcile.Result{Requeue: true}, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := v1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme) - assert.NoError(t, err) - r := &ReconcileJenkinsBaseConfiguration{ - k8sClient: fake.NewFakeClient(), - scheme: nil, - logger: logf.ZapLogger(false), - jenkins: tt.jenkins, - local: false, - minikube: false, - } - err = r.k8sClient.Create(context.TODO(), tt.jenkins) - assert.NoError(t, err) - got, err := r.ensurePluginsRequiredByAllBackupProviders(tt.requiredPlugins) - if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/pkg/controller/jenkins/configuration/base/resources/backup_credentials_secret.go b/pkg/controller/jenkins/configuration/base/resources/backup_credentials_secret.go deleted file mode 100644 index f024222e..00000000 --- a/pkg/controller/jenkins/configuration/base/resources/backup_credentials_secret.go +++ /dev/null @@ -1,30 +0,0 @@ -package resources - -import ( - "fmt" - - "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// GetBackupCredentialsSecretName returns name of Kubernetes secret used to store backup credentials -func GetBackupCredentialsSecretName(jenkins *v1alpha1.Jenkins) string { - return fmt.Sprintf("%s-backup-credentials-%s", constants.OperatorName, jenkins.Name) -} - -// NewBackupCredentialsSecret builds the Kubernetes secret used to store backup credentials -func NewBackupCredentialsSecret(jenkins *v1alpha1.Jenkins) *corev1.Secret { - meta := metav1.ObjectMeta{ - Name: GetBackupCredentialsSecretName(jenkins), - Namespace: jenkins.ObjectMeta.Namespace, - Labels: BuildLabelsForWatchedResources(jenkins), - } - - return &corev1.Secret{ - TypeMeta: buildSecretTypeMeta(), - ObjectMeta: meta, - } -} diff --git a/pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go b/pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go index b02d5099..9e40defa 100644 --- a/pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go +++ b/pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go @@ -16,7 +16,7 @@ import jenkins.model.JenkinsLocationConfiguration import hudson.model.Node.Mode def jenkins = Jenkins.instance -//Number of jobs that run simultaneously on master, currently only backup and SeedJob. +//Number of jobs that run simultaneously on master, currently only SeedJob. jenkins.setNumExecutors(%d) //Jobs must specify that they want to run on master jenkins.setMode(Mode.EXCLUSIVE) diff --git a/pkg/controller/jenkins/configuration/base/resources/pod.go b/pkg/controller/jenkins/configuration/base/resources/pod.go index 37d968b9..f02913c5 100644 --- a/pkg/controller/jenkins/configuration/base/resources/pod.go +++ b/pkg/controller/jenkins/configuration/base/resources/pod.go @@ -16,7 +16,6 @@ const ( jenkinsScriptsVolumeName = "scripts" jenkinsScriptsVolumePath = "/var/jenkins/scripts" initScriptName = "init.sh" - backupScriptName = "backup.sh" jenkinsOperatorCredentialsVolumeName = "operator-credentials" jenkinsOperatorCredentialsVolumePath = "/var/jenkins/operator-credentials" @@ -34,11 +33,6 @@ const ( // this scripts are provided by user JenkinsUserConfigurationVolumePath = "/var/jenkins/user-configuration" - jenkinsBackupCredentialsVolumeName = "backup-credentials" - // JenkinsBackupCredentialsVolumePath is a path where are credentials used for backup/restore - // credentials are provided by user - JenkinsBackupCredentialsVolumePath = "/var/jenkins/backup-credentials" - httpPortName = "http" slavePortName = "slavelistener" // HTTPPortInt defines Jenkins master HTTP port @@ -84,16 +78,6 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins "bash", fmt.Sprintf("%s/%s", jenkinsScriptsVolumePath, initScriptName), }, - Lifecycle: &corev1.Lifecycle{ - PreStop: &corev1.Handler{ - Exec: &corev1.ExecAction{ - Command: []string{ - "bash", - fmt.Sprintf("%s/%s", jenkinsScriptsVolumePath, backupScriptName), - }, - }, - }, - }, LivenessProbe: &corev1.Probe{ Handler: corev1.Handler{ HTTPGet: &corev1.HTTPGetAction{ @@ -168,11 +152,6 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins MountPath: jenkinsOperatorCredentialsVolumePath, ReadOnly: true, }, - { - Name: jenkinsBackupCredentialsVolumeName, - MountPath: JenkinsBackupCredentialsVolumePath, - ReadOnly: true, - }, }, }, }, @@ -231,14 +210,6 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins }, }, }, - { - Name: jenkinsBackupCredentialsVolumeName, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: GetBackupCredentialsSecretName(jenkins), - }, - }, - }, }, }, } diff --git a/pkg/controller/jenkins/configuration/base/resources/scripts_configmap.go b/pkg/controller/jenkins/configuration/base/resources/scripts_configmap.go index 4f7a6ae7..f88ac74f 100644 --- a/pkg/controller/jenkins/configuration/base/resources/scripts_configmap.go +++ b/pkg/controller/jenkins/configuration/base/resources/scripts_configmap.go @@ -264,70 +264,6 @@ echo "Installing plugins - end" /sbin/tini -s -- /usr/local/bin/jenkins.sh `)) -const backupBashFmt = `#!/usr/bin/env bash - -# don't add set -e - -JENKINS_SERVER="http://%s:$(cat %s/%s)@localhost:%d" -JOB="%s" -JOB_QUERY=/job/${JOB} - -echo 'Starting the build' -curl -f -v -X POST "${JENKINS_SERVER}${JOB_QUERY}/build?delay=0sec" || exit -1 -sleep 3 # give some time for Jenkins to update builds numbers - -BUILD_STATUS_QUERY=/lastBuild/api/json - -CURRENT_BUILD_NUMBER_QUERY=/lastBuild/buildNumber -CURRENT_BUILD_JSON=$(curl -s -f "${JENKINS_SERVER}${JOB_QUERY}${CURRENT_BUILD_NUMBER_QUERY}") -LAST_STABLE_BUILD_NUMBER_QUERY=/lastStableBuild/buildNumber - -check_build() -{ - GOOD_BUILD="Last build successful. " - BAD_BUILD="Last build failed. " - JOB_STATUS_JSON=$(curl -s -f "${JENKINS_SERVER}${JOB_QUERY}${BUILD_STATUS_QUERY}") - RESULT=$(echo "${JOB_STATUS_JSON}" | sed -n 's/.*"result":\([\"A-Za-z]*\),.*/\1/p') - CURRENT_BUILD_NUMBER=${CURRENT_BUILD_JSON} - LAST_STABLE_BUILD_JSON=$(curl --silent "${JENKINS_SERVER}${JOB_QUERY}${LAST_STABLE_BUILD_NUMBER_QUERY}") - LAST_STABLE_BUILD_NUMBER=${LAST_STABLE_BUILD_JSON} - LAST_BUILD_STATUS=${GOOD_BUILD} - echo "${LAST_STABLE_BUILD_NUMBER}" | grep "is not available" > /dev/null - GREP_RETURN_CODE=$? - if [[ ${GREP_RETURN_CODE} -ne 0 ]] - then - if [[ $(expr ${CURRENT_BUILD_NUMBER} - 1) -gt ${LAST_STABLE_BUILD_NUMBER} ]] - then - LAST_BUILD_STATUS=${BAD_BUILD} - fi - fi - - if [[ "${RESULT}" = "null" ]] - then - echo "${LAST_BUILD_STATUS}Building ${JOB} ${CURRENT_BUILD_NUMBER}... last stable was ${LAST_STABLE_BUILD_NUMBER}" - elif [[ "${RESULT}" = "\"SUCCESS\"" ]] - then - echo "${LAST_BUILD_STATUS}${JOB} ${CURRENT_BUILD_NUMBER} completed successfully." - exit 0 - elif [[ "${RESULT}" = "\"FAILURE\"" ]] - then - LAST_BUILD_STATUS=${BAD_BUILD} - echo "${LAST_BUILD_STATUS}${JOB} ${CURRENT_BUILD_NUMBER} failed" - exit -1 - else - LAST_BUILD_STATUS=${BAD_BUILD} - echo "${LAST_BUILD_STATUS}${JOB} ${CURRENT_BUILD_NUMBER} status unknown - '${RESULT}'" - exit -1 - fi -} - -while [[ true ]] -do - check_build - sleep 1 -done -` - func buildConfigMapTypeMeta() metav1.TypeMeta { return metav1.TypeMeta{ Kind: "ConfigMap", @@ -377,8 +313,6 @@ func NewScriptsConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) (*co Data: map[string]string{ initScriptName: *initBashScript, installPluginsCommand: fmt.Sprintf(installPluginsBashFmt, jenkinsHomePath), - backupScriptName: fmt.Sprintf(backupBashFmt, - OperatorUserName, jenkinsOperatorCredentialsVolumePath, OperatorCredentialsSecretTokenKey, HTTPPortInt, constants.BackupJobName), }, }, nil } diff --git a/pkg/controller/jenkins/configuration/base/validate.go b/pkg/controller/jenkins/configuration/base/validate.go index 2840bbe7..d5f37766 100644 --- a/pkg/controller/jenkins/configuration/base/validate.go +++ b/pkg/controller/jenkins/configuration/base/validate.go @@ -1,20 +1,14 @@ package base import ( - "context" "fmt" "regexp" "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/backup" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/plugins" "github.com/jenkinsci/kubernetes-operator/pkg/log" docker "github.com/docker/distribution/reference" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" ) var ( @@ -38,20 +32,6 @@ func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *v1alpha1.Jenkins) return false, nil } - valid, err := r.verifyBackup() - if !valid || err != nil { - return valid, err - } - - backupProvider, err := backup.GetBackupProvider(r.jenkins.Spec.Backup) - if err != nil { - return false, err - } - - if !backupProvider.IsConfigurationValidForBasePhase(*r.jenkins, r.logger) { - return false, nil - } - return true, nil } @@ -84,39 +64,3 @@ func (r *ReconcileJenkinsBaseConfiguration) validatePlugins(pluginsWithVersions return valid } - -func (r *ReconcileJenkinsBaseConfiguration) verifyBackup() (bool, error) { - if r.jenkins.Spec.Backup == "" { - r.logger.V(log.VWarn).Info("Backup strategy not set in 'spec.backup'") - return false, nil - } - - valid := false - for _, backupType := range v1alpha1.AllowedJenkinsBackups { - if r.jenkins.Spec.Backup == backupType { - valid = true - } - } - - if !valid { - r.logger.V(log.VWarn).Info(fmt.Sprintf("Invalid backup strategy '%s'", r.jenkins.Spec.Backup)) - r.logger.V(log.VWarn).Info(fmt.Sprintf("Allowed backups '%+v'", v1alpha1.AllowedJenkinsBackups)) - return false, nil - } - - if r.jenkins.Spec.Backup == v1alpha1.JenkinsBackupTypeNoBackup { - return true, nil - } - - backupSecretName := resources.GetBackupCredentialsSecretName(r.jenkins) - backupSecret := &corev1.Secret{} - err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: r.jenkins.Namespace, Name: backupSecretName}, backupSecret) - if err != nil && errors.IsNotFound(err) { - r.logger.V(log.VWarn).Info(fmt.Sprintf("Please create secret '%s' in namespace '%s'", backupSecretName, r.jenkins.Namespace)) - return false, nil - } else if err != nil && !errors.IsNotFound(err) { - return false, err - } - - return true, nil -} diff --git a/pkg/controller/jenkins/configuration/base/validate_test.go b/pkg/controller/jenkins/configuration/base/validate_test.go index e5c837a2..a44bf5c7 100644 --- a/pkg/controller/jenkins/configuration/base/validate_test.go +++ b/pkg/controller/jenkins/configuration/base/validate_test.go @@ -1,16 +1,10 @@ package base import ( - "context" "fmt" "testing" - "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/stretchr/testify/assert" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client/fake" logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" ) @@ -62,87 +56,3 @@ func TestValidatePlugins(t *testing.T) { }) } } - -func TestReconcileJenkinsBaseConfiguration_verifyBackup(t *testing.T) { - tests := []struct { - name string - jenkins *v1alpha1.Jenkins - secret *corev1.Secret - want bool - wantErr bool - }{ - { - name: "happy, no backup", - jenkins: &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-cr-name"}, - Spec: v1alpha1.JenkinsSpec{ - Backup: v1alpha1.JenkinsBackupTypeNoBackup, - }, - }, - want: true, - wantErr: false, - }, - { - name: "happy", - jenkins: &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-cr-name"}, - Spec: v1alpha1.JenkinsSpec{ - Backup: v1alpha1.JenkinsBackupTypeAmazonS3, - }, - }, - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-operator-backup-credentials-jenkins-cr-name"}, - }, - want: true, - wantErr: false, - }, - { - name: "fail, no secret", - jenkins: &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-cr-name"}, - Spec: v1alpha1.JenkinsSpec{ - Backup: v1alpha1.JenkinsBackupTypeAmazonS3, - }, - }, - want: false, - wantErr: false, - }, - { - name: "fail, empty backup type", - jenkins: &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-cr-name"}, - Spec: v1alpha1.JenkinsSpec{ - Backup: "", - }, - }, - secret: &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{Namespace: "namespace-name", Name: "jenkins-operator-backup-credentials-jenkins-cr-name"}, - }, - want: false, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - r := &ReconcileJenkinsBaseConfiguration{ - k8sClient: fake.NewFakeClient(), - scheme: nil, - logger: logf.ZapLogger(false), - jenkins: tt.jenkins, - local: false, - minikube: false, - } - if tt.secret != nil { - e := r.k8sClient.Create(context.TODO(), tt.secret) - assert.NoError(t, e) - } - got, err := r.verifyBackup() - if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/pkg/controller/jenkins/configuration/user/reconcile.go b/pkg/controller/jenkins/configuration/user/reconcile.go index 07e7ee1b..e2fedc87 100644 --- a/pkg/controller/jenkins/configuration/user/reconcile.go +++ b/pkg/controller/jenkins/configuration/user/reconcile.go @@ -5,7 +5,6 @@ import ( "time" "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/backup" jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/client" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/user/seedjobs" @@ -41,21 +40,8 @@ func New(k8sClient k8s.Client, jenkinsClient jenkinsclient.Jenkins, logger logr. // Reconcile it's a main reconciliation loop for user supplied configuration func (r *ReconcileUserConfiguration) Reconcile() (reconcile.Result, error) { - backupManager := backup.New(r.jenkins, r.k8sClient, r.logger, r.jenkinsClient) - if err := backupManager.EnsureRestoreJob(); err != nil { - return reconcile.Result{}, err - } - - result, err := backupManager.RestoreBackup() - if err != nil { - return reconcile.Result{}, err - } - if result.Requeue { - return result, nil - } - // reconcile seed jobs - result, err = r.ensureSeedJobs() + result, err := r.ensureSeedJobs() if err != nil { return reconcile.Result{}, err } @@ -71,11 +57,6 @@ func (r *ReconcileUserConfiguration) Reconcile() (reconcile.Result, error) { return result, nil } - err = backupManager.EnsureBackupJob() - if err != nil { - return reconcile.Result{}, err - } - return reconcile.Result{}, nil } diff --git a/pkg/controller/jenkins/configuration/user/validate.go b/pkg/controller/jenkins/configuration/user/validate.go index c7ccda1e..cdabf729 100644 --- a/pkg/controller/jenkins/configuration/user/validate.go +++ b/pkg/controller/jenkins/configuration/user/validate.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/backup" "github.com/jenkinsci/kubernetes-operator/pkg/log" "k8s.io/api/core/v1" @@ -24,12 +23,7 @@ func (r *ReconcileUserConfiguration) Validate(jenkins *v1alpha1.Jenkins) (bool, return valid, err } - backupProvider, err := backup.GetBackupProvider(r.jenkins.Spec.Backup) - if err != nil { - return false, err - } - - return backupProvider.IsConfigurationValidForUserPhase(r.k8sClient, *r.jenkins, r.logger) + return true, nil } func (r *ReconcileUserConfiguration) validateSeedJobs(jenkins *v1alpha1.Jenkins) (bool, error) { diff --git a/pkg/controller/jenkins/constants/constants.go b/pkg/controller/jenkins/constants/constants.go index 3f6526ae..04a7e4eb 100644 --- a/pkg/controller/jenkins/constants/constants.go +++ b/pkg/controller/jenkins/constants/constants.go @@ -9,14 +9,6 @@ const ( SeedJobSuffix = "job-dsl-seed" // DefaultJenkinsMasterImage is the default Jenkins master docker image DefaultJenkinsMasterImage = "jenkins/jenkins:lts" - // BackupAmazonS3SecretAccessKey is the Amazon user access key used to Amazon S3 backup - BackupAmazonS3SecretAccessKey = "access-key" - // BackupAmazonS3SecretSecretKey is the Amazon user secret key used to Amazon S3 backup - BackupAmazonS3SecretSecretKey = "secret-key" - // BackupJobName is the Jenkins job name used to backup jobs history - BackupJobName = OperatorName + "-backup" // UserConfigurationJobName is the Jenkins job name used to configure Jenkins by groovy scripts provided by user UserConfigurationJobName = OperatorName + "-user-configuration" - // BackupLatestFileName is the latest backup file name - BackupLatestFileName = "build-history-latest.tar.gz" ) diff --git a/pkg/controller/jenkins/jenkins_controller.go b/pkg/controller/jenkins/jenkins_controller.go index 92434ffb..6d12d368 100644 --- a/pkg/controller/jenkins/jenkins_controller.go +++ b/pkg/controller/jenkins/jenkins_controller.go @@ -212,12 +212,6 @@ func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha1.Jenkins, logger logr.Lo changed = true jenkins.Spec.Master.Image = constants.DefaultJenkinsMasterImage } - if len(jenkins.Spec.Backup) == 0 { - logger.Info("Setting default backup strategy: " + v1alpha1.JenkinsBackupTypeNoBackup) - logger.V(log.VWarn).Info("Backup is disable !!! Please configure backup in '.spec.backup'") - changed = true - jenkins.Spec.Backup = v1alpha1.JenkinsBackupTypeNoBackup - } if len(jenkins.Spec.Master.Plugins) == 0 { logger.Info("Setting default base plugins") changed = true diff --git a/test/e2e/aws_s3_backup_test.go b/test/e2e/aws_s3_backup_test.go deleted file mode 100644 index b323cf79..00000000 --- a/test/e2e/aws_s3_backup_test.go +++ /dev/null @@ -1,157 +0,0 @@ -package e2e - -import ( - "context" - "encoding/json" - "fmt" - "io/ioutil" - "os" - "testing" - - "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" - "github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/bndr/gojenkins" - framework "github.com/operator-framework/operator-sdk/pkg/test" - assert "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type amazonS3BackupConfiguration struct { - BucketName string `json:"bucketName,omitempty"` - BucketPath string `json:"bucketPath,omitempty"` - Region string `json:"region,omitempty"` - AccessKey string `json:"accessKey,omitempty"` - SecretKey string `json:"secretKey,omitempty"` -} - -func TestAmazonS3Backup(t *testing.T) { - t.Parallel() - if amazonS3BackupConfigurationFile == nil || len(*amazonS3BackupConfigurationFile) == 0 { - t.Skipf("Skipping testing because flag '%s' is not set", amazonS3BackupConfigurationParameterName) - } - backupConfig := loadAmazonS3BackupConfig(t) - - s3Client := createS3Client(t, backupConfig) - deleteAllBackupsInS3(t, backupConfig, s3Client) - namespace, ctx := setupTest(t) - defer ctx.Cleanup() // Deletes test namespace - - jenkins := createJenkinsCRWithAmazonS3Backup(t, namespace, backupConfig) - waitForJenkinsBaseConfigurationToComplete(t, jenkins) - waitForJenkinsUserConfigurationToComplete(t, jenkins) - - restartJenkinsMasterPod(t, jenkins) - waitForRecreateJenkinsMasterPod(t, jenkins) - - waitForJenkinsBaseConfigurationToComplete(t, jenkins) - waitForJenkinsUserConfigurationToComplete(t, jenkins) - jenkinsClient := verifyJenkinsAPIConnection(t, jenkins) - verifyIfBackupAndRestoreWasSuccessfull(t, jenkinsClient, backupConfig, s3Client) -} - -func createS3Client(t *testing.T, backupConfig amazonS3BackupConfiguration) *s3.S3 { - sess, err := session.NewSession(&aws.Config{ - Region: aws.String(backupConfig.Region), - Credentials: credentials.NewStaticCredentials(backupConfig.AccessKey, backupConfig.SecretKey, ""), - }) - assert.NoError(t, err) - - return s3.New(sess) -} - -func deleteAllBackupsInS3(t *testing.T, backupConfig amazonS3BackupConfiguration, s3Client *s3.S3) { - input := &s3.DeleteObjectInput{ - Bucket: aws.String(backupConfig.BucketName), - Key: aws.String(backupConfig.BucketPath), - } - - _, err := s3Client.DeleteObject(input) - assert.NoError(t, err) -} - -func verifyIfBackupAndRestoreWasSuccessfull(t *testing.T, jenkinsClient *gojenkins.Jenkins, backupConfig amazonS3BackupConfiguration, s3Client *s3.S3) { - job, err := jenkinsClient.GetJob(constants.UserConfigurationJobName) - assert.NoError(t, err) - // jenkins runs twice(2) + 1 as next build number - assert.Equal(t, int64(3), job.Raw.NextBuildNumber) - - listObjects, err := s3Client.ListObjects(&s3.ListObjectsInput{ - Bucket: aws.String(backupConfig.BucketName), - Marker: aws.String(backupConfig.BucketPath), - }) - assert.NoError(t, err) - t.Logf("Backups in S3:%+v", listObjects.Contents) - assert.Equal(t, len(listObjects.Contents), 2) - latestBackupFound := false - for _, backup := range listObjects.Contents { - if *backup.Key == fmt.Sprintf("%s/%s", backupConfig.BucketPath, constants.BackupLatestFileName) { - latestBackupFound = true - } - } - assert.True(t, latestBackupFound) -} - -func createJenkinsCRWithAmazonS3Backup(t *testing.T, namespace string, backupConfig amazonS3BackupConfiguration) *v1alpha1.Jenkins { - jenkins := &v1alpha1.Jenkins{ - ObjectMeta: metav1.ObjectMeta{ - Name: "e2e", - Namespace: namespace, - }, - Spec: v1alpha1.JenkinsSpec{ - Backup: v1alpha1.JenkinsBackupTypeAmazonS3, - BackupAmazonS3: v1alpha1.JenkinsBackupAmazonS3{ - Region: backupConfig.Region, - BucketPath: backupConfig.BucketPath, - BucketName: backupConfig.BucketName, - }, - Master: v1alpha1.JenkinsMaster{ - Image: "jenkins/jenkins", - }, - }, - } - - t.Logf("Jenkins CR %+v", *jenkins) - err := framework.Global.Client.Create(context.TODO(), jenkins, nil) - assert.NoError(t, err) - - backupCredentialsSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: resources.GetBackupCredentialsSecretName(jenkins), - Namespace: namespace, - }, - Data: map[string][]byte{ - constants.BackupAmazonS3SecretAccessKey: []byte(backupConfig.AccessKey), - constants.BackupAmazonS3SecretSecretKey: []byte(backupConfig.SecretKey), - }, - } - err = framework.Global.Client.Create(context.TODO(), backupCredentialsSecret, nil) - assert.NoError(t, err) - - return jenkins -} - -func loadAmazonS3BackupConfig(t *testing.T) amazonS3BackupConfiguration { - jsonFile, err := os.Open(*amazonS3BackupConfigurationFile) - assert.NoError(t, err) - defer func() { _ = jsonFile.Close() }() - - byteValue, err := ioutil.ReadAll(jsonFile) - assert.NoError(t, err) - - var result amazonS3BackupConfiguration - err = json.Unmarshal([]byte(byteValue), &result) - assert.NoError(t, err) - assert.NotEmpty(t, result.AccessKey) - assert.NotEmpty(t, result.BucketName) - assert.NotEmpty(t, result.Region) - assert.NotEmpty(t, result.SecretKey) - result.BucketPath = t.Name() - return result -} diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index 084fa5c3..d3c89737 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -1,7 +1,6 @@ package e2e import ( - "flag" "testing" "github.com/jenkinsci/kubernetes-operator/pkg/apis" @@ -15,16 +14,10 @@ import ( ) const ( - jenkinsOperatorDeploymentName = constants.OperatorName - amazonS3BackupConfigurationParameterName = "s3BackupConfig" -) - -var ( - amazonS3BackupConfigurationFile *string + jenkinsOperatorDeploymentName = constants.OperatorName ) func TestMain(m *testing.M) { - amazonS3BackupConfigurationFile = flag.String(amazonS3BackupConfigurationParameterName, "", "path to AWS S3 backup config") f.MainEntry(m) }