Skip to content

Commit

Permalink
Intermediate Commit for transition from Pod to Deployment based Jenki…
Browse files Browse the repository at this point in the history
…ns Controller

Allows for using the annotation jenkins.io/use-deployment
and setting the value to true makes the operator use a
Deployment instead of Pod for serving Jenkins.

This is part of a temporary feature and has to be committed to avoid bigger PRs.
  • Loading branch information
waveywaves committed May 14, 2020
1 parent 2dea712 commit 4e52eb3
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 30 deletions.
2 changes: 2 additions & 0 deletions pkg/apis/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package apis
import (
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
routev1 "github.com/openshift/api/route/v1"
appsv1 "k8s.io/api/apps/v1"

"k8s.io/apimachinery/pkg/runtime"
)
Expand All @@ -19,4 +20,5 @@ func init() {
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
AddToSchemes = append(AddToSchemes, v1alpha2.SchemeBuilder.AddToScheme)
AddToSchemes = append(AddToSchemes, routev1.AddToScheme)
AddToSchemes = append(AddToSchemes, appsv1.AddToScheme)
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error
backupNumber = jenkins.Status.LastBackup
}
bar.logger.Info(fmt.Sprintf("Restoring backup '%d'", backupNumber))
podName := resources.GetJenkinsMasterPodName(*jenkins)
podName := resources.GetJenkinsMasterPodName(jenkins)
command := jenkins.Spec.Restore.Action.Exec.Command
command = append(command, fmt.Sprintf("%d", backupNumber))
_, _, err := bar.Exec(podName, jenkins.Spec.Restore.ContainerName, command)
Expand Down Expand Up @@ -170,7 +170,7 @@ func (bar *BackupAndRestore) Backup(setBackupDoneBeforePodDeletion bool) error {
}
backupNumber := jenkins.Status.PendingBackup
bar.logger.Info(fmt.Sprintf("Performing backup '%d'", backupNumber))
podName := resources.GetJenkinsMasterPodName(*jenkins)
podName := resources.GetJenkinsMasterPodName(jenkins)
command := jenkins.Spec.Backup.Action.Exec.Command
command = append(command, fmt.Sprintf("%d", backupNumber))
_, _, err := bar.Exec(podName, jenkins.Spec.Backup.ContainerName, command)
Expand Down
56 changes: 56 additions & 0 deletions pkg/controller/jenkins/configuration/base/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package base

import (
"context"
"fmt"

"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications/event"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/notifications/reason"
"github.com/jenkinsci/kubernetes-operator/version"
stackerr "github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsDeployment(meta metav1.ObjectMeta) (reconcile.Result, error) {
userAndPasswordHash, err := r.calculateUserAndPasswordHash()
if err != nil {
return reconcile.Result{}, err
}

jenkinsDeployment, err := r.GetJenkinsDeployment()
if apierrors.IsNotFound(err) {
jenkinsDeployment = resources.NewJenkinsDeployment(meta, r.Configuration.Jenkins)
*r.Notifications <- event.Event{
Jenkins: *r.Configuration.Jenkins,
Phase: event.PhaseBase,
Level: v1alpha2.NotificationLevelInfo,
Reason: reason.NewPodCreation(reason.OperatorSource, []string{"Creating a Jenkins Deployment"}),
}

r.logger.Info(fmt.Sprintf("Creating a new Jenkins Deployment %s/%s", jenkinsDeployment.Namespace, jenkinsDeployment.Name))
err := r.CreateResource(jenkinsDeployment)
if err != nil {
return reconcile.Result{}, stackerr.WithStack(err)
}

now := metav1.Now()
r.Configuration.Jenkins.Status = v1alpha2.JenkinsStatus{
OperatorVersion: version.Version,
ProvisionStartTime: &now,
LastBackup: r.Configuration.Jenkins.Status.LastBackup,
PendingBackup: r.Configuration.Jenkins.Status.LastBackup,
UserAndPasswordHash: userAndPasswordHash,
}
return reconcile.Result{Requeue: true}, r.Client.Update(context.TODO(), r.Configuration.Jenkins)
} else if err != nil && !apierrors.IsNotFound(err) {
return reconcile.Result{}, stackerr.WithStack(err)
}

// TODO (waveywaves): replace with a cleaner solution
_ = jenkinsDeployment // This is to escape the variable is never used golint err
return reconcile.Result{}, nil
}
29 changes: 26 additions & 3 deletions pkg/controller/jenkins/configuration/base/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const (
fetchAllPlugins = 1
)

// ReconcileJenkinsBaseConfiguration defines values required for Jenkins base configuration
// ReconcileJenkinsBaseConfiguration defines values required for Jenkins base configuration.
type ReconcileJenkinsBaseConfiguration struct {
configuration.Configuration
logger logr.Logger
Expand All @@ -47,16 +47,30 @@ func New(config configuration.Configuration, jenkinsAPIConnectionSettings jenkin
}
}

// Reconcile takes care of base configuration
// Reconcile takes care of base configuration.
func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenkinsclient.Jenkins, error) {
metaObject := resources.NewResourceObjectMeta(r.Configuration.Jenkins)

// Create Necessary Resources
err := r.ensureResourcesRequiredForJenkinsPod(metaObject)
if err != nil {
return reconcile.Result{}, nil, err
}
r.logger.V(log.VDebug).Info("Kubernetes resources are present")

if useDeploymentForJenkinsMaster(r.Configuration.Jenkins) {
result, err := r.ensureJenkinsDeployment(metaObject)
if err != nil {
return reconcile.Result{}, nil, err
}
if result.Requeue {
return result, nil, nil
}
r.logger.V(log.VDebug).Info("Jenkins Deployment is present")

return result, nil, err
}

result, err := r.ensureJenkinsMasterPod(metaObject)
if err != nil {
return reconcile.Result{}, nil, err
Expand Down Expand Up @@ -110,6 +124,15 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenki
return result, jenkinsClient, err
}

func useDeploymentForJenkinsMaster(jenkins *v1alpha2.Jenkins) bool {
if val, ok := jenkins.Annotations["jenkins.io/use-deployment"]; ok {
if val == "true" {
return true
}
}
return false
}

func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod(metaObject metav1.ObjectMeta) error {
if err := r.createOperatorCredentialsSecret(metaObject); err != nil {
return err
Expand Down Expand Up @@ -245,7 +268,7 @@ func compareEnv(expected, actual []corev1.EnvVar) bool {
return reflect.DeepEqual(expected, actualEnv)
}

// CompareContainerVolumeMounts returns true if two containers volume mounts are the same
// CompareContainerVolumeMounts returns true if two containers volume mounts are the same.
func CompareContainerVolumeMounts(expected corev1.Container, actual corev1.Container) bool {
var withoutServiceAccount []corev1.VolumeMount
for _, volumeMount := range actual.VolumeMounts {
Expand Down
59 changes: 59 additions & 0 deletions pkg/controller/jenkins/configuration/base/resources/deployment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package resources

import (
"fmt"

"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
)

// NewJenkinsMasterPod builds Jenkins Master Kubernetes Pod resource.
func NewJenkinsDeployment(objectMeta metav1.ObjectMeta, jenkins *v1alpha2.Jenkins) *appsv1.Deployment {
serviceAccountName := objectMeta.Name
objectMeta.Annotations = jenkins.Spec.Master.Annotations
objectMeta.Name = GetJenkinsDeploymentName(jenkins)
selector := &metav1.LabelSelector{MatchLabels: objectMeta.Labels}
return &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: objectMeta.Name,
Namespace: objectMeta.Namespace,
Labels: objectMeta.Labels,
OwnerReferences: []metav1.OwnerReference{
{
BlockOwnerDeletion: pointer.BoolPtr(true),
Controller: pointer.BoolPtr(true),
Kind: jenkins.Kind,
Name: jenkins.Name,
APIVersion: jenkins.APIVersion,
UID: jenkins.UID,
},
},
},
Spec: appsv1.DeploymentSpec{
Replicas: pointer.Int32Ptr(1),
Strategy: appsv1.DeploymentStrategy{Type: appsv1.RollingUpdateDeploymentStrategyType},
Template: corev1.PodTemplateSpec{
ObjectMeta: objectMeta,
Spec: corev1.PodSpec{
ServiceAccountName: serviceAccountName,
NodeSelector: jenkins.Spec.Master.NodeSelector,
Containers: newContainers(jenkins),
Volumes: append(GetJenkinsMasterPodBaseVolumes(jenkins), jenkins.Spec.Master.Volumes...),
SecurityContext: jenkins.Spec.Master.SecurityContext,
ImagePullSecrets: jenkins.Spec.Master.ImagePullSecrets,
Tolerations: jenkins.Spec.Master.Tolerations,
PriorityClassName: jenkins.Spec.Master.PriorityClassName,
},
},
Selector: selector,
},
}
}

// GetJenkinsMasterPodName returns Jenkins pod name for given CR
func GetJenkinsDeploymentName(jenkins *v1alpha2.Jenkins) string {
return fmt.Sprintf("jenkins-%s", jenkins.Name)
}
4 changes: 2 additions & 2 deletions pkg/controller/jenkins/configuration/base/resources/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func newContainers(jenkins *v1alpha2.Jenkins) (containers []corev1.Container) {
}

// GetJenkinsMasterPodName returns Jenkins pod name for given CR
func GetJenkinsMasterPodName(jenkins v1alpha2.Jenkins) string {
func GetJenkinsMasterPodName(jenkins *v1alpha2.Jenkins) string {
return fmt.Sprintf("jenkins-%s", jenkins.Name)
}

Expand All @@ -313,7 +313,7 @@ func GetJenkinsMasterPodLabels(jenkins v1alpha2.Jenkins) map[string]string {
func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha2.Jenkins) *corev1.Pod {
serviceAccountName := objectMeta.Name
objectMeta.Annotations = jenkins.Spec.Master.Annotations
objectMeta.Name = GetJenkinsMasterPodName(*jenkins)
objectMeta.Name = GetJenkinsMasterPodName(jenkins)
objectMeta.Labels = GetJenkinsMasterPodLabels(*jenkins)

return &corev1.Pod{
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/jenkins/configuration/base/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ func TestValidateConfigMapVolume(t *testing.T) {

baseReconcileLoop := New(configuration.Configuration{
Jenkins: &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Name: "example"}},
Client: fakeClient,
Client: fakeClient,
}, client.JenkinsAPIConnectionSettings{})

got, err := baseReconcileLoop.validateConfigMapVolume(volume)
Expand Down Expand Up @@ -652,7 +652,7 @@ func TestValidateSecretVolume(t *testing.T) {
fakeClient := fake.NewFakeClient()
baseReconcileLoop := New(configuration.Configuration{
Jenkins: &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Name: "example"}},
Client: fakeClient,
Client: fakeClient,
}, client.JenkinsAPIConnectionSettings{})

got, err := baseReconcileLoop.validateSecretVolume(volume)
Expand Down
Loading

0 comments on commit 4e52eb3

Please sign in to comment.