From f9ad157c8be4926b573dcaf55f830eb1a936cc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20S=C4=99k?= Date: Sun, 9 Jun 2019 14:56:31 +0200 Subject: [PATCH] #9 Allow mount pvc in Jenkins pod --- deploy/role.yaml | 154 +++++++++--------- .../jenkins/configuration/base/reconcile.go | 34 +++- .../jenkins/configuration/base/validate.go | 29 +++- 3 files changed, 136 insertions(+), 81 deletions(-) diff --git a/deploy/role.yaml b/deploy/role.yaml index f9dfaa35..cffe99ce 100644 --- a/deploy/role.yaml +++ b/deploy/role.yaml @@ -4,77 +4,83 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: jenkins-operator rules: -- apiGroups: - - "" - resources: - - services - - configmaps - - secrets - verbs: - - get - - create - - update - - list - - watch -- apiGroups: - - "extensions" - resources: - - ingresses - verbs: - - create - - update -- apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create -- apiGroups: - - rbac.authorization.k8s.io - resources: - - roles - - rolebindings - verbs: - - create - - update -- apiGroups: - - "" - resources: - - pods/portforward - verbs: - - create -- apiGroups: - - "" - resources: - - pods/log - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - pods - - pods/exec - verbs: - - "*" -- apiGroups: - - "" - resources: - - events - verbs: - - create -- apiGroups: - - apps - resourceNames: - - jenkins-operator - resources: - - deployments/finalizers - verbs: - - update -- apiGroups: - - jenkins.io - resources: - - '*' - verbs: - - '*' + - apiGroups: + - "" + resources: + - services + - configmaps + - secrets + verbs: + - get + - create + - update + - list + - watch + - apiGroups: + - "extensions" + resources: + - ingresses + verbs: + - create + - update + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + - rolebindings + verbs: + - create + - update + - apiGroups: + - "" + resources: + - pods/portforward + verbs: + - create + - apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - "*" + - apiGroups: + - "" + resources: + - events + verbs: + - create + - apiGroups: + - apps + resourceNames: + - jenkins-operator + resources: + - deployments/finalizers + verbs: + - update + - apiGroups: + - jenkins.io + resources: + - '*' + verbs: + - '*' + - apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - get \ No newline at end of file diff --git a/pkg/controller/jenkins/configuration/base/reconcile.go b/pkg/controller/jenkins/configuration/base/reconcile.go index ba3201f8..15b824fa 100644 --- a/pkg/controller/jenkins/configuration/base/reconcile.go +++ b/pkg/controller/jenkins/configuration/base/reconcile.go @@ -63,8 +63,18 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenki if err != nil { return reconcile.Result{}, nil, err } + r.logger.V(log.VDebug).Info("Kubernetes resources are present") - result, err := r.ensureJenkinsMasterPod(metaObject) + result, err := r.waitForVolumes() + if err != nil { + return reconcile.Result{}, nil, err + } + if result.Requeue { + return result, nil, nil + } + r.logger.V(log.VDebug).Info("Jenkins master pod volumes are ready") + + result, err = r.ensureJenkinsMasterPod(metaObject) if err != nil { return reconcile.Result{}, nil, err } @@ -149,6 +159,26 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod return nil } +func (r *ReconcileJenkinsBaseConfiguration) waitForVolumes() (reconcile.Result, error) { + for _, volume := range r.jenkins.Spec.Master.Volumes { + if volume.PersistentVolumeClaim != nil { + pvc := &corev1.PersistentVolumeClaim{} + err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: volume.PersistentVolumeClaim.ClaimName, Namespace: r.jenkins.ObjectMeta.Namespace}, pvc) + if err != nil { + return reconcile.Result{}, err + } + + if pvc.Status.Phase != corev1.ClaimBound { + r.logger.V(log.VWarn).Info(fmt.Sprintf("PersistentVolumeClaim '%s' have invalid state '%s' - required '%s', volume '%v'", + volume.PersistentVolumeClaim.ClaimName, pvc.Status.Phase, corev1.ClaimBound, volume)) + return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, nil + } + } + } + + return reconcile.Result{}, nil +} + func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsclient.Jenkins, basePlugins map[string][]plugins.Plugin) (bool, error) { allPluginsInJenkins, err := jenkinsClient.GetPlugins(fetchAllPlugins) if err != nil { @@ -427,7 +457,7 @@ func (r *ReconcileJenkinsBaseConfiguration) isRecreatePodNeeded(currentJenkinsMa } if !r.compareVolumes(currentJenkinsMasterPod) { - r.logger.Info(fmt.Sprintf("Jenkins pod volumes have changed, actual '%+v' required '%+v', recreating pod", + r.logger.Info(fmt.Sprintf("Jenkins pod volumes have changed, actual '%v' required '%v', recreating pod", currentJenkinsMasterPod.Spec.Volumes, r.jenkins.Spec.Master.Volumes)) return true } diff --git a/pkg/controller/jenkins/configuration/base/validate.go b/pkg/controller/jenkins/configuration/base/validate.go index a0eb65a9..2208253f 100644 --- a/pkg/controller/jenkins/configuration/base/validate.go +++ b/pkg/controller/jenkins/configuration/base/validate.go @@ -69,15 +69,34 @@ func (r *ReconcileJenkinsBaseConfiguration) validateVolumes() (bool, error) { } else if !ok { valid = false } + case volume.PersistentVolumeClaim != nil: + if ok, err := r.validatePersistentVolumeClaim(volume); err != nil { + return false, err + } else if !ok { + valid = false + } default: //TODO add support for rest of volumes valid = false - r.logger.V(log.VWarn).Info(fmt.Sprintf("Unsupported volume '%+v'", volume)) + r.logger.V(log.VWarn).Info(fmt.Sprintf("Unsupported volume '%v'", volume)) } } return valid, nil } +func (r *ReconcileJenkinsBaseConfiguration) validatePersistentVolumeClaim(volume corev1.Volume) (bool, error) { + pvc := &corev1.PersistentVolumeClaim{} + err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: volume.PersistentVolumeClaim.ClaimName, Namespace: r.jenkins.ObjectMeta.Namespace}, pvc) + if err != nil && apierrors.IsNotFound(err) { + r.logger.V(log.VWarn).Info(fmt.Sprintf("PersistentVolumeClaim '%s' not found for volume '%v'", volume.PersistentVolumeClaim.ClaimName, volume)) + return false, nil + } else if err != nil && !apierrors.IsNotFound(err) { + return false, stackerr.WithStack(err) + } + + return true, nil +} + func (r *ReconcileJenkinsBaseConfiguration) validateConfigMapVolume(volume corev1.Volume) (bool, error) { if volume.ConfigMap.Optional != nil && *volume.ConfigMap.Optional { return true, nil @@ -86,7 +105,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateConfigMapVolume(volume corev configMap := &corev1.ConfigMap{} err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: volume.ConfigMap.Name, Namespace: r.jenkins.ObjectMeta.Namespace}, configMap) if err != nil && apierrors.IsNotFound(err) { - r.logger.V(log.VWarn).Info(fmt.Sprintf("ConfigMap '%s' not found for volume '%+v'", volume.ConfigMap.Name, volume)) + r.logger.V(log.VWarn).Info(fmt.Sprintf("ConfigMap '%s' not found for volume '%v'", volume.ConfigMap.Name, volume)) return false, nil } else if err != nil && !apierrors.IsNotFound(err) { return false, stackerr.WithStack(err) @@ -103,7 +122,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateSecretVolume(volume corev1.V secret := &corev1.Secret{} err := r.k8sClient.Get(context.TODO(), types.NamespacedName{Name: volume.Secret.SecretName, Namespace: r.jenkins.ObjectMeta.Namespace}, secret) if err != nil && apierrors.IsNotFound(err) { - r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' not found for volume '%+v'", volume.Secret.SecretName, volume)) + r.logger.V(log.VWarn).Info(fmt.Sprintf("Secret '%s' not found for volume '%v'", volume.Secret.SecretName, volume)) return false, nil } else if err != nil && !apierrors.IsNotFound(err) { return false, stackerr.WithStack(err) @@ -158,7 +177,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateContainerVolumeMounts(contai for _, volumeMount := range container.VolumeMounts { if len(volumeMount.MountPath) == 0 { - logger.V(log.VWarn).Info(fmt.Sprintf("mountPath not set for '%s' volume mount", volumeMount.Name)) + logger.V(log.VWarn).Info(fmt.Sprintf("mountPath not set for '%s' volume mount in container '%s'", volumeMount.Name, container.Name)) valid = false } @@ -170,7 +189,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateContainerVolumeMounts(contai } if !foundVolume { - logger.V(log.VWarn).Info(fmt.Sprintf("Not found volume for '%s' volume mount", volumeMount.Name)) + logger.V(log.VWarn).Info(fmt.Sprintf("Not found volume for '%s' volume mount in container '%s'", volumeMount.Name, container.Name)) valid = false } }