mirror of
https://github.com/jenkinsci/kubernetes-operator.git
synced 2026-10-04 23:21:11 +02:00
#14 Add username/password authentication for seed jobs
This commit is contained in:
@@ -253,9 +253,8 @@ func (r *ReconcileJenkinsBaseConfiguration) createUserConfigurationConfigMap(met
|
||||
} else if err != nil {
|
||||
return stackerr.WithStack(err)
|
||||
}
|
||||
valid := r.verifyLabelsForWatchedResource(currentConfigMap)
|
||||
if !valid {
|
||||
currentConfigMap.ObjectMeta.Labels = resources.BuildLabelsForWatchedResources(r.jenkins)
|
||||
if !resources.VerifyIfLabelsAreSet(currentConfigMap, resources.BuildLabelsForWatchedResources(*r.jenkins)) {
|
||||
currentConfigMap.ObjectMeta.Labels = resources.BuildLabelsForWatchedResources(*r.jenkins)
|
||||
return stackerr.WithStack(r.k8sClient.Update(context.TODO(), currentConfigMap))
|
||||
}
|
||||
|
||||
@@ -270,9 +269,8 @@ func (r *ReconcileJenkinsBaseConfiguration) createUserConfigurationSecret(meta m
|
||||
} else if err != nil {
|
||||
return stackerr.WithStack(err)
|
||||
}
|
||||
valid := r.verifyLabelsForWatchedResource(currentSecret)
|
||||
if !valid {
|
||||
currentSecret.ObjectMeta.Labels = resources.BuildLabelsForWatchedResources(r.jenkins)
|
||||
if !resources.VerifyIfLabelsAreSet(currentSecret, resources.BuildLabelsForWatchedResources(*r.jenkins)) {
|
||||
currentSecret.ObjectMeta.Labels = resources.BuildLabelsForWatchedResources(*r.jenkins)
|
||||
return stackerr.WithStack(r.k8sClient.Update(context.TODO(), currentSecret))
|
||||
}
|
||||
|
||||
@@ -547,14 +545,3 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureBaseConfiguration(jenkinsClien
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) verifyLabelsForWatchedResource(object metav1.Object) bool {
|
||||
requiredLabels := resources.BuildLabelsForWatchedResources(r.jenkins)
|
||||
for key, value := range requiredLabels {
|
||||
if object.GetLabels()[key] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
+12
-1
@@ -155,6 +155,16 @@ if (jenkins.getView(jenkinsViewName) == null) {
|
||||
jenkins.save()
|
||||
`
|
||||
|
||||
const disableJobDSLScriptApproval = `
|
||||
import jenkins.model.Jenkins
|
||||
import javaposse.jobdsl.plugin.GlobalJobDslSecurityConfiguration
|
||||
import jenkins.model.GlobalConfiguration
|
||||
|
||||
// disable Job DSL script approval
|
||||
GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration.class).useScriptSecurity=false
|
||||
GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration.class).save()
|
||||
`
|
||||
|
||||
// GetBaseConfigurationConfigMapName returns name of Kubernetes config map used to base configuration
|
||||
func GetBaseConfigurationConfigMapName(jenkins *v1alpha1.Jenkins) string {
|
||||
return fmt.Sprintf("%s-base-configuration-%s", constants.OperatorName, jenkins.ObjectMeta.Name)
|
||||
@@ -178,7 +188,8 @@ func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha1.Jen
|
||||
fmt.Sprintf("http://%s.%s:%d", GetJenkinsHTTPServiceName(jenkins), jenkins.ObjectMeta.Namespace, jenkins.Spec.Service.Port),
|
||||
fmt.Sprintf("%s.%s:%d", GetJenkinsSlavesServiceName(jenkins), jenkins.ObjectMeta.Namespace, jenkins.Spec.SlaveService.Port),
|
||||
),
|
||||
"7-configure-views.groovy": configureViews,
|
||||
"7-configure-views.groovy": configureViews,
|
||||
"8-disable-job-dsl-script-approval.groovy": disableJobDSLScriptApproval,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func BuildResourceLabels(jenkins *v1alpha1.Jenkins) map[string]string {
|
||||
// BuildLabelsForWatchedResources returns labels for Kubernetes resources which operator want to watch
|
||||
// resources with that labels should not be deleted after Jenkins CR deletion, to prevent this situation don't set
|
||||
// any owner
|
||||
func BuildLabelsForWatchedResources(jenkins *v1alpha1.Jenkins) map[string]string {
|
||||
func BuildLabelsForWatchedResources(jenkins v1alpha1.Jenkins) map[string]string {
|
||||
return map[string]string{
|
||||
constants.LabelAppKey: constants.LabelAppValue,
|
||||
constants.LabelJenkinsCRKey: jenkins.Name,
|
||||
@@ -41,3 +41,14 @@ func BuildLabelsForWatchedResources(jenkins *v1alpha1.Jenkins) map[string]string
|
||||
func GetResourceName(jenkins *v1alpha1.Jenkins) string {
|
||||
return fmt.Sprintf("%s-%s", constants.LabelAppValue, jenkins.ObjectMeta.Name)
|
||||
}
|
||||
|
||||
// VerifyIfLabelsAreSet check is selected labels are set for specific resource
|
||||
func VerifyIfLabelsAreSet(object metav1.Object, requiredLabels map[string]string) bool {
|
||||
for key, value := range requiredLabels {
|
||||
if object.GetLabels()[key] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func NewUserConfigurationConfigMap(jenkins *v1alpha1.Jenkins) *corev1.ConfigMap
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: GetUserConfigurationConfigMapNameFromJenkins(jenkins),
|
||||
Namespace: jenkins.ObjectMeta.Namespace,
|
||||
Labels: BuildLabelsForWatchedResources(jenkins),
|
||||
Labels: BuildLabelsForWatchedResources(*jenkins),
|
||||
},
|
||||
Data: map[string]string{
|
||||
"1-configure-theme.groovy": configureTheme,
|
||||
|
||||
@@ -27,7 +27,7 @@ func NewUserConfigurationSecret(jenkins *v1alpha1.Jenkins) *corev1.Secret {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: GetUserConfigurationSecretNameFromJenkins(jenkins),
|
||||
Namespace: jenkins.ObjectMeta.Namespace,
|
||||
Labels: BuildLabelsForWatchedResources(jenkins),
|
||||
Labels: BuildLabelsForWatchedResources(*jenkins),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@ import (
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
||||
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/log"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"k8s.io/api/core/v1"
|
||||
stackerr "github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
k8s "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
@@ -22,12 +24,23 @@ const (
|
||||
// ConfigureSeedJobsName this is the fixed seed job name
|
||||
ConfigureSeedJobsName = constants.OperatorName + "-configure-seed-job"
|
||||
|
||||
deployKeyIDParameterName = "DEPLOY_KEY_ID"
|
||||
privateKeyParameterName = "PRIVATE_KEY"
|
||||
idParameterName = "ID"
|
||||
credentialIDParameterName = "CREDENTIAL_ID"
|
||||
repositoryURLParameterName = "REPOSITORY_URL"
|
||||
repositoryBranchParameterName = "REPOSITORY_BRANCH"
|
||||
targetsParameterName = "TARGETS"
|
||||
displayNameParameterName = "SEED_JOB_DISPLAY_NAME"
|
||||
|
||||
// UsernameSecretKey is username data key in Kubernetes secret used to create Jenkins username/password credential
|
||||
UsernameSecretKey = "username"
|
||||
// PasswordSecretKey is password data key in Kubernetes secret used to create Jenkins username/password credential
|
||||
PasswordSecretKey = "password"
|
||||
// PrivateKeySecretKey is private key data key in Kubernetes secret used to create Jenkins SSH credential
|
||||
PrivateKeySecretKey = "privateKey"
|
||||
|
||||
// JenkinsCredentialTypeLabelName is label for kubernetes-credentials-provider-plugin which determine Jenkins
|
||||
// credential type
|
||||
JenkinsCredentialTypeLabelName = "jenkins.io/credentials-type"
|
||||
)
|
||||
|
||||
// SeedJobs defines API for configuring and ensuring Jenkins Seed Jobs and Deploy Keys
|
||||
@@ -48,11 +61,15 @@ func New(jenkinsClient jenkinsclient.Jenkins, k8sClient k8s.Client, logger logr.
|
||||
|
||||
// EnsureSeedJobs configures seed job and runs it for every entry from Jenkins.Spec.SeedJobs
|
||||
func (s *SeedJobs) EnsureSeedJobs(jenkins *v1alpha1.Jenkins) (done bool, err error) {
|
||||
err = s.createJob()
|
||||
if err != nil {
|
||||
if err = s.createJob(); err != nil {
|
||||
s.logger.V(log.VWarn).Info("Couldn't create jenkins seed job")
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err = s.ensureLabelsForSecrets(*jenkins); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
done, err = s.buildJobs(jenkins)
|
||||
if err != nil {
|
||||
s.logger.V(log.VWarn).Info("Couldn't build jenkins seed job")
|
||||
@@ -73,18 +90,46 @@ func (s *SeedJobs) createJob() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureLabelsForSecrets adds labels to Kubernetes secrets where are Jenkins credentials used for seed jobs,
|
||||
// thanks to them kubernetes-credentials-provider-plugin will create Jenkins credentials in Jenkins and
|
||||
// Operator will able to watch any changes made to them
|
||||
func (s *SeedJobs) ensureLabelsForSecrets(jenkins v1alpha1.Jenkins) error {
|
||||
for _, seedJob := range jenkins.Spec.SeedJobs {
|
||||
if seedJob.JenkinsCredentialType == v1alpha1.BasicSSHCredentialType || seedJob.JenkinsCredentialType == v1alpha1.UsernamePasswordCredentialType {
|
||||
requiredLabels := resources.BuildLabelsForWatchedResources(jenkins)
|
||||
requiredLabels[JenkinsCredentialTypeLabelName] = string(seedJob.JenkinsCredentialType)
|
||||
|
||||
secret := &corev1.Secret{}
|
||||
namespaceName := types.NamespacedName{Namespace: jenkins.ObjectMeta.Namespace, Name: seedJob.CredentialID}
|
||||
err := s.k8sClient.Get(context.TODO(), namespaceName, secret)
|
||||
if err != nil {
|
||||
return stackerr.WithStack(err)
|
||||
}
|
||||
|
||||
if !resources.VerifyIfLabelsAreSet(secret, requiredLabels) {
|
||||
secret.ObjectMeta.Labels = requiredLabels
|
||||
err = stackerr.WithStack(s.k8sClient.Update(context.TODO(), secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildJobs is responsible for running jenkins builds which configures jenkins seed jobs and deploy keys
|
||||
func (s *SeedJobs) buildJobs(jenkins *v1alpha1.Jenkins) (done bool, err error) {
|
||||
allDone := true
|
||||
seedJobs := jenkins.Spec.SeedJobs
|
||||
for _, seedJob := range seedJobs {
|
||||
privateKey, err := s.privateKeyFromSecret(jenkins.Namespace, seedJob)
|
||||
for _, seedJob := range jenkins.Spec.SeedJobs {
|
||||
credentialValue, err := s.credentialValue(jenkins.Namespace, seedJob)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
parameters := map[string]string{
|
||||
deployKeyIDParameterName: seedJob.ID,
|
||||
privateKeyParameterName: privateKey,
|
||||
idParameterName: seedJob.ID,
|
||||
credentialIDParameterName: seedJob.CredentialID,
|
||||
repositoryURLParameterName: seedJob.RepositoryURL,
|
||||
repositoryBranchParameterName: seedJob.RepositoryBranch,
|
||||
targetsParameterName: seedJob.Targets,
|
||||
@@ -92,8 +137,9 @@ func (s *SeedJobs) buildJobs(jenkins *v1alpha1.Jenkins) (done bool, err error) {
|
||||
}
|
||||
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(parameters[deployKeyIDParameterName]))
|
||||
hash.Write([]byte(parameters[privateKeyParameterName]))
|
||||
hash.Write([]byte(parameters[idParameterName]))
|
||||
hash.Write([]byte(parameters[credentialIDParameterName]))
|
||||
hash.Write([]byte(credentialValue))
|
||||
hash.Write([]byte(parameters[repositoryURLParameterName]))
|
||||
hash.Write([]byte(parameters[repositoryBranchParameterName]))
|
||||
hash.Write([]byte(parameters[targetsParameterName]))
|
||||
@@ -112,21 +158,23 @@ func (s *SeedJobs) buildJobs(jenkins *v1alpha1.Jenkins) (done bool, err error) {
|
||||
return allDone, nil
|
||||
}
|
||||
|
||||
// privateKeyFromSecret it's utility function which extracts deploy key from the kubernetes secret
|
||||
func (s *SeedJobs) privateKeyFromSecret(namespace string, seedJob v1alpha1.SeedJob) (string, error) {
|
||||
if seedJob.PrivateKey.SecretKeyRef != nil {
|
||||
deployKeySecret := &v1.Secret{}
|
||||
namespaceName := types.NamespacedName{Namespace: namespace, Name: seedJob.PrivateKey.SecretKeyRef.Name}
|
||||
err := s.k8sClient.Get(context.TODO(), namespaceName, deployKeySecret)
|
||||
func (s *SeedJobs) credentialValue(namespace string, seedJob v1alpha1.SeedJob) (string, error) {
|
||||
if seedJob.JenkinsCredentialType == v1alpha1.BasicSSHCredentialType || seedJob.JenkinsCredentialType == v1alpha1.UsernamePasswordCredentialType {
|
||||
secret := &corev1.Secret{}
|
||||
namespaceName := types.NamespacedName{Namespace: namespace, Name: seedJob.CredentialID}
|
||||
err := s.k8sClient.Get(context.TODO(), namespaceName, secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(deployKeySecret.Data[seedJob.PrivateKey.SecretKeyRef.Key]), nil
|
||||
|
||||
if seedJob.JenkinsCredentialType == v1alpha1.BasicSSHCredentialType {
|
||||
return string(secret.Data[PrivateKeySecretKey]), nil
|
||||
}
|
||||
return string(secret.Data[UsernameSecretKey]) + string(secret.Data[PasswordSecretKey]), nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// FIXME(antoniaklja) use mask-password plugin for params.PRIVATE_KEY
|
||||
// seedJobConfigXML this is the XML representation of seed job
|
||||
var seedJobConfigXML = `
|
||||
<flow-definition plugin="workflow-job@2.30">
|
||||
@@ -137,15 +185,16 @@ var seedJobConfigXML = `
|
||||
<hudson.model.ParametersDefinitionProperty>
|
||||
<parameterDefinitions>
|
||||
<hudson.model.StringParameterDefinition>
|
||||
<name>` + deployKeyIDParameterName + `</name>
|
||||
<name>` + idParameterName + `</name>
|
||||
<description></description>
|
||||
<defaultValue></defaultValue>
|
||||
<trim>false</trim>
|
||||
</hudson.model.StringParameterDefinition>
|
||||
<hudson.model.StringParameterDefinition>
|
||||
<name>` + privateKeyParameterName + `</name>
|
||||
<name>` + credentialIDParameterName + `</name>
|
||||
<description></description>
|
||||
<defaultValue></defaultValue>
|
||||
<trim>false</trim>
|
||||
</hudson.model.StringParameterDefinition>
|
||||
<hudson.model.StringParameterDefinition>
|
||||
<name>` + repositoryURLParameterName + `</name>
|
||||
@@ -175,11 +224,7 @@ var seedJobConfigXML = `
|
||||
</hudson.model.ParametersDefinitionProperty>
|
||||
</properties>
|
||||
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps@2.61">
|
||||
<script>import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey
|
||||
import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey.DirectEntryPrivateKeySource
|
||||
import com.cloudbees.plugins.credentials.CredentialsScope
|
||||
import com.cloudbees.plugins.credentials.SystemCredentialsProvider
|
||||
import com.cloudbees.plugins.credentials.domains.Domain
|
||||
<script>
|
||||
import hudson.model.FreeStyleProject
|
||||
import hudson.model.labels.LabelAtom
|
||||
import hudson.plugins.git.BranchSpec
|
||||
@@ -190,36 +235,19 @@ import javaposse.jobdsl.plugin.ExecuteDslScripts
|
||||
import javaposse.jobdsl.plugin.LookupStrategy
|
||||
import javaposse.jobdsl.plugin.RemovedJobAction
|
||||
import javaposse.jobdsl.plugin.RemovedViewAction
|
||||
import jenkins.model.Jenkins
|
||||
import javaposse.jobdsl.plugin.GlobalJobDslSecurityConfiguration
|
||||
import jenkins.model.GlobalConfiguration
|
||||
|
||||
import static com.google.common.collect.Lists.newArrayList
|
||||
|
||||
// https://javadoc.jenkins.io/plugin/ssh-credentials/com/cloudbees/jenkins/plugins/sshcredentials/impl/BasicSSHUserPrivateKey.html
|
||||
BasicSSHUserPrivateKey deployKeyPrivate = new BasicSSHUserPrivateKey(
|
||||
CredentialsScope.GLOBAL,
|
||||
"${params.DEPLOY_KEY_ID}",
|
||||
"git",
|
||||
new DirectEntryPrivateKeySource("${params.PRIVATE_KEY}"),
|
||||
"",
|
||||
"${params.DEPLOY_KEY_ID}"
|
||||
)
|
||||
|
||||
// https://javadoc.jenkins.io/plugin/credentials/index.html?com/cloudbees/plugins/credentials/SystemCredentialsProvider.html
|
||||
SystemCredentialsProvider.getInstance().getStore().addCredentials(Domain.global(), deployKeyPrivate)
|
||||
|
||||
Jenkins jenkins = Jenkins.instance
|
||||
|
||||
def jobDslSeedName = "${params.DEPLOY_KEY_ID}-` + constants.SeedJobSuffix + `"
|
||||
def jobDslDeployKeyName = "${params.DEPLOY_KEY_ID}"
|
||||
def jobDslSeedName = "${params.` + idParameterName + `}-` + constants.SeedJobSuffix + `"
|
||||
def jobRef = jenkins.getItem(jobDslSeedName)
|
||||
|
||||
def repoList = GitSCM.createRepoList("${params.REPOSITORY_URL}", jobDslDeployKeyName)
|
||||
def repoList = GitSCM.createRepoList("${params.` + repositoryURLParameterName + `}", "${params.` + credentialIDParameterName + `}")
|
||||
def gitExtensions = [new CloneOption(true, true, "", 10)]
|
||||
def scm = new GitSCM(
|
||||
repoList,
|
||||
newArrayList(new BranchSpec("${params.REPOSITORY_BRANCH}")),
|
||||
newArrayList(new BranchSpec("${params.` + repositoryBranchParameterName + `}")),
|
||||
false,
|
||||
Collections.<SubmoduleConfig> emptyList(),
|
||||
null,
|
||||
@@ -228,7 +256,7 @@ def scm = new GitSCM(
|
||||
)
|
||||
|
||||
def executeDslScripts = new ExecuteDslScripts()
|
||||
executeDslScripts.setTargets("${params.TARGETS}")
|
||||
executeDslScripts.setTargets("${params.` + targetsParameterName + `}")
|
||||
executeDslScripts.setSandbox(false)
|
||||
executeDslScripts.setRemovedJobAction(RemovedJobAction.DELETE)
|
||||
executeDslScripts.setRemovedViewAction(RemovedViewAction.DELETE)
|
||||
@@ -240,13 +268,11 @@ if (jobRef == null) {
|
||||
}
|
||||
jobRef.getBuildersList().clear()
|
||||
jobRef.getBuildersList().add(executeDslScripts)
|
||||
jobRef.setDisplayName("${params.SEED_JOB_DISPLAY_NAME}")
|
||||
jobRef.setDisplayName("${params.` + displayNameParameterName + `}")
|
||||
jobRef.setScm(scm)
|
||||
// TODO don't use master executors
|
||||
jobRef.setAssignedLabel(new LabelAtom("master"))
|
||||
|
||||
// disable Job DSL script approval
|
||||
GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration.class).useScriptSecurity=false
|
||||
GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration.class).save()
|
||||
jenkins.getQueue().schedule(jobRef)
|
||||
</script>
|
||||
<sandbox>false</sandbox>
|
||||
|
||||
@@ -134,11 +134,12 @@ func jenkinsCustomResource() *v1alpha1.Jenkins {
|
||||
},
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "jenkins-operator-e2e",
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
ID: "jenkins-operator-e2e",
|
||||
JenkinsCredentialType: v1alpha1.NoJenkinsCredentialCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/user/seedjobs"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
stackerr "github.com/pkg/errors"
|
||||
"k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -28,45 +30,69 @@ func (r *ReconcileUserConfiguration) Validate(jenkins *v1alpha1.Jenkins) (bool,
|
||||
|
||||
func (r *ReconcileUserConfiguration) validateSeedJobs(jenkins *v1alpha1.Jenkins) (bool, error) {
|
||||
valid := true
|
||||
|
||||
// TODO id must be unique
|
||||
if jenkins.Spec.SeedJobs != nil {
|
||||
for _, seedJob := range jenkins.Spec.SeedJobs {
|
||||
logger := r.logger.WithValues("seedJob", fmt.Sprintf("%+v", seedJob)).V(log.VWarn)
|
||||
|
||||
// validate seed job id is not empty
|
||||
if len(seedJob.ID) == 0 {
|
||||
logger.Info("seed job id can't be empty")
|
||||
logger.Info("id can't be empty")
|
||||
valid = false
|
||||
}
|
||||
|
||||
if len(seedJob.RepositoryBranch) == 0 {
|
||||
logger.Info("repository branch can't be empty")
|
||||
valid = false
|
||||
}
|
||||
|
||||
if len(seedJob.RepositoryURL) == 0 {
|
||||
logger.Info("repository URL branch can't be empty")
|
||||
valid = false
|
||||
}
|
||||
|
||||
if len(seedJob.Targets) == 0 {
|
||||
logger.Info("targets can't be empty")
|
||||
valid = false
|
||||
}
|
||||
|
||||
if _, ok := v1alpha1.AllowedJenkinsCredentialMap[string(seedJob.JenkinsCredentialType)]; !ok {
|
||||
logger.Info("unknown credential type")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if (seedJob.JenkinsCredentialType == v1alpha1.BasicSSHCredentialType ||
|
||||
seedJob.JenkinsCredentialType == v1alpha1.UsernamePasswordCredentialType) && len(seedJob.CredentialID) == 0 {
|
||||
logger.Info("credential ID can't be empty")
|
||||
valid = false
|
||||
}
|
||||
|
||||
// validate repository url match private key
|
||||
if strings.Contains(seedJob.RepositoryURL, "git@") {
|
||||
if seedJob.PrivateKey.SecretKeyRef == nil {
|
||||
logger.Info("private key can't be empty while using ssh repository url")
|
||||
valid = false
|
||||
}
|
||||
if strings.Contains(seedJob.RepositoryURL, "git@") && seedJob.JenkinsCredentialType == v1alpha1.NoJenkinsCredentialCredentialType {
|
||||
logger.Info("Jenkins credential must be set while using ssh repository url")
|
||||
valid = false
|
||||
}
|
||||
|
||||
// validate private key from secret
|
||||
if seedJob.PrivateKey.SecretKeyRef != nil {
|
||||
deployKeySecret := &v1.Secret{}
|
||||
namespaceName := types.NamespacedName{Namespace: jenkins.Namespace, Name: seedJob.PrivateKey.SecretKeyRef.Name}
|
||||
err := r.k8sClient.Get(context.TODO(), namespaceName, deployKeySecret)
|
||||
if seedJob.JenkinsCredentialType == v1alpha1.BasicSSHCredentialType || seedJob.JenkinsCredentialType == v1alpha1.UsernamePasswordCredentialType {
|
||||
secret := &v1.Secret{}
|
||||
namespaceName := types.NamespacedName{Namespace: jenkins.Namespace, Name: seedJob.CredentialID}
|
||||
err := r.k8sClient.Get(context.TODO(), namespaceName, secret)
|
||||
if err != nil && apierrors.IsNotFound(err) {
|
||||
logger.Info("secret not found")
|
||||
valid = false
|
||||
logger.Info(fmt.Sprintf("required secret '%s' with Jenkins credential not found", seedJob.CredentialID))
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, stackerr.WithStack(err)
|
||||
}
|
||||
|
||||
privateKey := string(deployKeySecret.Data[seedJob.PrivateKey.SecretKeyRef.Key])
|
||||
if privateKey == "" {
|
||||
logger.Info("private key is empty")
|
||||
valid = false
|
||||
if seedJob.JenkinsCredentialType == v1alpha1.BasicSSHCredentialType {
|
||||
if ok := validateBasicSSHSecret(logger, *secret); !ok {
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
|
||||
if err := validatePrivateKey(privateKey); err != nil {
|
||||
logger.Info(fmt.Sprintf("private key is invalid: %s", err))
|
||||
valid = false
|
||||
if seedJob.JenkinsCredentialType == v1alpha1.UsernamePasswordCredentialType {
|
||||
if ok := validateUsernamePasswordSecret(logger, *secret); !ok {
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +100,59 @@ func (r *ReconcileUserConfiguration) validateSeedJobs(jenkins *v1alpha1.Jenkins)
|
||||
return valid, nil
|
||||
}
|
||||
|
||||
func validateBasicSSHSecret(logger logr.InfoLogger, secret v1.Secret) bool {
|
||||
valid := true
|
||||
username, exists := secret.Data[seedjobs.UsernameSecretKey]
|
||||
if !exists {
|
||||
logger.Info(fmt.Sprintf("required data '%s' not found in secret '%s'", seedjobs.UsernameSecretKey, secret.ObjectMeta.Name))
|
||||
valid = false
|
||||
}
|
||||
if len(username) == 0 {
|
||||
logger.Info(fmt.Sprintf("required data '%s' is empty in secret '%s'", seedjobs.UsernameSecretKey, secret.ObjectMeta.Name))
|
||||
valid = false
|
||||
}
|
||||
|
||||
privateKey, exists := secret.Data[seedjobs.PrivateKeySecretKey]
|
||||
if !exists {
|
||||
logger.Info(fmt.Sprintf("required data '%s' not found in secret '%s'", seedjobs.PrivateKeySecretKey, secret.ObjectMeta.Name))
|
||||
valid = false
|
||||
}
|
||||
if len(string(privateKey)) == 0 {
|
||||
logger.Info(fmt.Sprintf("required data '%s' not found in secret '%s'", seedjobs.PrivateKeySecretKey, secret.ObjectMeta.Name))
|
||||
return false
|
||||
}
|
||||
if err := validatePrivateKey(string(privateKey)); err != nil {
|
||||
logger.Info(fmt.Sprintf("private key '%s' invalid in secret '%s': %s", seedjobs.PrivateKeySecretKey, secret.ObjectMeta.Name, err))
|
||||
valid = false
|
||||
}
|
||||
|
||||
return valid
|
||||
}
|
||||
|
||||
func validateUsernamePasswordSecret(logger logr.InfoLogger, secret v1.Secret) bool {
|
||||
valid := true
|
||||
username, exists := secret.Data[seedjobs.UsernameSecretKey]
|
||||
if !exists {
|
||||
logger.Info(fmt.Sprintf("required data '%s' not found in secret '%s'", seedjobs.UsernameSecretKey, secret.ObjectMeta.Name))
|
||||
valid = false
|
||||
}
|
||||
if len(username) == 0 {
|
||||
logger.Info(fmt.Sprintf("required data '%s' is empty in secret '%s'", seedjobs.UsernameSecretKey, secret.ObjectMeta.Name))
|
||||
valid = false
|
||||
}
|
||||
password, exists := secret.Data[seedjobs.PasswordSecretKey]
|
||||
if !exists {
|
||||
logger.Info(fmt.Sprintf("required data '%s' not found in secret '%s'", seedjobs.PasswordSecretKey, secret.ObjectMeta.Name))
|
||||
valid = false
|
||||
}
|
||||
if len(password) == 0 {
|
||||
logger.Info(fmt.Sprintf("required data '%s' is empty in secret '%s'", seedjobs.PasswordSecretKey, secret.ObjectMeta.Name))
|
||||
valid = false
|
||||
}
|
||||
|
||||
return valid
|
||||
}
|
||||
|
||||
func validatePrivateKey(privateKey string) error {
|
||||
block, _ := pem.Decode([]byte(privateKey))
|
||||
if block == nil {
|
||||
|
||||
@@ -2,10 +2,10 @@ package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/user/seedjobs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -40,8 +40,7 @@ JjihnIfoDu9MfU24GWDw49wGPTn+eI7GQC+8yxGg7fd24kohHSaCowoW16pbYVco
|
||||
6iLr5rkCgYBt0bcYJ3AOTH0UXS8kvJvnyce/RBIAMoUABwvdkZt9r5B4UzsoLq5e
|
||||
WrrU6fSRsE6lSsBd83pOAQ46tv+vntQ+0EihD9/0INhkQM99lBw1TFdFTgGSAs1e
|
||||
ns4JGP6f5uIuwqu/nbqPqMyDovjkGbX2znuGBcvki90Pi97XL7MMWw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
|
||||
var fakeInvalidPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEArK4ld6i2iqW6L3jaTZaKD/v7PjDn+Ik9MXp+kvLcUw/+wEGm
|
||||
@@ -50,189 +49,398 @@ SwiLd8TWAvXkxdXm8fDOGAZbYK2alMV+M+9E2OpZsBUCxmb/3FAofF6JccKoJOH8
|
||||
`
|
||||
|
||||
func TestValidateSeedJobs(t *testing.T) {
|
||||
data := []struct {
|
||||
description string
|
||||
jenkins *v1alpha1.Jenkins
|
||||
secret *corev1.Secret
|
||||
expectedResult bool
|
||||
}{
|
||||
{
|
||||
description: "Valid with public repository and without private key",
|
||||
jenkins: &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "jenkins-operator-e2e",
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
description: "Invalid without id",
|
||||
jenkins: &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
description: "Valid with private key and secret",
|
||||
jenkins: &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "jenkins-operator-e2e",
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
PrivateKey: v1alpha1.PrivateKey{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "deploy-keys",
|
||||
},
|
||||
Key: "jenkins-operator-e2e",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "deploy-keys",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"jenkins-operator-e2e": []byte(fakePrivateKey),
|
||||
},
|
||||
},
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
description: "Invalid private key in secret",
|
||||
jenkins: &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "jenkins-operator-e2e",
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
PrivateKey: v1alpha1.PrivateKey{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "deploy-keys",
|
||||
},
|
||||
Key: "jenkins-operator-e2e",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "deploy-keys",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"jenkins-operator-e2e": []byte(fakeInvalidPrivateKey),
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
description: "Invalid with PrivateKey and empty Secret data",
|
||||
jenkins: &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "jenkins-operator-e2e",
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
PrivateKey: v1alpha1.PrivateKey{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: "deploy-keys",
|
||||
},
|
||||
Key: "jenkins-operator-e2e",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
secret: &corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "deploy-keys",
|
||||
Namespace: "default",
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"jenkins-operator-e2e": []byte(""),
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
description: "Invalid with ssh RepositoryURL and empty PrivateKey",
|
||||
jenkins: &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "jenkins-operator-e2e",
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "git@github.com:jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResult: false,
|
||||
},
|
||||
secretTypeMeta := metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
}
|
||||
secretObjectMeta := metav1.ObjectMeta{
|
||||
Name: "deploy-keys",
|
||||
Namespace: "default",
|
||||
}
|
||||
t.Run("Valid with public repository and without private key", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "jenkins-operator-e2e",
|
||||
JenkinsCredentialType: v1alpha1.NoJenkinsCredentialCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testingData := range data {
|
||||
t.Run(fmt.Sprintf("Testing '%s'", testingData.description), func(t *testing.T) {
|
||||
fakeClient := fake.NewFakeClient()
|
||||
if testingData.secret != nil {
|
||||
err := fakeClient.Create(context.TODO(), testingData.secret)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(testingData.jenkins)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, testingData.expectedResult, result)
|
||||
})
|
||||
}
|
||||
userReconcileLoop := New(fake.NewFakeClient(), nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, result)
|
||||
})
|
||||
t.Run("Invalid without id", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
JenkinsCredentialType: v1alpha1.NoJenkinsCredentialCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
userReconcileLoop := New(fake.NewFakeClient(), nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Valid with private key and secret", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "deploy-keys",
|
||||
JenkinsCredentialType: v1alpha1.BasicSSHCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
TypeMeta: secretTypeMeta,
|
||||
ObjectMeta: secretObjectMeta,
|
||||
Data: map[string][]byte{
|
||||
seedjobs.UsernameSecretKey: []byte("username"),
|
||||
seedjobs.PrivateKeySecretKey: []byte(fakePrivateKey),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, result)
|
||||
})
|
||||
t.Run("Invalid private key in secret", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "deploy-keys",
|
||||
JenkinsCredentialType: v1alpha1.BasicSSHCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
TypeMeta: secretTypeMeta,
|
||||
ObjectMeta: secretObjectMeta,
|
||||
Data: map[string][]byte{
|
||||
seedjobs.UsernameSecretKey: []byte("username"),
|
||||
seedjobs.PrivateKeySecretKey: []byte(fakeInvalidPrivateKey),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Invalid with PrivateKey and empty Secret data", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "deploy-keys",
|
||||
JenkinsCredentialType: v1alpha1.BasicSSHCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
TypeMeta: secretTypeMeta,
|
||||
ObjectMeta: secretObjectMeta,
|
||||
Data: map[string][]byte{
|
||||
seedjobs.UsernameSecretKey: []byte("username"),
|
||||
seedjobs.PrivateKeySecretKey: []byte(""),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Invalid with ssh RepositoryURL and empty PrivateKey", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "jenkins-operator-e2e",
|
||||
JenkinsCredentialType: v1alpha1.BasicSSHCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "git@github.com:jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
userReconcileLoop := New(fake.NewFakeClient(), nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Invalid without targets", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
JenkinsCredentialType: v1alpha1.NoJenkinsCredentialCredentialType,
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
userReconcileLoop := New(fake.NewFakeClient(), nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Invalid without repository URL", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
JenkinsCredentialType: v1alpha1.NoJenkinsCredentialCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
userReconcileLoop := New(fake.NewFakeClient(), nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Invalid without repository branch", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
JenkinsCredentialType: v1alpha1.NoJenkinsCredentialCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
userReconcileLoop := New(fake.NewFakeClient(), nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Valid with username and password", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "deploy-keys",
|
||||
JenkinsCredentialType: v1alpha1.UsernamePasswordCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
TypeMeta: secretTypeMeta,
|
||||
ObjectMeta: secretObjectMeta,
|
||||
Data: map[string][]byte{
|
||||
seedjobs.UsernameSecretKey: []byte("some-username"),
|
||||
seedjobs.PasswordSecretKey: []byte("some-password"),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, result)
|
||||
})
|
||||
t.Run("Invalid with empty username", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "deploy-keys",
|
||||
JenkinsCredentialType: v1alpha1.UsernamePasswordCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
TypeMeta: secretTypeMeta,
|
||||
ObjectMeta: secretObjectMeta,
|
||||
Data: map[string][]byte{
|
||||
seedjobs.UsernameSecretKey: []byte(""),
|
||||
seedjobs.PasswordSecretKey: []byte("some-password"),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Invalid with empty password", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "deploy-keys",
|
||||
JenkinsCredentialType: v1alpha1.UsernamePasswordCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
TypeMeta: secretTypeMeta,
|
||||
ObjectMeta: secretObjectMeta,
|
||||
Data: map[string][]byte{
|
||||
seedjobs.UsernameSecretKey: []byte("some-username"),
|
||||
seedjobs.PasswordSecretKey: []byte(""),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Invalid without username", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "deploy-keys",
|
||||
JenkinsCredentialType: v1alpha1.UsernamePasswordCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
TypeMeta: secretTypeMeta,
|
||||
ObjectMeta: secretObjectMeta,
|
||||
Data: map[string][]byte{
|
||||
seedjobs.PasswordSecretKey: []byte("some-password"),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
t.Run("Invalid without password", func(t *testing.T) {
|
||||
jenkins := &v1alpha1.Jenkins{
|
||||
Spec: v1alpha1.JenkinsSpec{
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "example",
|
||||
CredentialID: "deploy-keys",
|
||||
JenkinsCredentialType: v1alpha1.UsernamePasswordCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
TypeMeta: secretTypeMeta,
|
||||
ObjectMeta: secretObjectMeta,
|
||||
Data: map[string][]byte{
|
||||
seedjobs.UsernameSecretKey: []byte("some-username"),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
userReconcileLoop := New(fakeClient, nil, logf.ZapLogger(false), nil)
|
||||
result, err := userReconcileLoop.validateSeedJobs(jenkins)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, result)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -402,11 +402,12 @@ func jenkinsCustomResource() *v1alpha1.Jenkins {
|
||||
},
|
||||
SeedJobs: []v1alpha1.SeedJob{
|
||||
{
|
||||
ID: "jenkins-operator-e2e",
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
ID: "jenkins-operator-e2e",
|
||||
JenkinsCredentialType: v1alpha1.NoJenkinsCredentialCredentialType,
|
||||
Targets: "cicd/jobs/*.jenkins",
|
||||
Description: "Jenkins Operator e2e tests repository",
|
||||
RepositoryBranch: "master",
|
||||
RepositoryURL: "https://github.com/jenkinsci/kubernetes-operator.git",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user