pkg/service/jenkins/jenkins.go (602 lines of code) (raw):

package jenkins import ( "bufio" "context" "encoding/base64" "errors" "fmt" "io" "os" "path/filepath" "reflect" "strings" "github.com/dchest/uniuri" coreV1Api "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" gerritApi "github.com/epam/edp-gerrit-operator/v2/pkg/apis/v2/v1" gerritSpec "github.com/epam/edp-gerrit-operator/v2/pkg/service/gerrit/spec" keycloakApi "github.com/epam/edp-keycloak-operator/pkg/apis/v1/v1" keycloakControllerHelper "github.com/epam/edp-keycloak-operator/pkg/controller/helper" jenkinsApi "github.com/epam/edp-jenkins-operator/v2/pkg/apis/v2/v1" jenkinsClient "github.com/epam/edp-jenkins-operator/v2/pkg/client/jenkins" helperController "github.com/epam/edp-jenkins-operator/v2/pkg/controller/helper" "github.com/epam/edp-jenkins-operator/v2/pkg/helper" jenkinsDefaultSpec "github.com/epam/edp-jenkins-operator/v2/pkg/service/jenkins/spec" "github.com/epam/edp-jenkins-operator/v2/pkg/service/platform" platformHelper "github.com/epam/edp-jenkins-operator/v2/pkg/service/platform/helper" "github.com/epam/edp-jenkins-operator/v2/pkg/util/consts" ) const ( initContainerName = "grant-permissions" defaultScriptsDirectory = "scripts" defaultSlavesDirectory = "slaves" defaultJobProvisionsDirectory = "job-provisions" defaultCiJobProvisionsDirectory = "ci" defaultCdJobProvisionsDirectory = "cd" DefaultTemplatesDirectory = "templates" SlavesTemplateName = "jenkins-slaves" SharedLibrariesTemplateName = "config-shared-libraries.tmpl" kubernetesPluginTemplateName = "config-kubernetes-plugin.tmpl" keycloakConfigTemplateName = "config-keycloak.tmpl" cbisTemplateName = "cbis.json" jimTemplateName = "jim.json" defaultScriptConfigMapKey = "context" sshKeyDefaultMountPath = "/tmp/ssh" imgFolder = "img" jenIcon = "jenkins.svg" configMapStringFormat = "%s-%s" pathStringFormat = "%s/%s" ) var log = ctrl.Log.WithName("jenkins_service") // JenkinsService interface for Jenkins EDP component. type JenkinsService interface { Configure(instance *jenkinsApi.Jenkins) (*jenkinsApi.Jenkins, bool, error) ExposeConfiguration(instance *jenkinsApi.Jenkins) (*jenkinsApi.Jenkins, bool, error) Integration(instance *jenkinsApi.Jenkins) (*jenkinsApi.Jenkins, bool, error) IsDeploymentReady(instance *jenkinsApi.Jenkins) (bool, error) CreateAdminPassword(instance *jenkinsApi.Jenkins) error } // NewJenkinsService function that returns JenkinsService implementation. func NewJenkinsService(ps platform.PlatformService, k8sClient client.Client, scheme *runtime.Scheme) JenkinsService { return JenkinsServiceImpl{ platformService: ps, k8sClient: k8sClient, k8sScheme: scheme, keycloakHelper: keycloakControllerHelper.MakeHelper(k8sClient, scheme, ctrl.Log.WithName("jenkins_service")), } } // JenkinsServiceImpl struct fo Jenkins EDP Component. type JenkinsServiceImpl struct { platformService platform.PlatformService k8sClient client.Client k8sScheme *runtime.Scheme keycloakHelper *keycloakControllerHelper.Helper } func (j JenkinsServiceImpl) setAdminSecretInStatus(instance *jenkinsApi.Jenkins, value string) (*jenkinsApi.Jenkins, error) { instance.Status.AdminSecretName = value if err := j.k8sClient.Status().Update(context.TODO(), instance); err != nil { if err := j.k8sClient.Update(context.TODO(), instance); err != nil { return instance, fmt.Errorf("failed to set admin secret name in status: %w", err) } } return instance, nil } // newIntegrationKeycloakClient creates a v1.KeycloakClient to be used in Integration. func (j JenkinsServiceImpl) newIntegrationKeycloakClient(instance *jenkinsApi.Jenkins) (*keycloakApi.KeycloakClient, error) { keycloakClient := keycloakApi.KeycloakClient{ ObjectMeta: metav1.ObjectMeta{ Name: instance.Name, Namespace: instance.Namespace, }, Spec: keycloakApi.KeycloakClientSpec{ ClientId: instance.Name, Public: !instance.Spec.KeycloakSpec.IsPrivate, Secret: instance.Spec.KeycloakSpec.SecretName, WebUrl: instance.Spec.ExternalURL, RealmRoles: &[]keycloakApi.RealmRole{ { Name: "jenkins-administrators", Composite: "administrator", }, { Name: "jenkins-users", Composite: "developer", }, }, }, } if keycloakClient.Spec.WebUrl == "" { externalURL, err := j.getExternalUrl(instance) if err != nil { return nil, fmt.Errorf("failed to get route from cluster: %w", err) } keycloakClient.Spec.WebUrl = externalURL } if instance.Spec.KeycloakSpec.Realm != "" { keycloakClient.Spec.TargetRealm = instance.Spec.KeycloakSpec.Realm } if err := j.platformService.CreateKeycloakClient(&keycloakClient); err != nil { return nil, fmt.Errorf("failed to create Keycloak Client data: %w", err) } keycloakClient, err := j.platformService.GetKeycloakClient(instance.Name, instance.Namespace) if err != nil { return nil, fmt.Errorf("failed to get Keycloak Client CR: %w", err) } return &keycloakClient, nil } // newIntegrationKeycloakRealm creates a v1.KeycloakRealm to be used in Integration. func (j JenkinsServiceImpl) newIntegrationKeycloakRealm(keycloakClient *keycloakApi.KeycloakClient, ) (*keycloakApi.KeycloakRealm, error) { keycloakRealm, err := j.keycloakHelper.GetOwnerKeycloakRealm(keycloakClient.ObjectMeta) if err != nil { return nil, fmt.Errorf("failed to get Keycloak Realm for %s client: %w", keycloakClient.Name, err) } if keycloakRealm == nil { return nil, errors.New("keycloak Realm CR in not created yet") } return keycloakRealm, nil } // newIntegrationKeycloak creates a v1.Keycloak to be used in Integration. func (j JenkinsServiceImpl) newIntegrationKeycloak( keycloakClient *keycloakApi.KeycloakClient, realm *keycloakApi.KeycloakRealm, ) (*keycloakApi.Keycloak, error) { keycloak, err := j.keycloakHelper.GetOwnerKeycloak(realm.ObjectMeta) if err != nil { errMsg := fmt.Sprintf("failed to get owner for %s/%s", keycloakClient.Namespace, keycloakClient.Name) return nil, fmt.Errorf("%s: %w", errMsg, err) } if keycloak == nil { return nil, errors.New("keycloak CR is not created yet") } return keycloak, nil } // newIntegrationJenkinsScriptData creates helper.JenkinsScriptData to be used in Integration. func (j JenkinsServiceImpl) newIntegrationJenkinsScriptData( instance *jenkinsApi.Jenkins, keycloak *keycloakApi.Keycloak, keycloakRealm *keycloakApi.KeycloakRealm, keycloakClient *keycloakApi.KeycloakClient, ) (*platformHelper.JenkinsScriptData, error) { jenkinsScriptData := platformHelper.JenkinsScriptData{} jenkinsScriptData.RealmName = keycloakRealm.Spec.RealmName jenkinsScriptData.KeycloakClientName = keycloakClient.Spec.ClientId jenkinsScriptData.KeycloakUrl = keycloak.Spec.Url jenkinsScriptData.KeycloakIsPrivate = instance.Spec.KeycloakSpec.IsPrivate if instance.Spec.KeycloakSpec.IsPrivate { dt, getSecretDataErr := j.platformService.GetSecretData(instance.Namespace, keycloakClient.Spec.Secret) if getSecretDataErr != nil { return nil, fmt.Errorf("failed to get keycloak client secret data: %w", getSecretDataErr) } jenkinsScriptData.KeycloakClientSecret = string(dt["clientSecret"]) return &jenkinsScriptData, nil } return &jenkinsScriptData, nil } func (j JenkinsServiceImpl) mountGerritCredentials(instance *jenkinsApi.Jenkins) error { options := client.ListOptions{Namespace: instance.Namespace} list := &gerritApi.GerritList{} if err := j.k8sClient.List(context.TODO(), list, &options); err != nil { str := err.Error() log.Info(str) log.V(1).Info(fmt.Sprintf("Gerrit installation is not found in namespace %v", instance.Namespace)) return nil } if len(list.Items) == 0 { log.V(1).Info(fmt.Sprintf("Gerrit installation is not found in namespace %v", instance.Namespace)) return nil } gerritCrObject := &list.Items[0] gerritSpecName := fmt.Sprintf(pathStringFormat, gerritSpec.EdpAnnotationsPrefix, gerritSpec.EdpCiUSerSshKeySuffix) if val, ok := gerritCrObject.ObjectMeta.Annotations[gerritSpecName]; ok { volMount := []coreV1Api.VolumeMount{ { Name: val, MountPath: sshKeyDefaultMountPath, ReadOnly: true, }, } var mode int32 = 400 vol := []coreV1Api.Volume{ { Name: val, VolumeSource: coreV1Api.VolumeSource{ Secret: &coreV1Api.SecretVolumeSource{ SecretName: val, DefaultMode: &mode, Items: []coreV1Api.KeyToPath{ { Key: "id_rsa", Path: "id_rsa", Mode: &mode, }, }, }, }, }, } if err := j.platformService.AddVolumeToInitContainer(instance, initContainerName, vol, volMount); err != nil { return fmt.Errorf("failed to patch Jenkins DC in namespace %v: %w", instance.Namespace, err) } } return nil } func (j JenkinsServiceImpl) createSecret( instance *jenkinsApi.Jenkins, secretName, username string, password *string, ) error { var secretPassword string if password == nil { secretPassword = uniuri.New() } else { secretPassword = *password } secretData := map[string][]byte{ "username": []byte(username), "password": []byte(secretPassword), } if err := j.platformService.CreateSecret(instance, secretName, secretData); err != nil { return fmt.Errorf("failed to create Secret %v: %w", secretName, err) } return nil } func setAnnotation(instance *jenkinsApi.Jenkins, key, value string) { if len(instance.Annotations) == 0 { instance.ObjectMeta.Annotations = map[string]string{ key: value, } return } instance.ObjectMeta.Annotations[key] = value } // Integration performs Jenkins integration with other EDP components. func (j JenkinsServiceImpl) Integration(instance *jenkinsApi.Jenkins) (*jenkinsApi.Jenkins, bool, error) { if instance.Spec.KeycloakSpec.Enabled { enabledInstance, err := j.integrateEnabledInstance(instance) if err != nil { return enabledInstance, false, fmt.Errorf("failed to integrate Enabled Instance: %w", err) } if err = j.mountGerritCredentials(enabledInstance); err != nil { return enabledInstance, false, fmt.Errorf("failed to mount Gerrit credentials: %w", err) } return enabledInstance, true, nil } if err := j.mountGerritCredentials(instance); err != nil { return instance, false, fmt.Errorf("failed to mount Gerrit credentials: %w", err) } return instance, true, nil } func (j JenkinsServiceImpl) integrateEnabledInstance(instance *jenkinsApi.Jenkins) (*jenkinsApi.Jenkins, error) { keycloakClient, err := j.newIntegrationKeycloakClient(instance) if err != nil { return instance, fmt.Errorf("failed to create KeycloakClient: %w", err) } keycloakRealm, err := j.newIntegrationKeycloakRealm(keycloakClient) if err != nil { return instance, fmt.Errorf("failed to create KeycloakRealm: %w", err) } keycloak, err := j.newIntegrationKeycloak(keycloakClient, keycloakRealm) if err != nil { return instance, fmt.Errorf("failed to create Keycloak: %w", err) } directoryPath, err := platformHelper.CreatePathToTemplateDirectory(DefaultTemplatesDirectory) if err != nil { return instance, fmt.Errorf("failed to create path to template directory: %w", err) } keycloakCfgFilePath := fmt.Sprintf("%s/%s", directoryPath, keycloakConfigTemplateName) jenkinsScriptData, err := j.newIntegrationJenkinsScriptData(instance, keycloak, keycloakRealm, keycloakClient) if err != nil { return instance, fmt.Errorf("failed to create JenkinsScriptData: %w", err) } scriptContext, err := platformHelper.ParseTemplate(jenkinsScriptData, keycloakCfgFilePath, keycloakConfigTemplateName) if err != nil { return instance, fmt.Errorf("failed to parse template: %w", err) } configKeycloakName := fmt.Sprintf(configMapStringFormat, instance.Name, "config-keycloak") configMapData := map[string]string{defaultScriptConfigMapKey: scriptContext.String()} if _, err = j.platformService.CreateConfigMap(instance, configKeycloakName, configMapData); err != nil { return instance, fmt.Errorf("failed to create config map: %w", err) } if _, err = j.platformService.CreateJenkinsScript(instance.Namespace, configKeycloakName, false); err != nil { return instance, fmt.Errorf("failed to create jenkins script: %w", err) } return instance, nil } // ExposeConfiguration performs exposing Jenkins configuration for other EDP components. func (j JenkinsServiceImpl) ExposeConfiguration(instance *jenkinsApi.Jenkins) (*jenkinsApi.Jenkins, bool, error) { upd := false jc, err := jenkinsClient.InitJenkinsClient(instance, j.platformService) if err != nil { return instance, upd, fmt.Errorf("failed to init Jenkins REST client: %w", err) } if jc == nil { return instance, upd, errors.New("jenkins returns nil client") } sl, err := jc.GetSlaves() if err != nil { return instance, upd, fmt.Errorf("failed to get Jenkins slave list: %w", err) } ss := newSlaveArray(sl) if !reflect.DeepEqual(instance.Status.Slaves, ss) { instance.Status.Slaves = ss upd = true } scopes := []string{defaultCiJobProvisionsDirectory, defaultCdJobProvisionsDirectory} var ps []jenkinsApi.JobProvision for _, scope := range scopes { pr, getJobProvisionsErr := jc.GetJobProvisions(fmt.Sprintf("/job/%v/job/%v", defaultJobProvisionsDirectory, scope)) if getJobProvisionsErr != nil { return instance, upd, fmt.Errorf("failed to get Jenkins Job provisions list for scope %v: %w", scope, getJobProvisionsErr) } for _, p := range pr { ps = append(ps, jenkinsApi.JobProvision{Name: p, Scope: scope}) } } if !reflect.DeepEqual(instance.Status.JobProvisions, ps) { instance.Status.JobProvisions = ps upd = true } if err := j.createEDPComponent(instance); err != nil { return instance, upd, err } return instance, upd, nil } func newSlaveArray(slaveNames []string) []jenkinsApi.Slave { slaves := make([]jenkinsApi.Slave, 0, len(slaveNames)) for _, name := range slaveNames { slaves = append(slaves, jenkinsApi.Slave{Name: name}) } return slaves } func (j JenkinsServiceImpl) createEDPComponent(jen *jenkinsApi.Jenkins) error { url, err := j.getExternalUrl(jen) if err != nil { return err } icon, err := j.getIcon() if err != nil { return err } if err := j.platformService.CreateEDPComponentIfNotExist(jen, url, *icon); err != nil { return fmt.Errorf("failed to check or create EDP component: %w", err) } return nil } func (j JenkinsServiceImpl) getExternalUrl(jen *jenkinsApi.Jenkins) (string, error) { if jen.Spec.ExternalURL != "" { return jen.Spec.ExternalURL, nil } h, s, p, err := j.platformService.GetExternalEndpoint(jen.Namespace, jen.Name) if err != nil { return "", fmt.Errorf("failed to get external endpoint: %w", err) } return fmt.Sprintf("%v://%v%v", s, h, p), nil } func (JenkinsServiceImpl) getIcon() (*string, error) { p, err := platformHelper.CreatePathToTemplateDirectory(imgFolder) if err != nil { return nil, fmt.Errorf("failed to create path to template dir: %w", err) } filePath := fmt.Sprintf(pathStringFormat, p, jenIcon) f, err := os.Open(filepath.Clean(filePath)) if err != nil { return nil, fmt.Errorf("failed to open icon file: %w", err) } reader := bufio.NewReader(f) content, err := io.ReadAll(reader) if err != nil { return nil, fmt.Errorf("failed to read icon file: %w", err) } encoded := base64.StdEncoding.EncodeToString(content) return &encoded, nil } func (j JenkinsServiceImpl) newJenkinsClient(instance *jenkinsApi.Jenkins) (*jenkinsClient.JenkinsClient, error) { jc, err := jenkinsClient.InitJenkinsClient(instance, j.platformService) if err != nil { return nil, fmt.Errorf("failed to init Jenkins REST client: %w", err) } if jc == nil { return nil, errors.New("jenkins returns nil client") } return jc, nil } func (j JenkinsServiceImpl) handleEmptyAdminTokenSecret(instance *jenkinsApi.Jenkins, adminTokenSecretName string, ) (*jenkinsApi.Jenkins, error) { jc, err := j.newJenkinsClient(instance) if err != nil { return instance, fmt.Errorf("failed to create new JenkinsClient: %w", err) } token, getAdminTokenErr := jc.GetAdminToken() if getAdminTokenErr != nil { return instance, fmt.Errorf("failed to get token from admin user: %w", getAdminTokenErr) } if err = j.createSecret(instance, adminTokenSecretName, jenkinsDefaultSpec.JenkinsDefaultAdminUser, token); err != nil { return instance, fmt.Errorf("failed to create secret: %w", err) } adminTokenAnnotationKey := helper.GenerateAnnotationKey(jenkinsDefaultSpec.JenkinsTokenAnnotationSuffix) setAnnotation(instance, adminTokenAnnotationKey, adminTokenSecretName) if err = j.k8sClient.Update(context.TODO(), instance); err != nil { return instance, fmt.Errorf("failed to update jenkins instance: %w", err) } updatedInstance, setSecretErr := j.setAdminSecretInStatus(instance, adminTokenSecretName) if setSecretErr != nil { return instance, fmt.Errorf("failed to set AdminSecret in Status: %w", setSecretErr) } return updatedInstance, nil } func (j JenkinsServiceImpl) createScriptsFromDefaultDir(instance *jenkinsApi.Jenkins) error { scriptsDirectoryPath, err := platformHelper.CreatePathToTemplateDirectory(defaultScriptsDirectory) if err != nil { return fmt.Errorf("failed to create path to template dir: %w", err) } scriptFiles, err := os.ReadDir(scriptsDirectoryPath) if err != nil { return fmt.Errorf("failed to read scriptFiles from dir %v: %w", scriptsDirectoryPath, err) } for _, file := range scriptFiles { configMapName := fmt.Sprintf(configMapStringFormat, instance.Name, file.Name()) configMapKey := consts.JenkinsDefaultScriptConfigMapKey path := filepath.FromSlash(fmt.Sprintf(pathStringFormat, scriptsDirectoryPath, file.Name())) if err = j.createScript(instance, configMapName, configMapKey, path); err != nil { return fmt.Errorf("failed to create script: %w", err) } } return nil } func (j JenkinsServiceImpl) createJobProvisionsFromDefaultDir(instance *jenkinsApi.Jenkins) error { scopes := []string{defaultCiJobProvisionsDirectory, defaultCdJobProvisionsDirectory} for _, scope := range scopes { jobPath := fmt.Sprintf(pathStringFormat, defaultJobProvisionsDirectory, scope) if err := j.createJobProvisions(jobPath, instance); err != nil { return fmt.Errorf("failed to create JobProvisions: %w", err) } } return nil } func (j JenkinsServiceImpl) createSlavesFromDefaultDir(instance *jenkinsApi.Jenkins) error { slavesDirectoryPath, err := platformHelper.CreatePathToTemplateDirectory(defaultSlavesDirectory) if err != nil { return fmt.Errorf("failed to create path to template directory: %w", err) } if _, err = os.ReadDir(slavesDirectoryPath); err != nil { return fmt.Errorf("failed to read directory %v: %w", slavesDirectoryPath, err) } JenkinsSlavesConfigmapLabels := map[string]string{ "role": "jenkins-slave", } if err = j.platformService.CreateConfigMapFromFileOrDir(instance, SlavesTemplateName, nil, slavesDirectoryPath, instance, JenkinsSlavesConfigmapLabels, ); err != nil { return fmt.Errorf("failed to create config-map %v in namespace %v: %w", SlavesTemplateName, instance.Namespace, err) } return nil } func (j JenkinsServiceImpl) createTemplatesFromDefaultDir(instance *jenkinsApi.Jenkins) error { templatesDirectoryPath, err := platformHelper.CreatePathToTemplateDirectory(DefaultTemplatesDirectory) if err != nil { return fmt.Errorf("failed to create path to template dir: %w", err) } var templatesList []string templatesList = append( templatesList, SharedLibrariesTemplateName, kubernetesPluginTemplateName, ) jenkinsScriptData := platformHelper.JenkinsScriptData{} jenkinsScriptData.JenkinsSharedLibraries = instance.Spec.SharedLibraries jenkinsScriptData.JenkinsUrl = fmt.Sprintf("http://%v:%v/%v", instance.Name, jenkinsDefaultSpec.JenkinsDefaultUiPort, instance.Spec.BasePath) for _, template := range templatesList { if err = createTemplateScript( templatesDirectoryPath, template, j.platformService, &jenkinsScriptData, instance, ); err != nil { return nil } } for _, template := range []map[string]string{ {"name": cbisTemplateName, "cmName": "cbis-template"}, {"name": jimTemplateName, "cmName": "jim-template"}, } { configMapName := template["cmName"] filePath := fmt.Sprintf("%s/%s", templatesDirectoryPath, template["name"]) if err = j.platformService.CreateConfigMapFromFileOrDir(instance, configMapName, nil, filePath, instance); err != nil { return fmt.Errorf("failed to create config-map %v: %w", configMapName, err) } } return nil } // Configure performs self-configuration of Jenkins. func (j JenkinsServiceImpl) Configure(instance *jenkinsApi.Jenkins) (*jenkinsApi.Jenkins, bool, error) { adminTokenSecretName := fmt.Sprintf(configMapStringFormat, instance.Name, jenkinsDefaultSpec.JenkinsTokenAnnotationSuffix) adminTokenSecret, err := j.platformService.GetSecretData(instance.Namespace, adminTokenSecretName) if err != nil { return instance, false, fmt.Errorf("failed to get admin token secret for %v: %w", instance.Name, err) } if adminTokenSecret == nil { updatedInstance, handleErr := j.handleEmptyAdminTokenSecret(instance, adminTokenSecretName) if handleErr != nil { return updatedInstance, false, fmt.Errorf("failed to handle empty AdminTokenSecret: %w", handleErr) } instance = updatedInstance } if err = j.createScriptsFromDefaultDir(instance); err != nil { return instance, false, fmt.Errorf("failed to create Scripts from Default Dir: %w", err) } if err = j.createJobProvisionsFromDefaultDir(instance); err != nil { return instance, false, fmt.Errorf("failed to create JobProvisions from Default Dir: %w", err) } if err = j.createSlavesFromDefaultDir(instance); err != nil { return instance, false, fmt.Errorf("failed to create Slaves from Default Dir: %w", err) } if err = j.createTemplatesFromDefaultDir(instance); err != nil { return instance, false, fmt.Errorf("failed to create Templates from Default Dir: %w", err) } return instance, true, nil } func createTemplateScript( templatesDirectoryPath, template string, platformService platform.PlatformService, jenkinsScriptData *platformHelper.JenkinsScriptData, instance *jenkinsApi.Jenkins, ) error { templateFilePath := fmt.Sprintf(pathStringFormat, templatesDirectoryPath, template) script, err := platformHelper.ParseTemplate(jenkinsScriptData, templateFilePath, template) if err != nil { return fmt.Errorf("failed to parse template %s: %w", template, err) } jenkinsScriptName := strings.Split(template, ".")[0] configMapName := fmt.Sprintf(configMapStringFormat, instance.Name, jenkinsScriptName) configMapData := map[string]string{consts.JenkinsDefaultScriptConfigMapKey: script.String()} isUpdated, err := platformService.CreateConfigMapWithUpdate(instance, configMapName, configMapData) if err != nil { return fmt.Errorf("failed to create config map: %w", err) } if _, err = platformService.CreateJenkinsScript(instance.Namespace, configMapName, isUpdated); err != nil { return fmt.Errorf("failed to create jenkins script: %w", err) } return nil } func (j JenkinsServiceImpl) createJobProvisions(jobPath string, instance *jenkinsApi.Jenkins) error { jobProvisionsDirectoryPath, err := platformHelper.CreatePathToTemplateDirectory(jobPath) if err != nil { return fmt.Errorf("failed to create path to template directory: %w", err) } configMapName := strings.ReplaceAll(fmt.Sprintf(configMapStringFormat, instance.Name, jobPath), "/", "-") configMapKey := consts.JenkinsDefaultScriptConfigMapKey env, err := helperController.GetPlatformTypeEnv() if err != nil { return fmt.Errorf("failed to get platform type env: %w", err) } path := filepath.FromSlash(fmt.Sprintf(pathStringFormat, jobProvisionsDirectoryPath, env)) if err := j.createScript(instance, configMapName, configMapKey, path); err != nil { return fmt.Errorf("failed to create script: %w", err) } return nil } // IsDeploymentReady check if DC for Jenkins is ready. func (j JenkinsServiceImpl) IsDeploymentReady(instance *jenkinsApi.Jenkins) (bool, error) { res, err := j.platformService.IsDeploymentReady(instance) if err != nil { return false, fmt.Errorf("failed to check if deployment is ready: %w", err) } return res, nil } func (j JenkinsServiceImpl) createScript(instance *jenkinsApi.Jenkins, configMapName, configMapKey, contextPath string) error { jenkinsScript, err := j.platformService.CreateJenkinsScript(instance.Namespace, configMapName, false) if err != nil { return fmt.Errorf("failed to create jecnkins script: %w", err) } if err = j.platformService.CreateConfigMapFromFileOrDir(instance, configMapName, &configMapKey, contextPath, jenkinsScript); err != nil { return fmt.Errorf("failed to create config-map %v in namespace %v: %w", configMapName, instance.Namespace, err) } return nil } func (j JenkinsServiceImpl) CreateAdminPassword(instance *jenkinsApi.Jenkins) error { secretName := fmt.Sprintf(configMapStringFormat, instance.Name, jenkinsDefaultSpec.JenkinsAdminPasswordSuffix) if err := j.createSecret(instance, secretName, jenkinsDefaultSpec.JenkinsDefaultAdminUser, nil); err != nil { return fmt.Errorf("failed to create admin password secret: %w", err) } if instance.Status.AdminSecretName == "" { _, err := j.setAdminSecretInStatus(instance, secretName) if err != nil { return fmt.Errorf("failed to set admin secret in status: %w", err) } } return nil }