Commit ec68d991 authored by Vineet Reddy Rajula's avatar Vineet Reddy Rajula Committed by Konstantinos Samaras-Tsakiris
Browse files

deploymentCongis -> deployments, createOrUpdate function

parent 3040baa2
......@@ -7,9 +7,9 @@ metadata:
name: manager-role
rules:
- apiGroups:
- apps.openshift.io
- app
resources:
- deploymentconfigs
- deployments
verbs:
- '*'
- apiGroups:
......
......@@ -21,12 +21,12 @@ import (
"fmt"
"github.com/go-logr/logr"
appsv1 "github.com/openshift/api/apps/v1"
buildv1 "github.com/openshift/api/build/v1"
imagev1 "github.com/openshift/api/image/v1"
routev1 "github.com/openshift/api/route/v1"
"github.com/operator-framework/operator-lib/status"
webservicesv1a1 "gitlab.cern.ch/drupal/paas/drupalsite-operator/api/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
......@@ -47,8 +47,7 @@ type DrupalSiteReconciler struct {
// +kubebuilder:rbac:groups=drupal.webservices.cern.ch,resources=drupalsites,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=drupal.webservices.cern.ch,resources=drupalsites/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=drupal.webservices.cern.ch,resources=drupalsites/finalizers,verbs=update
// +kubebuilder:rbac:groups=apps.openshift.io,resources=deploymentconfigs,verbs=*
// +kubebuilder:rbac:groups=app,resources=deployments,verbs=*
// +kubebuilder:rbac:groups=build.openshift.io,resources=buildconfig,verbs=*
// +kubebuilder:rbac:groups=image.openshift.io,resources=imagestream,verbs=*
// +kubebuilder:rbac:groups=route.openshift.io,resources=routes,verbs=*
......@@ -60,7 +59,7 @@ type DrupalSiteReconciler struct {
func (r *DrupalSiteReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&webservicesv1a1.DrupalSite{}).
Owns(&appsv1.DeploymentConfig{}).
Owns(&appsv1.Deployment{}).
Owns(&buildv1.BuildConfig{}).
Owns(&imagev1.ImageStream{}).
Owns(&routev1.Route{}).
......
......@@ -22,24 +22,25 @@ import (
"fmt"
"io/ioutil"
"math/rand"
"strconv"
"strings"
"time"
"github.com/asaskevich/govalidator"
"github.com/go-logr/logr"
appsv1 "github.com/openshift/api/apps/v1"
buildv1 "github.com/openshift/api/build/v1"
imagev1 "github.com/openshift/api/image/v1"
routev1 "github.com/openshift/api/route/v1"
webservicesv1a1 "gitlab.cern.ch/drupal/paas/drupalsite-operator/api/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/pointer"
controllerruntime "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
......@@ -50,6 +51,7 @@ const (
finalizerStr = "controller.drupalsite.webservices.cern.ch"
productionEnvironment = "production"
routerShardLabel = "drupal.cern.ch/router-shard"
adminAnnotation = "drupal.cern.ch/admin-custom-edit"
)
var (
......@@ -213,7 +215,7 @@ func (r *DrupalSiteReconciler) ensureIngressResources(drp *webservicesv1a1.Drupa
// labelsForDrupalSite returns the labels for selecting the resources
// belonging to the given drupalSite CR name.
func labelsForDrupalSite(name string) map[string]string {
return map[string]string{"CRD": "drupalSite", "drupalSite_cr": name}
return map[string]string{"drupalSite": name}
}
// TODO: Translate the `drupalVersion` -> {`PHP_BASE_VERSION`, `NGINX_VERSION`, `COMPOSER_VERSION`}
......@@ -229,7 +231,7 @@ func baseImageReferenceToUse(d *webservicesv1a1.DrupalSite) corev1.ObjectReferen
if len(d.Spec.Environment.ExtraConfigRepo) > 0 {
return corev1.ObjectReference{
Kind: "ImageStreamTag",
Name: imageStreamForDrupalSiteBuilderS2I(d).Name + ":" + d.Spec.DrupalVersion,
Name: "drupal-site-builder-s2i-" + d.Name + ":" + d.Spec.DrupalVersion,
}
}
return corev1.ObjectReference{
......@@ -247,7 +249,7 @@ func triggersForBuildConfigs(d *webservicesv1a1.DrupalSite) buildv1.BuildTrigger
ImageChange: &buildv1.ImageChangeTrigger{
From: &corev1.ObjectReference{
Kind: "ImageStreamTag",
Name: imageStreamForDrupalSiteBuilderS2I(d).Name + ":" + d.Spec.DrupalVersion,
Name: "drupal-site-builder-s2i-" + d.Name + ":" + d.Spec.DrupalVersion,
},
},
}
......@@ -258,498 +260,494 @@ func triggersForBuildConfigs(d *webservicesv1a1.DrupalSite) buildv1.BuildTrigger
}
// imageStreamForDrupalSiteBuilderS2I returns a ImageStream object for Drupal SiteBuilder S2I
func imageStreamForDrupalSiteBuilderS2I(d *webservicesv1a1.DrupalSite) *imagev1.ImageStream {
func imageStreamForDrupalSiteBuilderS2I(currentobject *imagev1.ImageStream, d *webservicesv1a1.DrupalSite) error {
if currentobject.CreationTimestamp.IsZero() {
addOwnerRefToObject(currentobject, asOwner(d))
currentobject.Labels = map[string]string{}
}
if len(currentobject.GetAnnotations()[adminAnnotation]) > 0 {
// Do nothing
return nil
}
ls := labelsForDrupalSite(d.Name)
ls["app"] = "site-builder"
is := createImageStream("drupal-site-builder-s2i-"+d.Name, d.Namespace, ls)
addOwnerRefToObject(is, asOwner(d))
return is
for k, v := range ls {
currentobject.Labels[k] = v
}
currentobject.Spec.LookupPolicy.Local = true
return nil
}
// imageStreamForDrupalSitePHP returns a ImageStream object for Drupal PHP
func imageStreamForDrupalSitePHP(d *webservicesv1a1.DrupalSite) *imagev1.ImageStream {
func imageStreamForDrupalSitePHP(currentobject *imagev1.ImageStream, d *webservicesv1a1.DrupalSite) error {
if currentobject.CreationTimestamp.IsZero() {
addOwnerRefToObject(currentobject, asOwner(d))
}
if currentobject.Labels == nil {
currentobject.Labels = map[string]string{}
}
if len(currentobject.GetAnnotations()[adminAnnotation]) > 0 {
// Do nothing
return nil
}
ls := labelsForDrupalSite(d.Name)
ls["app"] = "php"
is := createImageStream("drupal-php-"+d.Name, d.Namespace, ls)
addOwnerRefToObject(is, asOwner(d))
return is
for k, v := range ls {
currentobject.Labels[k] = v
}
currentobject.Spec.LookupPolicy.Local = true
return nil
}
// imageStreamForDrupalSiteNginx returns a ImageStream object for Drupal Nginx
func imageStreamForDrupalSiteNginx(d *webservicesv1a1.DrupalSite) *imagev1.ImageStream {
func imageStreamForDrupalSiteNginx(currentobject *imagev1.ImageStream, d *webservicesv1a1.DrupalSite) error {
if currentobject.CreationTimestamp.IsZero() {
addOwnerRefToObject(currentobject, asOwner(d))
}
if currentobject.Labels == nil {
currentobject.Labels = map[string]string{}
}
if len(currentobject.GetAnnotations()[adminAnnotation]) > 0 {
// Do nothing
return nil
}
ls := labelsForDrupalSite(d.Name)
ls["app"] = "nginx"
is := createImageStream("drupal-nginx-"+d.Name, d.Namespace, ls)
addOwnerRefToObject(is, asOwner(d))
return is
}
func createImageStream(name, namespace string, labels map[string]string) *imagev1.ImageStream {
return &imagev1.ImageStream{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Labels: labels,
},
Spec: imagev1.ImageStreamSpec{
LookupPolicy: imagev1.ImageLookupPolicy{
Local: true,
},
},
for k, v := range ls {
currentobject.Labels[k] = v
}
currentobject.Spec.LookupPolicy.Local = true
return nil
}
// buildConfigForDrupalSiteBuilderS2I returns a BuildConfig object for Drupal SiteBuilder S2I
func buildConfigForDrupalSiteBuilderS2I(d *webservicesv1a1.DrupalSite) *buildv1.BuildConfig {
func buildConfigForDrupalSiteBuilderS2I(currentobject *buildv1.BuildConfig, d *webservicesv1a1.DrupalSite) error {
if currentobject.CreationTimestamp.IsZero() {
addOwnerRefToObject(currentobject, asOwner(d))
}
if currentobject.Labels == nil {
currentobject.Labels = map[string]string{}
}
if len(currentobject.GetAnnotations()[adminAnnotation]) > 0 {
// Do nothing
return nil
}
ls := labelsForDrupalSite(d.Name)
ls["app"] = "site-builder"
objectName := "drupal-site-builder-s2i-" + d.Name
bc := &buildv1.BuildConfig{
ObjectMeta: metav1.ObjectMeta{
Name: objectName,
Namespace: d.Namespace,
Labels: ls,
},
Spec: buildv1.BuildConfigSpec{
CommonSpec: buildv1.CommonSpec{
CompletionDeadlineSeconds: pointer.Int64Ptr(1200),
Source: buildv1.BuildSource{
Git: &buildv1.GitBuildSource{
// TODO: support branches https://gitlab.cern.ch/drupal/paas/drupalsite-operator/-/issues/28
Ref: "master",
URI: d.Spec.Environment.ExtraConfigRepo,
},
},
Strategy: buildv1.BuildStrategy{
SourceStrategy: &buildv1.SourceBuildStrategy{
From: corev1.ObjectReference{
Kind: "DockerImage",
Name: "gitlab-registry.cern.ch/drupal/paas/drupal-runtime/site-builder-base:" + d.Spec.DrupalVersion,
},
},
for k, v := range ls {
currentobject.Labels[k] = v
}
currentobject.Spec = buildv1.BuildConfigSpec{
CommonSpec: buildv1.CommonSpec{
CompletionDeadlineSeconds: pointer.Int64Ptr(1200),
Source: buildv1.BuildSource{
Git: &buildv1.GitBuildSource{
// TODO: support branches https://gitlab.cern.ch/drupal/paas/drupalsite-operator/-/issues/28
Ref: "master",
URI: d.Spec.Environment.ExtraConfigRepo,
},
Output: buildv1.BuildOutput{
To: &corev1.ObjectReference{
Kind: "ImageStreamTag",
Name: objectName + ":" + d.Spec.DrupalVersion,
},
Strategy: buildv1.BuildStrategy{
SourceStrategy: &buildv1.SourceBuildStrategy{
From: corev1.ObjectReference{
Kind: "DockerImage",
Name: "gitlab-registry.cern.ch/drupal/paas/drupal-runtime/site-builder-base:" + d.Spec.DrupalVersion,
},
},
},
Triggers: []buildv1.BuildTriggerPolicy{
{
Type: buildv1.ConfigChangeBuildTriggerType,
Output: buildv1.BuildOutput{
To: &corev1.ObjectReference{
Kind: "ImageStreamTag",
Name: currentobject.Name + ":" + d.Spec.DrupalVersion,
},
},
},
Triggers: []buildv1.BuildTriggerPolicy{
{
Type: buildv1.ConfigChangeBuildTriggerType,
},
},
}
// Set DrupalSite instance as the owner and controller
// ctrl.SetControllerReference(d, dep, r.Scheme)
// Add owner reference
addOwnerRefToObject(bc, asOwner(d))
return bc
return nil
}
// buildConfigForDrupalSitePHP returns a BuildConfig object for Drupal PHP
func buildConfigForDrupalSitePHP(d *webservicesv1a1.DrupalSite) *buildv1.BuildConfig {
func buildConfigForDrupalSitePHP(currentobject *buildv1.BuildConfig, d *webservicesv1a1.DrupalSite) error {
if currentobject.CreationTimestamp.IsZero() {
addOwnerRefToObject(currentobject, asOwner(d))
}
if currentobject.Labels == nil {
currentobject.Labels = map[string]string{}
}
if len(currentobject.GetAnnotations()[adminAnnotation]) > 0 {
// Do nothing
return nil
}
ls := labelsForDrupalSite(d.Name)
ls["app"] = "php"
objectName := "drupal-php-" + d.Name
bc := &buildv1.BuildConfig{
ObjectMeta: metav1.ObjectMeta{
Name: objectName,
Namespace: d.Namespace,
Labels: ls,
},
Spec: buildv1.BuildConfigSpec{
CommonSpec: buildv1.CommonSpec{
CompletionDeadlineSeconds: pointer.Int64Ptr(1200),
Source: buildv1.BuildSource{
Git: &buildv1.GitBuildSource{
Ref: ImageRecipesRepoRef,
URI: ImageRecipesRepo,
},
ContextDir: "images/php-fpm",
Images: []buildv1.ImageSource{
{
From: baseImageReferenceToUse(d),
Paths: []buildv1.ImageSourcePath{
{
SourcePath: "/app/.",
DestinationDir: "./images/php-fpm/drupal-files/",
},
},
},
},
for k, v := range ls {
currentobject.Labels[k] = v
}
currentobject.Spec = buildv1.BuildConfigSpec{
CommonSpec: buildv1.CommonSpec{
CompletionDeadlineSeconds: pointer.Int64Ptr(1200),
Source: buildv1.BuildSource{
Git: &buildv1.GitBuildSource{
Ref: ImageRecipesRepoRef,
URI: ImageRecipesRepo,
},
Strategy: buildv1.BuildStrategy{
DockerStrategy: &buildv1.DockerBuildStrategy{
BuildArgs: []corev1.EnvVar{
ContextDir: "images/php-fpm",
Images: []buildv1.ImageSource{
{
From: baseImageReferenceToUse(d),
Paths: []buildv1.ImageSourcePath{
{
Name: "DRUPAL_VERSION",
Value: d.Spec.DrupalVersion,
},
},
Env: []corev1.EnvVar{
{
Name: "SITE_BUILDER_DIR",
Value: "drupal-files",
SourcePath: "/app/.",
DestinationDir: "./images/php-fpm/drupal-files/",
},
},
},
},
Output: buildv1.BuildOutput{
To: &corev1.ObjectReference{
Kind: "ImageStreamTag",
Name: objectName + ":" + d.Spec.DrupalVersion,
},
Strategy: buildv1.BuildStrategy{
DockerStrategy: &buildv1.DockerBuildStrategy{
BuildArgs: []corev1.EnvVar{
{
Name: "DRUPAL_VERSION",
Value: d.Spec.DrupalVersion,
},
},
Env: []corev1.EnvVar{
{
Name: "SITE_BUILDER_DIR",
Value: "drupal-files",
},
},
},
},
Triggers: []buildv1.BuildTriggerPolicy{
triggersForBuildConfigs(d),
Output: buildv1.BuildOutput{
To: &corev1.ObjectReference{
Kind: "ImageStreamTag",
Name: currentobject.Name + ":" + d.Spec.DrupalVersion,
},
},
},
Triggers: []buildv1.BuildTriggerPolicy{
triggersForBuildConfigs(d),
},
}
// Set DrupalSite instance as the owner and controller
// ctrl.SetControllerReference(d, dep, r.Scheme)
// Add owner reference
addOwnerRefToObject(bc, asOwner(d))
return bc
return nil
}
// buildConfigForDrupalSiteNginx returns a BuildConfig object for Drupal Nginx
func buildConfigForDrupalSiteNginx(d *webservicesv1a1.DrupalSite) *buildv1.BuildConfig {
func buildConfigForDrupalSiteNginx(currentobject *buildv1.BuildConfig, d *webservicesv1a1.DrupalSite) error {
if currentobject.CreationTimestamp.IsZero() {
addOwnerRefToObject(currentobject, asOwner(d))
}
if currentobject.Labels == nil {
currentobject.Labels = map[string]string{}
}
if len(currentobject.GetAnnotations()[adminAnnotation]) > 0 {
// Do nothing
return nil
}
ls := labelsForDrupalSite(d.Name)
ls["app"] = "nginx"
objectName := "drupal-nginx-" + d.Name
bc := &buildv1.BuildConfig{
ObjectMeta: metav1.ObjectMeta{
Name: objectName,
Namespace: d.Namespace,
Labels: ls,
},
Spec: buildv1.BuildConfigSpec{
CommonSpec: buildv1.CommonSpec{
CompletionDeadlineSeconds: pointer.Int64Ptr(1200),
Source: buildv1.BuildSource{
Git: &buildv1.GitBuildSource{
Ref: ImageRecipesRepoRef,
URI: ImageRecipesRepo,
},
ContextDir: "images/nginx",
Images: []buildv1.ImageSource{
{
From: baseImageReferenceToUse(d),
Paths: []buildv1.ImageSourcePath{
{
SourcePath: "/app/.",
DestinationDir: "./images/nginx/drupal-files/",
},
},
},
},
for k, v := range ls {
currentobject.Labels[k] = v
}
currentobject.Spec = buildv1.BuildConfigSpec{
CommonSpec: buildv1.CommonSpec{
CompletionDeadlineSeconds: pointer.Int64Ptr(1200),
Source: buildv1.BuildSource{
Git: &buildv1.GitBuildSource{
Ref: ImageRecipesRepoRef,
URI: ImageRecipesRepo,
},
Strategy: buildv1.BuildStrategy{
DockerStrategy: &buildv1.DockerBuildStrategy{
BuildArgs: []corev1.EnvVar{
{
Name: "DRUPAL_VERSION",
Value: d.Spec.DrupalVersion,
},
},
Env: []corev1.EnvVar{
ContextDir: "images/nginx",
Images: []buildv1.ImageSource{
{
From: baseImageReferenceToUse(d),
Paths: []buildv1.ImageSourcePath{
{
Name: "SITE_BUILDER_DIR",
Value: "drupal-files",
SourcePath: "/app/.",
DestinationDir: "./images/nginx/drupal-files/",
},
},
},
},
Output: buildv1.BuildOutput{
To: &corev1.ObjectReference{
Kind: "ImageStreamTag",
Name: objectName + ":" + d.Spec.DrupalVersion,
},
Strategy: buildv1.BuildStrategy{
DockerStrategy: &buildv1.DockerBuildStrategy{
BuildArgs: []corev1.EnvVar{
{
Name: "DRUPAL_VERSION",
Value: d.Spec.DrupalVersion,
},
},
Env: []corev1.EnvVar{
{
Name: "SITE_BUILDER_DIR",
Value: "drupal-files",
},
},
},
},
Triggers: []buildv1.BuildTriggerPolicy{
triggersForBuildConfigs(d),
Output: buildv1.BuildOutput{
To: &corev1.ObjectReference{
Kind: "ImageStreamTag",
Name: currentobject.Name + ":" + d.Spec.DrupalVersion,
},
},
},
Triggers: []buildv1.BuildTriggerPolicy{
triggersForBuildConfigs(d),
},
}
// Set DrupalSite instance as the owner and controller
// ctrl.SetControllerReference(d, dep, r.Scheme)
// Add owner reference
addOwnerRefToObject(bc, asOwner(d))
return bc
return nil
}
// deploymentConfigForDrupalSiteMySQL returns a DeploymentConfig object for MySQL
func deploymentConfigForDrupalSiteMySQL(d *webservicesv1a1.DrupalSite) *appsv1.DeploymentConfig {
// deploymentForDrupalSiteMySQL returns a Deployment object for MySQL
func deploymentForDrupalSiteMySQL(currentobject *appsv1.Deployment, d *webservicesv1a1.DrupalSite) error {
if currentobject.CreationTimestamp.IsZero() {
addOwnerRefToObject(currentobject, asOwner(d))
currentobject.Spec.Template.ObjectMeta.Annotations = map[string]string{
"mysql-configmap-version": "1",
}
}
if currentobject.Labels == nil {
currentobject.Labels = map[string]string{}
}
if len(currentobject.GetAnnotations()[adminAnnotation]) > 0 {
// Do nothing
return nil
}
ls := labelsForDrupalSite(d.Name)
ls["app"] = "mysql"
objectName := "drupal-mysql-" + d.Name
dep := &appsv1.DeploymentConfig{
ObjectMeta: metav1.ObjectMeta{
Name: objectName,
Namespace: d.Namespace,
},
Spec: appsv1.DeploymentConfigSpec{
Replicas: 1,
Selector: ls,
Template: &corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: ls,
for k, v := range ls {
currentobject.Labels[k] = v
}
currentobject.Spec.Replicas = pointer.Int32Ptr(1)
currentobject.Spec.Selector = &metav1.LabelSelector{
MatchLabels: ls,
}
currentobject.Spec.Template.ObjectMeta.Labels = ls
currentobject.Spec.Template.Spec = corev1.PodSpec{
Containers: []corev1.Container{{
Image: "mysql:5.7",
Name: "mysql",
ImagePullPolicy: "IfNotPresent",
Ports: []corev1.ContainerPort{{
ContainerPort: 3306,
Name: "mysql",
Protocol: "TCP",
}},
Env: []corev1.EnvVar{
{
Name: "MYSQL_DATABASE",
Value: "drupal",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{{
Image: "mysql:5.7",
Name: "mysql",
ImagePullPolicy: "IfNotPresent",
Ports: []corev1.ContainerPort{{
ContainerPort: 3306,
Name: "mysql",
Protocol: "TCP",
}},
Env: []corev1.EnvVar{
{
Name: "MYSQL_DATABASE",
Value: "drupal",
},
{
Name: "MYSQL_ROOT_PASSWORD",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
Key: "DB_PASSWORD",
LocalObjectReference: corev1.LocalObjectReference{
Name: "drupal-mysql-secret",
},
},
},