diff --git a/Makefile b/Makefile index 6a47b4c9..163bfbfd 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,9 @@ IMAGE_ORG_BASE ?= quay.io/project-codeflare # codeflare.dev/codeflare-operator-bundle:$VERSION and codeflare.dev/codeflare-operator-catalog:$VERSION. IMAGE_TAG_BASE ?= $(IMAGE_ORG_BASE)/codeflare-operator +# MCAD_IMAGE defines the default container image for the MCAD controller +MCAD_IMAGE ?= $(IMAGE_ORG_BASE)/mcad-controller:$(MCAD_REF) + # INSTASCALE_IMAGE defines the default container image for the InstaScale controller INSTASCALE_IMAGE ?= $(IMAGE_ORG_BASE)/instascale-controller:$(INSTASCALE_VERSION) @@ -117,6 +120,7 @@ defaults: @echo "// ***********************" >> $(DEFAULTS_FILE) @echo "" >> $(DEFAULTS_FILE) @echo "const (" >> $(DEFAULTS_FILE) + @echo " MCADImage = \"$(MCAD_IMAGE)\"" >> $(DEFAULTS_FILE) @echo " InstaScaleImage = \"$(INSTASCALE_IMAGE)\"" >> $(DEFAULTS_FILE) @echo "" >> $(DEFAULTS_FILE) @echo ")" >> $(DEFAULTS_FILE) diff --git a/api/codeflare/v1alpha1/mcad_types.go b/api/codeflare/v1alpha1/mcad_types.go index 217791a2..dc22291f 100644 --- a/api/codeflare/v1alpha1/mcad_types.go +++ b/api/codeflare/v1alpha1/mcad_types.go @@ -53,6 +53,17 @@ type MCADSpec struct { // ControllerResources defines the cpu and memory resource requirements for the MCAD Controller // +kubebuilder:default={} ControllerResources v1.ResourceRequirements `json:"controllerResources,omitempty" protobuf:"bytes,8,opt"` + + // The container image for the MCAD controller deployment. + // If specified, the provided container image must be compatible with the running CodeFlare operator. + // Using an incompatible, or unrelated container image, will result in an undefined behavior. + // A CodeFlare operator upgrade will not upgrade the MCAD controller, that'll keep running this + // specified container image. + // If not specified, the latest version compatible with the running CodeFlare operator is used. + // A CodeFlare operator upgrade may upgrade the MCAD controller to a newer container image. + // + // +optional + ControllerImage string `json:"controllerImage,omitempty"` } // MCADStatus defines the observed state of MCAD diff --git a/config/crd/bases/codeflare.codeflare.dev_mcads.yaml b/config/crd/bases/codeflare.codeflare.dev_mcads.yaml index fdb41834..8172df33 100644 --- a/config/crd/bases/codeflare.codeflare.dev_mcads.yaml +++ b/config/crd/bases/codeflare.codeflare.dev_mcads.yaml @@ -39,6 +39,17 @@ spec: description: AgentConfigs determine paths to agent config file:deploymentName separated by commas(,). type: string + controllerImage: + description: The container image for the MCAD controller deployment. + If specified, the provided container image must be compatible with + the running CodeFlare operator. Using an incompatible, or unrelated + container image, will result in an undefined behavior. A CodeFlare + operator upgrade will not upgrade the MCAD controller, that'll keep + running this specified container image. If not specified, the latest + version compatible with the running CodeFlare operator is used. + A CodeFlare operator upgrade may upgrade the MCAD controller to + a newer container image. + type: string controllerResources: description: ControllerResources defines the cpu and memory resource requirements for the MCAD Controller diff --git a/config/internal/mcad/deployment.yaml.tmpl b/config/internal/mcad/deployment.yaml.tmpl index 7f6ebfa8..810b6c13 100644 --- a/config/internal/mcad/deployment.yaml.tmpl +++ b/config/internal/mcad/deployment.yaml.tmpl @@ -19,13 +19,13 @@ spec: spec: containers: - name: mcad-controller - args: [ "--v", "4", "--logtostderr"] + args: ["--v", "4", "--logtostderr"] command: - mcad-controller envFrom: - configMapRef: name: mcad-{{.Name}}-config - image: 'quay.io/project-codeflare/mcad-controller:release-v1.31.0' + image: {{.ControllerImage}} imagePullPolicy: Always ports: - name: https diff --git a/controllers/defaults.go b/controllers/defaults.go index 3f3fe49f..d3cac3d0 100644 --- a/controllers/defaults.go +++ b/controllers/defaults.go @@ -5,5 +5,6 @@ package controllers // *********************** const ( + MCADImage = "quay.io/project-codeflare/mcad-controller:release-v1.31.0" InstaScaleImage = "quay.io/project-codeflare/instascale-controller:v0.0.4" ) diff --git a/controllers/mcad_controller.go b/controllers/mcad_controller.go index 1dfe8b9b..f21023cd 100644 --- a/controllers/mcad_controller.go +++ b/controllers/mcad_controller.go @@ -151,11 +151,7 @@ func (r *MCADReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. mcadCustomResource.APIVersion, mcadCustomResource.Kind = gvk.Version, gvk.Kind } - err = params.ExtractParams(mcadCustomResource) - if err != nil { - log.Error(err, "Unable to parse MCAD custom resource") - return ctrl.Result{}, err - } + params.ExtractParams(mcadCustomResource) if mcadCustomResource.ObjectMeta.DeletionTimestamp.IsZero() { if !controllerutil.ContainsFinalizer(mcadCustomResource, finalizerName) { @@ -189,7 +185,7 @@ func (r *MCADReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl. if err != nil { return ctrl.Result{}, err } - err = r.Client.Status().Update(context.Background(), mcadCustomResource) + err = r.Client.Status().Update(ctx, mcadCustomResource) if err != nil { return ctrl.Result{}, err } diff --git a/controllers/mcad_controller_test.go b/controllers/mcad_controller_test.go index ff1189c4..35e892c3 100644 --- a/controllers/mcad_controller_test.go +++ b/controllers/mcad_controller_test.go @@ -21,6 +21,8 @@ const ( mcadConfigMap2 = "./testdata/mcad_test_results/case_2/configmap.yaml" mcadService2 = "./testdata/mcad_test_results/case_2/service.yaml" mcadServiceAccount2 = "./testdata/mcad_test_results/case_2/serviceaccount.yaml" + mcadCRCase3 = "./testdata/mcad_test_cases/case_3.yaml" + mcadDeployment3 = "./testdata/mcad_test_results/case_3/deployment.yaml" ) func deployMCAD(ctx context.Context, path string, opts mf.Option) { @@ -54,4 +56,12 @@ var _ = Describe("The MCAD Controller", func() { compareServices(mcadService2, opts) }) }) + + Context("In a namespace, when a MCAD resource with a custom image is deployed", func() { + + It("It should create a deployment", func() { + deployMCAD(ctx, mcadCRCase3, opts) + compareDeployments(mcadDeployment3, opts) + }) + }) }) diff --git a/controllers/mcad_params.go b/controllers/mcad_params.go index cedbdecc..5992bede 100644 --- a/controllers/mcad_params.go +++ b/controllers/mcad_params.go @@ -33,16 +33,17 @@ type MCADParams struct { QuotaRestURL string PodCreationTimeout int ControllerResources ControllerResources + ControllerImage string } -// type ControllerResources struct { -// v1.ResourceRequirements -// } - // ExtractParams is currently a straight-up copy. We can add in more complex validation at a later date -func (p *MCADParams) ExtractParams(mcad *mcadv1alpha1.MCAD) error { +func (p *MCADParams) ExtractParams(mcad *mcadv1alpha1.MCAD) { p.Name = mcad.Name p.Namespace = mcad.Namespace + p.ControllerImage = mcad.Spec.ControllerImage + if p.ControllerImage == "" { + p.ControllerImage = MCADImage + } p.Owner = mcad p.EnableMonitoring = mcad.Spec.EnableMonitoring p.MultiCluster = mcad.Spec.MultiCluster @@ -52,6 +53,4 @@ func (p *MCADParams) ExtractParams(mcad *mcadv1alpha1.MCAD) error { p.QuotaRestURL = mcad.Spec.QuotaRestURL p.PodCreationTimeout = mcad.Spec.PodCreationTimeout p.ControllerResources = ControllerResources{mcad.Spec.ControllerResources} - - return nil } diff --git a/controllers/testdata/mcad_test_cases/case_3.yaml b/controllers/testdata/mcad_test_cases/case_3.yaml new file mode 100644 index 00000000..c048e2e8 --- /dev/null +++ b/controllers/testdata/mcad_test_cases/case_3.yaml @@ -0,0 +1,6 @@ +apiVersion: codeflare.codeflare.dev/v1alpha1 +kind: MCAD +metadata: + name: custom-image +spec: + controllerImage: quay.io/project-codeflare/mcad-controller:custom diff --git a/controllers/testdata/mcad_test_results/case_3/deployment.yaml b/controllers/testdata/mcad_test_results/case_3/deployment.yaml new file mode 100644 index 00000000..5efa0df2 --- /dev/null +++ b/controllers/testdata/mcad_test_results/case_3/deployment.yaml @@ -0,0 +1,45 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: mcad-controller-custom-image + namespace: default + labels: + app: mcad-custom-image + component: multi-cluster-application-dispatcher +spec: + replicas: 1 + selector: + matchLabels: + app: mcad-custom-image + template: + metadata: + labels: + app: mcad-custom-image + component: multi-cluster-application-dispatcher + spec: + containers: + - name: mcad-controller + args: ["--v", "4", "--logtostderr"] + command: + - mcad-controller + envFrom: + - configMapRef: + name: mcad-custom-image-config + image: quay.io/project-codeflare/mcad-controller:custom + imagePullPolicy: Always + ports: + - name: https + containerPort: 6443 + protocol: TCP + - name: http + containerPort: 8080 + protocol: TCP + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - name: temp-vol + mountPath: /tmp + serviceAccountName: mcad-controller-custom-image + volumes: + - name: temp-vol + emptyDir: {}