Added TestPlugins, TestRestart and TestRestoreBackup (#504)

Co-authored-by: Tomasz Sęk
This commit is contained in:
SylwiaBrant 2021-02-05 13:17:06 +01:00 committed by GitHub
parent 294be87c64
commit 021ebb4745
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 485 additions and 238 deletions

View File

@ -211,14 +211,6 @@ func (r *JenkinsReconciler) reconcile(request reconcile.Request) (reconcile.Resu
return reconcile.Result{Requeue: true}, jenkins, nil
}
requeue, err = r.handleDeprecatedData(jenkins)
if err != nil {
return reconcile.Result{}, jenkins, err
}
if requeue {
return reconcile.Result{Requeue: true}, jenkins, nil
}
config := r.newJenkinsReconcilier(jenkins)
// Reconcile base configuration
baseConfiguration := base.New(config, r.JenkinsAPIConnectionSettings)
@ -367,7 +359,7 @@ func (r *JenkinsReconciler) setDefaults(jenkins *v1alpha2.Jenkins) (requeue bool
if jenkinsContainer.ReadinessProbe == nil {
logger.Info("Setting default Jenkins readinessProbe")
changed = true
jenkinsContainer.ReadinessProbe = resources.NewSimpleProbe(containerProbeURI, containerProbePortName, corev1.URISchemeHTTP, 30)
jenkinsContainer.ReadinessProbe = resources.NewProbe(containerProbeURI, containerProbePortName, corev1.URISchemeHTTP, 30, 1, 3)
}
if jenkinsContainer.LivenessProbe == nil {
logger.Info("Setting default Jenkins livenessProbe")
@ -493,7 +485,3 @@ func basePlugins() (result []v1alpha2.Plugin) {
}
return
}
func (r *JenkinsReconciler) handleDeprecatedData(_ *v1alpha2.Jenkins) (requeue bool, err error) {
return false, nil
}

View File

@ -5,7 +5,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
)
func NewSimpleProbe(uri string, port string, scheme corev1.URIScheme, initialDelaySeconds int32) *corev1.Probe {
func NewProbe(uri string, port string, scheme corev1.URIScheme, initialDelaySeconds, timeoutSeconds, failureThreshold int32) *corev1.Probe {
return &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
@ -15,14 +15,9 @@ func NewSimpleProbe(uri string, port string, scheme corev1.URIScheme, initialDel
},
},
InitialDelaySeconds: initialDelaySeconds,
TimeoutSeconds: timeoutSeconds,
FailureThreshold: failureThreshold,
SuccessThreshold: int32(1),
PeriodSeconds: int32(1),
}
}
func NewProbe(uri string, port string, scheme corev1.URIScheme, initialDelaySeconds, timeoutSeconds, failureThreshold int32) *corev1.Probe {
p := NewSimpleProbe(uri, port, scheme, initialDelaySeconds)
p.TimeoutSeconds = timeoutSeconds
p.FailureThreshold = failureThreshold
return p
}

View File

@ -23,49 +23,6 @@ import (
const e2e = "e2e"
// FIXME
/*func TestPlugins(t *testing.T) {
t.Parallel()
namespace, ctx := setupTest(t)
// Deletes test namespace
defer showLogsAndCleanup(t, ctx)
jobID := "k8s-e2e"
priorityClassName := ""
seedJobs := &[]v1alpha2.SeedJob{
{
ID: "jenkins-operator",
CredentialID: "jenkins-operator",
JenkinsCredentialType: v1alpha2.NoJenkinsCredentialCredentialType,
Targets: "cicd/jobs/k8s.jenkins",
Description: "Jenkins Operator repository",
RepositoryBranch: "master",
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
},
}
jenkins := createJenkinsCR(t, "k8s-e2e", namespace, seedJobs, v1alpha2.GroovyScripts{}, v1alpha2.ConfigurationAsCode{}, priorityClassName)
waitForJenkinsUserConfigurationToComplete(t, jenkins)
jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(t, jenkins, namespace)
defer cleanUpFunc()
waitForJob(t, jenkinsClient, jobID)
job, err := jenkinsClient.GetJob(jobID)
require.NoError(t, err, job)
i, err := job.InvokeSimple(map[string]string{})
require.NoError(t, err, i)
// FIXME: waitForJobToFinish use
time.Sleep(100 * time.Second) // wait for the build to complete
job, err = jenkinsClient.GetJob(jobID)
require.NoError(t, err, job)
build, err := job.GetLastBuild()
require.NoError(t, err)
assert.True(t, build.IsGood())
}*/
func createUserConfigurationSecret(namespace string, stringData map[string]string) {
By("creating user configuration secret")

View File

@ -139,3 +139,58 @@ var _ = Describe("Jenkins controller priority class", func() {
})
})
})
var _ = Describe("Jenkins controller plugins test", func() {
const (
jenkinsCRName = e2e
priorityClassName = ""
jobID = "k8s-e2e"
)
var (
namespace *corev1.Namespace
jenkins *v1alpha2.Jenkins
mySeedJob = seedJobConfig{
SeedJob: v1alpha2.SeedJob{
ID: "jenkins-operator",
CredentialID: "jenkins-operator",
JenkinsCredentialType: v1alpha2.NoJenkinsCredentialCredentialType,
Targets: "cicd/jobs/k8s.jenkins",
Description: "Jenkins Operator repository",
RepositoryBranch: "master",
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
},
}
groovyScripts = v1alpha2.GroovyScripts{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
},
}
casc = v1alpha2.ConfigurationAsCode{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
},
}
)
BeforeEach(func() {
namespace = createNamespace()
jenkins = createJenkinsCRSafe(jenkinsCRName, namespace.Name, &[]v1alpha2.SeedJob{mySeedJob.SeedJob}, groovyScripts, casc, priorityClassName)
})
AfterEach(func() {
destroyNamespace(namespace)
})
Context("when deploying CR with a SeedJob to cluster", func() {
It("runs kubernetes plugin job successfully", func() {
waitForJenkinsUserConfigurationToComplete(jenkins)
jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(jenkins, namespace.Name)
defer cleanUpFunc()
waitForJobCreation(jenkinsClient, jobID)
verifyJobCanBeRun(jenkinsClient, jobID)
verifyJobHasBeenRunCorrectly(jenkinsClient, jobID)
})
})
})

View File

@ -0,0 +1,108 @@
package e2e
import (
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
// +kubebuilder:scaffold:imports
)
var _ = Describe("Jenkins controller", func() {
const (
jenkinsCRName = e2e
priorityClassName = ""
)
var (
namespace *corev1.Namespace
jenkins *v1alpha2.Jenkins
groovyScripts = v1alpha2.GroovyScripts{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
},
}
casc = v1alpha2.ConfigurationAsCode{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
},
}
)
BeforeEach(func() {
namespace = createNamespace()
configureAuthorizationToUnSecure(namespace.Name, userConfigurationConfigMapName)
jenkins = createJenkinsCR(jenkinsCRName, namespace.Name, nil, groovyScripts, casc, priorityClassName)
})
AfterEach(func() {
destroyNamespace(namespace)
})
Context("when restarting Jenkins master pod", func() {
It("new Jenkins Master pod should be created", func() {
waitForJenkinsBaseConfigurationToComplete(jenkins)
restartJenkinsMasterPod(jenkins)
waitForRecreateJenkinsMasterPod(jenkins)
checkBaseConfigurationCompleteTimeIsNotSet(jenkins)
waitForJenkinsBaseConfigurationToComplete(jenkins)
})
})
})
var _ = Describe("Jenkins controller", func() {
const (
jenkinsCRName = e2e
priorityClassName = ""
)
var (
namespace *corev1.Namespace
jenkins *v1alpha2.Jenkins
groovyScripts = v1alpha2.GroovyScripts{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{
{
Name: userConfigurationConfigMapName,
},
},
},
}
casc = v1alpha2.ConfigurationAsCode{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
},
}
)
BeforeEach(func() {
namespace = createNamespace()
configureAuthorizationToUnSecure(namespace.Name, userConfigurationConfigMapName)
jenkins = createJenkinsCRSafeRestart(jenkinsCRName, namespace.Name, nil, groovyScripts, casc, priorityClassName)
})
AfterEach(func() {
destroyNamespace(namespace)
})
Context("when running Jenkins safe restart", func() {
It("authorization strategy is not overwritten", func() {
waitForJenkinsBaseConfigurationToComplete(jenkins)
waitForJenkinsUserConfigurationToComplete(jenkins)
jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(jenkins, namespace.Name)
defer cleanUpFunc()
checkIfAuthorizationStrategyUnsecuredIsSet(jenkinsClient)
err := jenkinsClient.SafeRestart()
Expect(err).NotTo(HaveOccurred())
waitForJenkinsSafeRestart(jenkinsClient)
checkIfAuthorizationStrategyUnsecuredIsSet(jenkinsClient)
})
})
})

View File

@ -0,0 +1,61 @@
package e2e
import (
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
. "github.com/onsi/ginkgo"
corev1 "k8s.io/api/core/v1"
// +kubebuilder:scaffold:imports
)
var _ = Describe("Jenkins controller backup and restore", func() {
const (
jenkinsCRName = e2e
jobID = "e2e-jenkins-operator"
)
var (
namespace *corev1.Namespace
jenkins *v1alpha2.Jenkins
)
BeforeEach(func() {
namespace = createNamespace()
createPVC(namespace.Name)
jenkins = createJenkinsWithBackupAndRestoreConfigured(jenkinsCRName, namespace.Name)
})
AfterEach(func() {
destroyNamespace(namespace)
})
Context("when deploying CR with backup enabled to cluster", func() {
It("performs backups before pod deletion and restores them even Jenkins status is restarted", func() {
waitForJenkinsUserConfigurationToComplete(jenkins)
jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(jenkins, namespace.Name)
defer cleanUpFunc()
waitForJobCreation(jenkinsClient, jobID)
verifyJobCanBeRun(jenkinsClient, jobID)
jenkins = getJenkins(jenkins.Namespace, jenkins.Name)
restartJenkinsMasterPod(jenkins)
waitForRecreateJenkinsMasterPod(jenkins)
waitForJenkinsUserConfigurationToComplete(jenkins)
jenkinsClient2, cleanUpFunc2 := verifyJenkinsAPIConnection(jenkins, namespace.Name)
defer cleanUpFunc2()
waitForJobCreation(jenkinsClient2, jobID)
verifyJobBuildsAfterRestoreBackup(jenkinsClient2, jobID)
resetJenkinsStatus(jenkins)
jenkins = getJenkins(jenkins.Namespace, jenkins.Name)
checkBaseConfigurationCompleteTimeIsNotSet(jenkins)
waitForJenkinsUserConfigurationToComplete(jenkins)
jenkinsClient3, cleanUpFunc3 := verifyJenkinsAPIConnection(jenkins, namespace.Name)
defer cleanUpFunc3()
waitForJobCreation(jenkinsClient3, jobID)
verifyJobBuildsAfterRestoreBackup(jenkinsClient3, jobID)
})
})
})

View File

@ -152,6 +152,112 @@ func createJenkinsCR(name, namespace string, seedJob *[]v1alpha2.SeedJob, groovy
return jenkins
}
func createJenkinsCRSafeRestart(name, namespace string, seedJob *[]v1alpha2.SeedJob, groovyScripts v1alpha2.GroovyScripts, casc v1alpha2.ConfigurationAsCode, priorityClassName string) *v1alpha2.Jenkins {
var seedJobs []v1alpha2.SeedJob
if seedJob != nil {
seedJobs = append(seedJobs, *seedJob...)
}
jenkins := &v1alpha2.Jenkins{
TypeMeta: v1alpha2.JenkinsTypeMeta(),
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: v1alpha2.JenkinsSpec{
GroovyScripts: groovyScripts,
ConfigurationAsCode: casc,
Master: v1alpha2.JenkinsMaster{
Annotations: map[string]string{"test": "label"},
Containers: []v1alpha2.Container{
{
Name: resources.JenkinsMasterContainerName,
Env: []corev1.EnvVar{
{
Name: "TEST_ENV",
Value: "test_env_value",
},
},
ReadinessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/login",
Port: intstr.FromString("http"),
Scheme: corev1.URISchemeHTTP,
},
},
InitialDelaySeconds: int32(80),
TimeoutSeconds: int32(4),
FailureThreshold: int32(10),
SuccessThreshold: int32(1),
PeriodSeconds: int32(1),
},
LivenessProbe: &corev1.Probe{
Handler: corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Path: "/login",
Port: intstr.FromString("http"),
Scheme: corev1.URISchemeHTTP,
},
},
InitialDelaySeconds: int32(100),
TimeoutSeconds: int32(5),
FailureThreshold: int32(12),
SuccessThreshold: int32(1),
PeriodSeconds: int32(5),
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "plugins-cache",
MountPath: "/usr/share/jenkins/ref/plugins",
},
},
},
{
Name: "envoyproxy",
Image: "envoyproxy/envoy-alpine:v1.14.1",
},
},
Plugins: []v1alpha2.Plugin{
{Name: "audit-trail", Version: "3.7"},
{Name: "simple-theme-plugin", Version: "0.6"},
{Name: "github", Version: "1.32.0"},
{Name: "devoptics", Version: "1.1905", DownloadURL: "https://jenkins-updates.cloudbees.com/download/plugins/devoptics/1.1905/devoptics.hpi"},
},
PriorityClassName: priorityClassName,
NodeSelector: map[string]string{"kubernetes.io/os": "linux"},
Volumes: []corev1.Volume{
{
Name: "plugins-cache",
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
},
},
SeedJobs: seedJobs,
Service: v1alpha2.Service{
Type: corev1.ServiceTypeNodePort,
Port: constants.DefaultHTTPPortInt32,
},
},
}
jenkins.Spec.Roles = []rbacv1.RoleRef{
{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: resources.GetResourceName(jenkins),
},
}
updateJenkinsCR(jenkins)
_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins CR %+v\n", *jenkins)
Expect(k8sClient.Create(context.TODO(), jenkins)).Should(Succeed())
return jenkins
}
func createJenkinsAPIClientFromServiceAccount(jenkins *v1alpha2.Jenkins, jenkinsAPIURL string) (jenkinsclient.Jenkins, error) {
podName := resources.GetJenkinsMasterPodName(jenkins)
@ -224,12 +330,18 @@ func verifyJenkinsAPIConnection(jenkins *v1alpha2.Jenkins, namespace string) (je
return jenkinsClient, cleanUpFunc
}
/*func restartJenkinsMasterPod(jenkins *v1alpha2.Jenkins) {
_, _ = fmt.Fprintf(GinkgoWriter, "Restarting Jenkins master pod")
func restartJenkinsMasterPod(jenkins *v1alpha2.Jenkins) {
_, _ = fmt.Fprintf(GinkgoWriter, "Restarting Jenkins master pod\n")
jenkinsPod := getJenkinsMasterPod(jenkins)
Expect(k8sClient.Delete(context.TODO(), jenkinsPod)).Should(Succeed())
_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins master pod has been restarted")
}*/
Eventually(func() (bool, error) {
jenkinsPod = getJenkinsMasterPod(jenkins)
return jenkinsPod.DeletionTimestamp != nil, nil
}, 30*retryInterval, retryInterval).Should(BeTrue())
_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins master pod has been restarted\n")
}
func getJenkinsService(jenkins *v1alpha2.Jenkins, serviceKind string) *corev1.Service {
service := &corev1.Service{}

View File

@ -1,70 +1,20 @@
package e2e
// TODO
/*
import (
"context"
"testing"
"time"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
framework "github.com/operator-framework/operator-sdk/pkg/test"
"github.com/stretchr/testify/require"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
func TestJenkinsMasterPodRestart(t *testing.T) {
t.Parallel()
namespace, ctx := setupTest(t)
defer showLogsAndCleanup(t, ctx)
jenkins := createJenkinsCR(t, "e2e", namespace, nil, v1alpha2.GroovyScripts{}, v1alpha2.ConfigurationAsCode{}, "")
waitForJenkinsBaseConfigurationToComplete(t, jenkins)
restartJenkinsMasterPod(t, jenkins)
waitForRecreateJenkinsMasterPod(t, jenkins)
checkBaseConfigurationCompleteTimeIsNotSet(t, jenkins)
waitForJenkinsBaseConfigurationToComplete(t, jenkins)
}
func TestSafeRestart(t *testing.T) {
if skipTestSafeRestart {
t.Skip()
}
t.Parallel()
namespace, ctx := setupTest(t)
// Deletes test namespace
defer ctx.Cleanup()
jenkinsCRName := "e2e"
configureAuthorizationToUnSecure(t, namespace, userConfigurationConfigMapName)
groovyScriptsConfig := v1alpha2.GroovyScripts{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{
{
Name: userConfigurationConfigMapName,
},
},
},
}
jenkins := createJenkinsCR(t, jenkinsCRName, namespace, nil, groovyScriptsConfig, v1alpha2.ConfigurationAsCode{}, "")
waitForJenkinsBaseConfigurationToComplete(t, jenkins)
waitForJenkinsUserConfigurationToComplete(t, jenkins)
jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(t, jenkins, namespace)
defer cleanUpFunc()
checkIfAuthorizationStrategyUnsecuredIsSet(t, jenkinsClient)
err := jenkinsClient.SafeRestart()
require.NoError(t, err)
waitForJenkinsSafeRestart(t, jenkinsClient)
checkIfAuthorizationStrategyUnsecuredIsSet(t, jenkinsClient)
}
func configureAuthorizationToUnSecure(t *testing.T, namespace, configMapName string) {
func configureAuthorizationToUnSecure(namespace, configMapName string) {
limitRange := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: configMapName,
@ -83,11 +33,12 @@ jenkins.save()
},
}
err := framework.Global.Client.Create(context.TODO(), limitRange, nil)
require.NoError(t, err)
Expect(k8sClient.Create(context.TODO(), limitRange)).Should(Succeed())
}
func checkIfAuthorizationStrategyUnsecuredIsSet(t *testing.T, jenkinsClient jenkinsclient.Jenkins) {
func checkIfAuthorizationStrategyUnsecuredIsSet(jenkinsClient jenkinsclient.Jenkins) {
By("checking if Authorization Strategy Unsecured is set")
logs, err := jenkinsClient.ExecuteScript(`
import hudson.security.*
@ -97,18 +48,18 @@ func checkIfAuthorizationStrategyUnsecuredIsSet(t *testing.T, jenkinsClient jenk
throw new Exception('AuthorizationStrategy.Unsecured is not set')
}
`)
require.NoError(t, err, logs)
Expect(err).NotTo(HaveOccurred(), logs)
}
func checkBaseConfigurationCompleteTimeIsNotSet(t *testing.T, jenkins *v1alpha2.Jenkins) {
jenkinsStatus := &v1alpha2.Jenkins{}
namespaceName := types.NamespacedName{Namespace: jenkins.Namespace, Name: jenkins.Name}
err := framework.Global.Client.Get(context.TODO(), namespaceName, jenkinsStatus)
if err != nil {
t.Fatal(err)
}
if jenkinsStatus.Status.BaseConfigurationCompletedTime != nil {
t.Fatalf("Status.BaseConfigurationCompletedTime is set after pod restart, status %+v", jenkinsStatus.Status)
}
func checkBaseConfigurationCompleteTimeIsNotSet(jenkins *v1alpha2.Jenkins) {
By("checking that Base Configuration's complete time is not set")
Eventually(func() (bool, error) {
actualJenkins := &v1alpha2.Jenkins{}
err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: jenkins.Name, Namespace: jenkins.Namespace}, actualJenkins)
if err != nil {
return false, err
}
return actualJenkins.Status.BaseConfigurationCompletedTime == nil, nil
}, time.Duration(110)*retryInterval, time.Second).Should(BeTrue())
}
*/

View File

@ -1,21 +1,17 @@
package e2e
// TODO
/*
import (
"context"
"testing"
"fmt"
"time"
"github.com/jenkinsci/kubernetes-operator/internal/try"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/client"
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
framework "github.com/operator-framework/operator-sdk/pkg/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -23,64 +19,33 @@ import (
const pvcName = "pvc-jenkins"
func TestBackupAndRestore(t *testing.T) {
t.Parallel()
namespace, ctx := setupTest(t)
func waitForJobCreation(jenkinsClient client.Jenkins, jobID string) {
By("waiting for Jenkins job creation")
defer showLogsAndCleanup(t, ctx)
jobID := "e2e-jenkins-operator"
createPVC(t, namespace)
jenkins := createJenkinsWithBackupAndRestoreConfigured(t, "e2e", namespace)
waitForJenkinsUserConfigurationToComplete(t, jenkins)
jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(t, jenkins, namespace)
defer cleanUpFunc()
waitForJob(t, jenkinsClient, jobID)
job, err := jenkinsClient.GetJob(jobID)
require.NoError(t, err, job)
i, err := job.InvokeSimple(map[string]string{})
require.NoError(t, err, i)
// FIXME: waitForJobToFinish use
time.Sleep(60 * time.Second) // wait for the build to complete
jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name)
lastDoneBackup := jenkins.Status.LastBackup
restartJenkinsMasterPod(t, jenkins)
waitForRecreateJenkinsMasterPod(t, jenkins)
waitForJenkinsUserConfigurationToComplete(t, jenkins)
jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name)
assert.Equal(t, lastDoneBackup, jenkins.Status.RestoredBackup)
jenkinsClient2, cleanUpFunc2 := verifyJenkinsAPIConnection(t, jenkins, namespace)
defer cleanUpFunc2()
waitForJob(t, jenkinsClient2, jobID)
verifyJobBuildsAfterRestoreBackup(t, jenkinsClient2, jobID)
jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name)
lastDoneBackup = jenkins.Status.LastBackup
resetJenkinsStatus(t, jenkins)
waitForJenkinsUserConfigurationToComplete(t, jenkins)
jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name)
assert.Equal(t, lastDoneBackup, jenkins.Status.RestoredBackup)
}
func waitForJob(t *testing.T, jenkinsClient client.Jenkins, jobID string) {
err := try.Until(func() (end bool, err error) {
var err error
Eventually(func() (bool, error) {
_, err = jenkinsClient.GetJob(jobID)
if err != nil {
return false, err
}
return err == nil, err
}, time.Second*2, time.Minute*3)
require.NoErrorf(t, err, "Jenkins job '%s' not created by seed job", jobID)
}, time.Minute*3, time.Second*2).Should(BeTrue())
Expect(err).NotTo(HaveOccurred())
}
func verifyJobBuildsAfterRestoreBackup(t *testing.T, jenkinsClient client.Jenkins, jobID string) {
func verifyJobBuildsAfterRestoreBackup(jenkinsClient client.Jenkins, jobID string) {
By("checking if job builds after restoring backup")
job, err := jenkinsClient.GetJob(jobID)
require.NoError(t, err)
Expect(err).NotTo(HaveOccurred())
build, err := job.GetLastBuild()
require.NoError(t, err)
assert.Equal(t, int64(1), build.GetBuildNumber())
Expect(err).NotTo(HaveOccurred())
Expect(build.GetBuildNumber()).To(Equal(int64(1)))
}
func createPVC(t *testing.T, namespace string) {
func createPVC(namespace string) {
pvc := &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: pvcName,
@ -96,11 +61,10 @@ func createPVC(t *testing.T, namespace string) {
},
}
err := framework.Global.Client.Create(context.TODO(), pvc, nil)
require.NoError(t, err)
Expect(k8sClient.Create(context.TODO(), pvc)).Should(Succeed())
}
func createJenkinsWithBackupAndRestoreConfigured(t *testing.T, name, namespace string) *v1alpha2.Jenkins {
func createJenkinsWithBackupAndRestoreConfigured(name, namespace string) *v1alpha2.Jenkins {
containerName := "backup"
jenkins := &v1alpha2.Jenkins{
TypeMeta: v1alpha2.JenkinsTypeMeta(),
@ -130,6 +94,16 @@ func createJenkinsWithBackupAndRestoreConfigured(t *testing.T, name, namespace s
},
},
},
GroovyScripts: v1alpha2.GroovyScripts{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
},
},
ConfigurationAsCode: v1alpha2.ConfigurationAsCode{
Customization: v1alpha2.Customization{
Configurations: []v1alpha2.ConfigMapRef{},
},
},
Master: v1alpha2.JenkinsMaster{
Containers: []v1alpha2.Container{
{
@ -201,19 +175,20 @@ func createJenkinsWithBackupAndRestoreConfigured(t *testing.T, name, namespace s
},
},
}
updateJenkinsCR(t, jenkins)
t.Logf("Jenkins CR %+v", *jenkins)
err := framework.Global.Client.Create(context.TODO(), jenkins, nil)
require.NoError(t, err)
updateJenkinsCR(jenkins)
_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins CR %+v\n", *jenkins)
Expect(k8sClient.Create(context.TODO(), jenkins)).Should(Succeed())
return jenkins
}
func resetJenkinsStatus(t *testing.T, jenkins *v1alpha2.Jenkins) {
jenkins = getJenkins(t, jenkins.Namespace, jenkins.Name)
func resetJenkinsStatus(jenkins *v1alpha2.Jenkins) {
By("resetting Jenkins status")
jenkins = getJenkins(jenkins.Namespace, jenkins.Name)
jenkins.Status = v1alpha2.JenkinsStatus{}
err := framework.Global.Client.Update(context.TODO(), jenkins)
require.NoError(t, err)
Expect(k8sClient.Status().Update(context.TODO(), jenkins)).Should(Succeed())
}
*/

View File

@ -13,6 +13,7 @@ import (
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/user/seedjobs"
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
"github.com/bndr/gojenkins"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
@ -27,12 +28,13 @@ type seedJobConfig struct {
PrivateKey string `json:"privateKey,omitempty"`
}
/*type seedJobsConfig struct {
/*
type seedJobsConfig struct {
SeedJobs []seedJobConfig `json:"seedJobs,omitempty"`
}*/
}
// FIXME
/*func TestSeedJobs(t *testing.T) {
func TestSeedJobs(t *testing.T) {
t.Parallel()
if seedJobConfigurationFile == nil || len(*seedJobConfigurationFile) == 0 {
t.Skipf("Skipping test because flag '%+v' is not set", seedJobConfigurationFile)
@ -63,22 +65,22 @@ type seedJobConfig struct {
verifyJenkinsSeedJobs(t, jenkinsClient, seedJobsConfig.SeedJobs)
}
func loadSeedJobsConfig(t *testing.T) seedJobsConfig {
func loadSeedJobsConfig() seedJobsConfig {
//seedJobConfigurationFile = flag.String(seedJobConfigurationParameterName, "", "path to seed job config")
jsonFile, err := os.Open(*seedJobConfigurationFile)
assert.NoError(t, err)
Expect(err).NotTo(HaveOccurred())
defer func() { _ = jsonFile.Close() }()
byteValue, err := ioutil.ReadAll(jsonFile)
assert.NoError(t, err)
Expect(err).NotTo(HaveOccurred())
var result seedJobsConfig
err = json.Unmarshal(byteValue, &result)
assert.NoError(t, err)
assert.NotEmpty(t, result.SeedJobs)
Expect(err).NotTo(HaveOccurred())
Expect(result.SeedJobs).NotTo(BeEmpty())
return result
}
*/
func createKubernetesCredentialsProviderSecret(namespace string, config seedJobConfig) {
if config.JenkinsCredentialType == v1alpha2.NoJenkinsCredentialCredentialType {
return
@ -112,7 +114,7 @@ func verifyJenkinsSeedJobs(jenkinsClient jenkinsclient.Jenkins, seedJobs []seedJ
for _, seedJob := range seedJobs {
if seedJob.JenkinsCredentialType == v1alpha2.BasicSSHCredentialType || seedJob.JenkinsCredentialType == v1alpha2.UsernamePasswordCredentialType {
err = verifyIfJenkinsCredentialExists(jenkinsClient, seedJob.CredentialID)
Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Jenkins credential '%s' not created for seed job ID '%s'", seedJob.CredentialID, seedJob.ID))
Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Jenkins credential '%s' not created for seed job ID '%s'\n", seedJob.CredentialID, seedJob.ID))
}
verifySeedJobProperties(jenkinsClient, seedJob)
@ -122,7 +124,7 @@ func verifyJenkinsSeedJobs(jenkinsClient jenkinsclient.Jenkins, seedJobs []seedJ
_, err = jenkinsClient.GetJob(requireJobName)
return err == nil, err
}, time.Second*2, time.Minute*2)
Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Jenkins job '%s' not created by seed job ID '%s'", requireJobName, seedJob.ID))
Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Jenkins job '%s' not created by seed job ID '%s'\n", requireJobName, seedJob.ID))
}
}
}
@ -292,3 +294,36 @@ for (BuildStep step : jobRef.getBuildersList()) {
}
}
`))
func verifyJobCanBeRun(jenkinsClient jenkinsclient.Jenkins, jobID string) {
By("retrieving created Jenkins job")
job, err := jenkinsClient.GetJob(jobID)
Expect(err).To(BeNil())
By("running Jenkins job")
_, err = job.InvokeSimple(map[string]string{})
Expect(err).To(BeNil())
// FIXME: waitForJobToFinish use
By("waiting for the job to finish")
time.Sleep(100 * time.Second) // wait for the build to complete
}
func verifyJobHasBeenRunCorrectly(jenkinsClient jenkinsclient.Jenkins, jobID string) {
By("retrieving finished job")
var (
err error
job *gojenkins.Job
build *gojenkins.Build
)
Eventually(func() (bool, error) {
job, err = jenkinsClient.GetJob(jobID)
Expect(err).To(BeNil())
build, err = job.GetLastBuild()
Expect(err).To(BeNil())
By("evaluating correctness of the outcome")
return build.IsGood(), err
}, time.Duration(110)*retryInterval, retryInterval).Should(BeTrue())
}

View File

@ -3,13 +3,20 @@ package e2e
import (
"context"
"fmt"
"net/http"
"time"
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var (
@ -36,26 +43,28 @@ func waitForJenkinsBaseConfigurationToComplete(jenkins *v1alpha2.Jenkins) {
Expect(k8sClient.Get(context.TODO(), namespacedName, jenkins)).Should(Succeed())
}
/*func waitForRecreateJenkinsMasterPod(t *testing.T, jenkins *v1alpha2.Jenkins) {
err := wait.Poll(retryInterval, 30*retryInterval, func() (bool, error) {
lo := metav1.ListOptions{
LabelSelector: labels.SelectorFromSet(resources.GetJenkinsMasterPodLabels(*jenkins)).String(),
func waitForRecreateJenkinsMasterPod(jenkins *v1alpha2.Jenkins) {
By("waiting for Jenkins Master Pod recreation")
Eventually(func() (bool, error) {
lo := &client.ListOptions{
LabelSelector: labels.SelectorFromSet(resources.GetJenkinsMasterPodLabels(*jenkins)),
Namespace: jenkins.Namespace,
}
podList, err := framework.Global.KubeClient.CoreV1().Pods(jenkins.ObjectMeta.Namespace).List(lo)
pods := &corev1.PodList{}
err := k8sClient.List(context.TODO(), pods, lo)
if err != nil {
return false, err
}
if len(podList.Items) != 1 {
if len(pods.Items) != 1 {
return false, nil
}
return podList.Items[0].DeletionTimestamp == nil, nil
})
if err != nil {
t.Fatal(err)
}
_, _ = fmt.Fprintf(GinkgoWriter,"Jenkins pod has been recreated")
}*/
return pods.Items[0].DeletionTimestamp == nil, nil
}, 30*retryInterval, retryInterval).Should(BeTrue())
_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins pod has been recreated\n")
}
func waitForJenkinsUserConfigurationToComplete(jenkins *v1alpha2.Jenkins) {
By("waiting for Jenkins user configuration phase to complete")
@ -66,22 +75,23 @@ func waitForJenkinsUserConfigurationToComplete(jenkins *v1alpha2.Jenkins) {
if err != nil {
return nil, err
}
return actualJenkins.Status.UserConfigurationCompletedTime, nil
}, time.Duration(110)*retryInterval, retryInterval).Should(Not(BeNil()))
_, _ = fmt.Fprintf(GinkgoWriter, "Jenkins instance is up and ready\n")
}
/*func waitForJenkinsSafeRestart(t *testing.T, jenkinsClient jenkinsclient.Jenkins) {
err := try.Until(func() (end bool, err error) {
func waitForJenkinsSafeRestart(jenkinsClient jenkinsclient.Jenkins) {
By("waiting for Jenkins safe restart")
Eventually(func() (bool, error) {
status, err := jenkinsClient.Poll()
_, _ = fmt.Fprintf(GinkgoWriter, "Safe restart status: %+v, err: %s\n", status, err)
if err != nil {
return false, err
}
if status != http.StatusOK {
return false, errors.Wrap(err, "couldn't poll data from Jenkins API")
return false, err
}
return true, nil
}, time.Second, time.Second*70)
require.NoError(t, err)
}*/
}, time.Second*200, time.Second*5).Should(BeTrue())
}