277 lines
9.3 KiB
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())
|
|
}
|