295 lines
9.9 KiB
Go
295 lines
9.9 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/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"`
|
|
}
|
|
|
|
/*type seedJobsConfig struct {
|
|
SeedJobs []seedJobConfig `json:"seedJobs,omitempty"`
|
|
}*/
|
|
|
|
// FIXME
|
|
/*func TestSeedJobs(t *testing.T) {
|
|
t.Parallel()
|
|
if seedJobConfigurationFile == nil || len(*seedJobConfigurationFile) == 0 {
|
|
t.Skipf("Skipping test because flag '%+v' is not set", seedJobConfigurationFile)
|
|
}
|
|
seedJobsConfig := loadSeedJobsConfig(t)
|
|
namespace, ctx := setupTest(t)
|
|
|
|
defer showLogsAndCleanup(t, ctx)
|
|
|
|
jenkinsCRName := "e2e"
|
|
var seedJobs []v1alpha2.SeedJob
|
|
|
|
// base
|
|
for _, seedJobConfig := range seedJobsConfig.SeedJobs {
|
|
createKubernetesCredentialsProviderSecret(t, namespace, seedJobConfig)
|
|
seedJobs = append(seedJobs, seedJobConfig.SeedJob)
|
|
}
|
|
jenkins := createJenkinsCR(t, jenkinsCRName, namespace, &seedJobs, v1alpha2.GroovyScripts{}, v1alpha2.ConfigurationAsCode{}, "")
|
|
waitForJenkinsBaseConfigurationToComplete(t, jenkins)
|
|
|
|
verifyJenkinsMasterPodAttributes(t, jenkins)
|
|
jenkinsClient, cleanUpFunc := verifyJenkinsAPIConnection(t, jenkins, namespace)
|
|
defer cleanUpFunc()
|
|
verifyPlugins(t, jenkinsClient, jenkins)
|
|
|
|
// user
|
|
waitForJenkinsUserConfigurationToComplete(t, jenkins)
|
|
verifyJenkinsSeedJobs(t, jenkinsClient, seedJobsConfig.SeedJobs)
|
|
}
|
|
|
|
func loadSeedJobsConfig(t *testing.T) seedJobsConfig {
|
|
jsonFile, err := os.Open(*seedJobConfigurationFile)
|
|
assert.NoError(t, err)
|
|
defer func() { _ = jsonFile.Close() }()
|
|
|
|
byteValue, err := ioutil.ReadAll(jsonFile)
|
|
assert.NoError(t, err)
|
|
|
|
var result seedJobsConfig
|
|
err = json.Unmarshal(byteValue, &result)
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, result.SeedJobs)
|
|
return result
|
|
}
|
|
*/
|
|
|
|
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'", 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'", 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")
|
|
}
|
|
}
|
|
`))
|