Seed Jobs refactoring

- add new CreateOrUpdateJob function for Jenkins client
- better naming
This commit is contained in:
antoniaklja 2018-12-21 16:13:28 +01:00
parent 43d45cda31
commit 25d63a881f
4 changed files with 57 additions and 38 deletions

View File

@ -8,6 +8,7 @@ import (
"strings" "strings"
"github.com/bndr/gojenkins" "github.com/bndr/gojenkins"
"errors"
) )
// Jenkins defines Jenkins API // Jenkins defines Jenkins API
@ -20,6 +21,7 @@ type Jenkins interface {
CreateFolder(name string, parents ...string) (*gojenkins.Folder, error) CreateFolder(name string, parents ...string) (*gojenkins.Folder, error)
CreateJobInFolder(config string, jobName string, parentIDs ...string) (*gojenkins.Job, error) CreateJobInFolder(config string, jobName string, parentIDs ...string) (*gojenkins.Job, error)
CreateJob(config string, options ...interface{}) (*gojenkins.Job, error) CreateJob(config string, options ...interface{}) (*gojenkins.Job, error)
CreateOrUpdateJob(config string, options ...interface{}) (*gojenkins.Job, error)
RenameJob(job string, name string) *gojenkins.Job RenameJob(job string, name string) *gojenkins.Job
CopyJob(copyFrom string, newName string) (*gojenkins.Job, error) CopyJob(copyFrom string, newName string) (*gojenkins.Job, error)
DeleteJob(name string) (bool, error) DeleteJob(name string) (bool, error)
@ -53,6 +55,34 @@ type jenkins struct {
gojenkins.Jenkins gojenkins.Jenkins
} }
// CreateOrUpdateJob creates or updates a job from config
func (jenkins *jenkins) CreateOrUpdateJob(config string, options ...interface{}) (*gojenkins.Job, error) {
// taken from gojenkins.CreateJob
qr := make(map[string]string)
if len(options) > 0 {
qr["name"] = options[0].(string)
} else {
return nil, errors.New("error creating job, job name is missing")
}
// create or update
job, err := jenkins.GetJob(qr["name"])
if jobNotExists(err) {
_, err := jenkins.CreateJob(config, options)
return nil, err
} else if err != nil {
err := job.UpdateConfig(config)
return nil, err
}
return job, err
}
func jobNotExists(err error) bool {
if err != nil {
return err.Error() == errors.New("404").Error()
}
return false
}
// BuildJenkinsAPIUrl returns Jenkins API URL // BuildJenkinsAPIUrl returns Jenkins API URL
func BuildJenkinsAPIUrl(namespace, serviceName string, portNumber int, local, minikube bool) (string, error) { func BuildJenkinsAPIUrl(namespace, serviceName string, portNumber int, local, minikube bool) (string, error) {
// Get Jenkins URL from minikube command // Get Jenkins URL from minikube command

View File

@ -1,2 +1,2 @@
// Package user is responsible for Jenkins user configuration // Package user implements Jenkins user configuration and reconciliation
package user package user

View File

@ -36,7 +36,7 @@ func (r *ReconcileUserConfiguration) Reconcile() (*reconcile.Result, error) {
return &reconcile.Result{}, nil return &reconcile.Result{}, nil
} }
err := seedjobs.ConfigureSeedJobs(r.jenkinsClient, r.k8sClient, r.jenkins) err := seedjobs.EnsureSeedJobs(r.jenkinsClient, r.k8sClient, r.jenkins)
if err != nil { if err != nil {
return &reconcile.Result{}, err return &reconcile.Result{}, err
} }

View File

@ -6,7 +6,6 @@ import (
k8s "sigs.k8s.io/controller-runtime/pkg/client" k8s "sigs.k8s.io/controller-runtime/pkg/client"
"context" "context"
"errors"
"fmt" "fmt"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@ -24,20 +23,35 @@ const (
displayNameParameterName = "SEED_JOB_DISPLAY_NAME" displayNameParameterName = "SEED_JOB_DISPLAY_NAME"
) )
// ConfigureSeedJobs configures and triggers seed job pipeline for every Jenkins.Spec.SeedJobs entry // EnsureSeedJobs configures seed job and runs it for every entry from Jenkins.Spec.SeedJobs
func ConfigureSeedJobs(jenkinsClient jenkins.Jenkins, k8sClient k8s.Client, jenkins *virtuslabv1alpha1.Jenkins) error { func EnsureSeedJobs(jenkinsClient jenkins.Jenkins, k8sClient k8s.Client, jenkins *virtuslabv1alpha1.Jenkins) error {
err := configureSeedJobsPipeline(jenkinsClient) err := configureSeedJob(jenkinsClient)
if err != nil { if err != nil {
return err return err
} }
err = buildAndVerifySeedJobs(jenkinsClient, k8sClient, jenkins)
if err != nil {
return err
}
return nil
}
func configureSeedJob(jenkinsClient jenkins.Jenkins) error {
_, err := jenkinsClient.CreateOrUpdateJob(seedJobConfigXML, ConfigureSeedJobsName)
if err != nil {
return err
}
return nil
}
func buildAndVerifySeedJobs(jenkinsClient jenkins.Jenkins, k8sClient k8s.Client, jenkins *virtuslabv1alpha1.Jenkins) error {
seedJobs := jenkins.Spec.SeedJobs seedJobs := jenkins.Spec.SeedJobs
for _, seedJob := range seedJobs { for _, seedJob := range seedJobs {
privateKey, err := extractPrivateKey(k8sClient, jenkins.Namespace, seedJob) privateKey, err := privateKeyFromSecret(k8sClient, jenkins.Namespace, seedJob)
if err != nil { if err != nil {
return err return err
} }
err = triggerConfigureSeedJobsPipeline( err = buildAndVerifySeedJob(
jenkinsClient, jenkinsClient,
seedJob.ID, seedJob.ID,
privateKey, privateKey,
@ -50,33 +64,9 @@ func ConfigureSeedJobs(jenkinsClient jenkins.Jenkins, k8sClient k8s.Client, jenk
return nil return nil
} }
// configureSeedJobsPipeline configures seed jobs and deploy keys func buildAndVerifySeedJob(jenkinsClient jenkins.Jenkins, deployKeyID, privateKey, repositoryURL, repositoryBranch, targets, displayName string) error {
func configureSeedJobsPipeline(jenkinsClient jenkins.Jenkins) error { // FIXME this function should build job and verify job status when finished (state in cr status)
return createOrUpdateSeedJob(jenkinsClient) // requeue when job is running and check job status next time
}
// FIXME this function should be part of jenkins client API
func createOrUpdateSeedJob(jenkinsClient jenkins.Jenkins) error {
job, err := jenkinsClient.GetJob(ConfigureSeedJobsName)
if jobNotExists(err) {
_, err := jenkinsClient.CreateJob(seedJobConfigXML, ConfigureSeedJobsName)
return err
} else if err != nil {
err := job.UpdateConfig(seedJobConfigXML)
return err
}
return err
}
func jobNotExists(err error) bool {
if err != nil {
return err.Error() == errors.New("404").Error()
}
return false
}
// triggerConfigureSeedJobsPipeline triggers and configures seed job for specific GitHub repository
func triggerConfigureSeedJobsPipeline(jenkinsClient jenkins.Jenkins, deployKeyID, privateKey, repositoryURL, repositoryBranch, targets, displayName string) error {
options := map[string]string{ options := map[string]string{
deployKeyIDParameterName: deployKeyID, deployKeyIDParameterName: deployKeyID,
privateKeyParameterName: privateKey, privateKeyParameterName: privateKey,
@ -85,7 +75,6 @@ func triggerConfigureSeedJobsPipeline(jenkinsClient jenkins.Jenkins, deployKeyID
targetsParameterName: targets, targetsParameterName: targets,
displayNameParameterName: displayName, displayNameParameterName: displayName,
} }
// FIXME implement EnsureJob()
_, err := jenkinsClient.BuildJob(ConfigureSeedJobsName, options) _, err := jenkinsClient.BuildJob(ConfigureSeedJobsName, options)
if err != nil { if err != nil {
return err return err
@ -93,7 +82,7 @@ func triggerConfigureSeedJobsPipeline(jenkinsClient jenkins.Jenkins, deployKeyID
return nil return nil
} }
func extractPrivateKey(k8sClient k8s.Client, namespace string, seedJob virtuslabv1alpha1.SeedJob) (string, error) { func privateKeyFromSecret(k8sClient k8s.Client, namespace string, seedJob virtuslabv1alpha1.SeedJob) (string, error) {
if seedJob.PrivateKey.SecretKeyRef != nil { if seedJob.PrivateKey.SecretKeyRef != nil {
deployKeySecret := &v1.Secret{} deployKeySecret := &v1.Secret{}
namespaceName := types.NamespacedName{Namespace: namespace, Name: seedJob.PrivateKey.SecretKeyRef.Name} namespaceName := types.NamespacedName{Namespace: namespace, Name: seedJob.PrivateKey.SecretKeyRef.Name}
@ -106,7 +95,7 @@ func extractPrivateKey(k8sClient k8s.Client, namespace string, seedJob virtuslab
return "", nil return "", nil
} }
// FIXME use mask-password plugin for params.PRIVATE_KEY // FIXME consider to use mask-password plugin for params.PRIVATE_KEY
var seedJobConfigXML = ` var seedJobConfigXML = `
<flow-definition plugin="workflow-job@2.30"> <flow-definition plugin="workflow-job@2.30">
<actions/> <actions/>