kubernetes-operator/test/e2e/seedjobs_test.go

277 lines
9.3 KiB
Go

package e2e
import (
"context"
"fmt"
"text/template"
"time"
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/internal/render"
"github.com/jenkinsci/kubernetes-operator/internal/try"
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
"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"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type seedJobConfig struct {
v1alpha2.SeedJob
JobNames []string `json:"jobNames,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
PrivateKey string `json:"privateKey,omitempty"`
}
func createKubernetesCredentialsProviderSecret(namespace string, config seedJobConfig) {
if config.JenkinsCredentialType == v1alpha2.NoJenkinsCredentialCredentialType {
return
}
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: config.CredentialID,
Namespace: namespace,
Annotations: map[string]string{
"jenkins.io/credentials-description": "credentials from Kubernetes " + config.ID,
},
Labels: map[string]string{
seedjobs.JenkinsCredentialTypeLabelName: config.CredentialID,
},
},
StringData: map[string]string{
seedjobs.UsernameSecretKey: config.Username,
seedjobs.PasswordSecretKey: config.Password,
seedjobs.PrivateKeySecretKey: config.PrivateKey,
},
}
Expect(K8sClient.Create(context.TODO(), secret)).Should(Succeed())
}
func verifyJenkinsSeedJobs(jenkinsClient jenkinsclient.Jenkins, seedJobs []seedJobConfig) {
By("creating Jenkins jobs by seed jobs")
var err error
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'\n", seedJob.CredentialID, seedJob.ID))
}
verifySeedJobProperties(jenkinsClient, seedJob)
for _, requireJobName := range seedJob.JobNames {
err = try.Until(func() (end bool, err error) {
_, 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'\n", requireJobName, seedJob.ID))
}
}
}
func verifySeedJobProperties(jenkinsClient jenkinsclient.Jenkins, seedJob seedJobConfig) {
data := struct {
ID string
CredentialID string
Targets string
RepositoryBranch string
RepositoryURL string
GitHubPushTrigger bool
BuildPeriodically string
PollSCM string
IgnoreMissingFiles bool
AdditionalClasspath string
FailOnMissingPlugin bool
UnstableOnDeprecation bool
SeedJobSuffix string
AgentName string
}{
ID: seedJob.ID,
CredentialID: seedJob.CredentialID,
Targets: seedJob.Targets,
RepositoryBranch: seedJob.RepositoryBranch,
RepositoryURL: seedJob.RepositoryURL,
GitHubPushTrigger: seedJob.GitHubPushTrigger,
BuildPeriodically: seedJob.BuildPeriodically,
PollSCM: seedJob.PollSCM,
IgnoreMissingFiles: seedJob.IgnoreMissingFiles,
AdditionalClasspath: seedJob.AdditionalClasspath,
FailOnMissingPlugin: seedJob.FailOnMissingPlugin,
UnstableOnDeprecation: seedJob.UnstableOnDeprecation,
SeedJobSuffix: constants.SeedJobSuffix,
AgentName: seedjobs.AgentName,
}
groovyScript, err := render.Render(verifySeedJobPropertiesGroovyScriptTemplate, data)
Expect(err).NotTo(HaveOccurred(), groovyScript)
logs, err := jenkinsClient.ExecuteScript(groovyScript)
Expect(err).NotTo(HaveOccurred(), logs, groovyScript)
}
func verifyIfJenkinsCredentialExists(jenkinsClient jenkinsclient.Jenkins, credentialName string) error {
groovyScriptFmt := `import com.cloudbees.plugins.credentials.Credentials
Set<Credentials> allCredentials = new HashSet<Credentials>();
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.Credentials.class
);
allCredentials.addAll(creds)
Jenkins.instance.getAllItems(com.cloudbees.hudson.plugins.folder.Folder.class).each{ f ->
creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.Credentials.class, f)
allCredentials.addAll(creds)
}
def found = false
for (c in allCredentials) {
if("%s".equals(c.id)) found = true
}
if(!found) {
throw new Exception("Expected credential not found")
}`
groovyScript := fmt.Sprintf(groovyScriptFmt, credentialName)
_, err := jenkinsClient.ExecuteScript(groovyScript)
return err
}
var verifySeedJobPropertiesGroovyScriptTemplate = template.Must(template.New("test-e2e-verify-job-properties").Parse(`
import hudson.model.FreeStyleProject;
import hudson.plugins.git.GitSCM;
import hudson.plugins.git.BranchSpec;
import hudson.triggers.SCMTrigger;
import hudson.triggers.TimerTrigger;
import hudson.util.Secret;
import javaposse.jobdsl.plugin.*;
import jenkins.model.Jenkins;
import jenkins.model.JenkinsLocationConfiguration;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.domains.Domain;
import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
import jenkins.model.JenkinsLocationConfiguration;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition;
{{ if .GitHubPushTrigger }}
import com.cloudbees.jenkins.GitHubPushTrigger;
{{ end }}
import hudson.model.FreeStyleProject;
import hudson.model.labels.LabelAtom;
import hudson.plugins.git.BranchSpec;
import hudson.plugins.git.GitSCM;
import hudson.plugins.git.SubmoduleConfig;
import hudson.plugins.git.extensions.impl.CloneOption;
import javaposse.jobdsl.plugin.ExecuteDslScripts;
import javaposse.jobdsl.plugin.LookupStrategy;
import javaposse.jobdsl.plugin.RemovedJobAction;
import javaposse.jobdsl.plugin.RemovedViewAction;
import hudson.tasks.BuildStep;
Jenkins jenkins = Jenkins.instance
def jobDslSeedName = "{{ .ID }}-{{ .SeedJobSuffix }}"
def jobRef = jenkins.getItem(jobDslSeedName)
if (jobRef == null) {
throw new Exception("Job with given name not found")
}
if (!jobRef.getDisplayName().equals("Seed Job from {{ .ID }}")) {
throw new Exception("Display name is not equal")
}
if (jobRef.getScm() == null) {
throw new Exception("No SCM found")
}
if (jobRef.getScm().getBranches().find { val -> val.getName() == "{{ .RepositoryBranch }}" } == null) {
throw new Exception("Specified SCM branch not found")
}
if(jobRef.getScm().getRepositories().find { it.getURIs().find { uri -> uri.toString().equals("https://github.com/jenkinsci/kubernetes-operator.git") } } == null) {
throw new Exception("Specified SCM repositories are invalid")
}
{{ if .PollSCM }}
if (jobRef.getTriggers().find { key, val -> val.getClass().getSimpleName() == "SCMTrigger" && val.getSpec() == "{{ .PollSCM }}" } == null) {
throw new Exception("SCMTrigger not found but set")
}
{{ end }}
{{ if .GitHubPushTrigger }}
if (jobRef.getTriggers().find { key, val -> val.getClass().getSimpleName() == "GitHubPushTrigger" } == null) {
throw new Exception("GitHubPushTrigger not found but set")
}
{{ end }}
{{ if .BuildPeriodically }}
if (jobRef.getTriggers().find { key, val -> val.getClass().getSimpleName() == "TimerTrigger" && val.getSpec() == "{{ .BuildPeriodically }}" } == null) {
throw new Exception("BuildPeriodically not found but set")
}
{{ end }}
for (BuildStep step : jobRef.getBuildersList()) {
if (!step.getTargets().equals("{{ .Targets }}")) {
throw new Exception("Targets are not equals'")
}
if (!step.getAdditionalClasspath().equals(null)) {
throw new Exception("AdditionalClasspath is not equal")
}
if (!step.isFailOnMissingPlugin().equals({{ .FailOnMissingPlugin }})) {
throw new Exception("FailOnMissingPlugin is not equal")
}
if (!step.isUnstableOnDeprecation().equals({{ .UnstableOnDeprecation }})) {
throw new Exception("UnstableOnDeprecation is not equal")
}
if (!step.isIgnoreMissingFiles().equals({{ .IgnoreMissingFiles }})) {
throw new Exception("IgnoreMissingFiles is not equal")
}
}
`))
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())
}