From eaf1b609e369f8e565f5ba76934dfc698d1f4b10 Mon Sep 17 00:00:00 2001 From: Jiaming Hu Date: Thu, 1 Apr 2021 20:59:29 -0400 Subject: [PATCH] feat: Add a new CRD as a simplied OperandRequest --- PROJECT | 16 ++- .../composableoperatorrequest_types.go | 90 ++++++++++++ api/v1alpha1/operandrequest_types.go | 4 +- api/v1alpha1/zz_generated.deepcopy.go | 109 +++++++++++++++ bundle.Dockerfile | 2 +- ...fecycle-manager.clusterserviceversion.yaml | 14 ++ ...or.ibm.com_composableoperatorrequests.yaml | 72 ++++++++++ ...or.ibm.com_composableoperatorrequests.yaml | 70 ++++++++++ config/crd/kustomization.yaml | 4 + .../label_in_composableoperatorrequests.yaml | 8 ++ ...fecycle-manager.clusterserviceversion.yaml | 14 ++ ...composableoperatorrequest_editor_role.yaml | 24 ++++ ...composableoperatorrequest_viewer_role.yaml | 20 +++ .../composableoperatorrequest_controller.go | 128 ++++++++++++++++++ .../operandrequest_controller.go | 2 +- go.mod | 1 - main.go | 8 ++ 17 files changed, 577 insertions(+), 9 deletions(-) create mode 100644 api/v1alpha1/composableoperatorrequest_types.go create mode 100644 bundle/manifests/operator.ibm.com_composableoperatorrequests.yaml create mode 100644 config/crd/bases/operator.ibm.com_composableoperatorrequests.yaml create mode 100644 config/crd/patches/label_in_composableoperatorrequests.yaml create mode 100644 config/rbac/composableoperatorrequest_editor_role.yaml create mode 100644 config/rbac/composableoperatorrequest_viewer_role.yaml create mode 100644 controllers/composableoperatorrequest/composableoperatorrequest_controller.go diff --git a/PROJECT b/PROJECT index f2e4ff25..1050512a 100644 --- a/PROJECT +++ b/PROJECT @@ -3,18 +3,26 @@ layout: go.kubebuilder.io/v3 projectName: operand-deployment-lifecycle-manager repo: github.com/IBM/operand-deployment-lifecycle-manager resources: -- group: operator +- crdVersion: v1 + group: operator kind: OperandRequest version: v1alpha1 -- group: operator +- crdVersion: v1 + group: operator kind: OperandRegistry version: v1alpha1 -- group: operator +- crdVersion: v1 + group: operator kind: OperandConfig version: v1alpha1 -- group: operator +- crdVersion: v1 + group: operator kind: OperandBindInfo version: v1alpha1 +- crdVersion: v1 + group: operator + kind: ComposableOperatorRequest + version: v1alpha1 version: 3-alpha plugins: manifests.sdk.operatorframework.io/v2: {} diff --git a/api/v1alpha1/composableoperatorrequest_types.go b/api/v1alpha1/composableoperatorrequest_types.go new file mode 100644 index 00000000..cd9dd26b --- /dev/null +++ b/api/v1alpha1/composableoperatorrequest_types.go @@ -0,0 +1,90 @@ +// +// Copyright 2021 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// OperatorRequestPhase is the phase of the ComposableOperatorRequest. +type OperatorRequestPhase string + +const ( + ComposableInstalling OperatorRequestPhase = "Installing" + ComposableUpdating OperatorRequestPhase = "Updating" + ComposableFailed OperatorRequestPhase = "Failed" + ComposableInit OperatorRequestPhase = "Initializing" + ComposableRunning OperatorRequestPhase = "Running" + ComposableNone OperatorRequestPhase = "" +) + +// ComposableOperatorRequestSpec defines the desired state of ComposableOperatorRequest +type ComposableOperatorRequestSpec struct { + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Composable Components" + ComposableComponents []Component `json:"composableComponents"` +} + +// Component is used to enable or disable operators. +type Component struct { + // OperatorName the name of the Operator. + OperatorName string `json:"name"` + // Enabled indicates if the operator is enabled + Enabled bool `json:"enabled"` +} + +// ComposableOperatorRequestStatus defines the observed state of ComposableOperatorRequest +type ComposableOperatorRequestStatus struct { + // Phase is the cluster running phase. + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Phase",xDescriptors="urn:alm:descriptor:io.kubernetes.phase" + // +optional + Phase OperatorRequestPhase `json:"phase,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// ComposableOperatorRequest is the Schema for the composableoperatorrequests API +type ComposableOperatorRequest struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ComposableOperatorRequestSpec `json:"spec,omitempty"` + Status ComposableOperatorRequestStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// ComposableOperatorRequestList contains a list of ComposableOperatorRequest +type ComposableOperatorRequestList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ComposableOperatorRequest `json:"items"` +} + +//InitRequestStatus initializes OperandRequest status. +func (r *ComposableOperatorRequest) InitRequestStatus() bool { + isInitialized := true + if r.Status.Phase == "" { + isInitialized = false + r.Status.Phase = ComposableInit + } + return isInitialized +} + +func init() { + SchemeBuilder.Register(&ComposableOperatorRequest{}, &ComposableOperatorRequestList{}) +} diff --git a/api/v1alpha1/operandrequest_types.go b/api/v1alpha1/operandrequest_types.go index da1b1d8d..9e6e19a2 100644 --- a/api/v1alpha1/operandrequest_types.go +++ b/api/v1alpha1/operandrequest_types.go @@ -454,7 +454,7 @@ func (r *OperandRequest) UpdateClusterPhase() { r.SetClusterPhase(clusterPhase) } -// GetRegistryKey Set the default value for Request spec. +// GetRegistryKey sets the default value for Request spec. func (r *OperandRequest) GetRegistryKey(req Request) types.NamespacedName { regName := req.Registry regNs := req.RegistryNamespace @@ -464,7 +464,7 @@ func (r *OperandRequest) GetRegistryKey(req Request) types.NamespacedName { return types.NamespacedName{Namespace: regNs, Name: regName} } -//InitRequestStatus OperandConfig status. +//InitRequestStatus initializes OperandRequest status. func (r *OperandRequest) InitRequestStatus() bool { isInitialized := true if r.Status.Phase == "" { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 0a49cf8d..3335e930 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -24,6 +24,115 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Component) DeepCopyInto(out *Component) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Component. +func (in *Component) DeepCopy() *Component { + if in == nil { + return nil + } + out := new(Component) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComposableOperatorRequest) DeepCopyInto(out *ComposableOperatorRequest) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComposableOperatorRequest. +func (in *ComposableOperatorRequest) DeepCopy() *ComposableOperatorRequest { + if in == nil { + return nil + } + out := new(ComposableOperatorRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ComposableOperatorRequest) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComposableOperatorRequestList) DeepCopyInto(out *ComposableOperatorRequestList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ComposableOperatorRequest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComposableOperatorRequestList. +func (in *ComposableOperatorRequestList) DeepCopy() *ComposableOperatorRequestList { + if in == nil { + return nil + } + out := new(ComposableOperatorRequestList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ComposableOperatorRequestList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComposableOperatorRequestSpec) DeepCopyInto(out *ComposableOperatorRequestSpec) { + *out = *in + if in.ComposableComponents != nil { + in, out := &in.ComposableComponents, &out.ComposableComponents + *out = make([]Component, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComposableOperatorRequestSpec. +func (in *ComposableOperatorRequestSpec) DeepCopy() *ComposableOperatorRequestSpec { + if in == nil { + return nil + } + out := new(ComposableOperatorRequestSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComposableOperatorRequestStatus) DeepCopyInto(out *ComposableOperatorRequestStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComposableOperatorRequestStatus. +func (in *ComposableOperatorRequestStatus) DeepCopy() *ComposableOperatorRequestStatus { + if in == nil { + return nil + } + out := new(ComposableOperatorRequestStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Condition) DeepCopyInto(out *Condition) { *out = *in diff --git a/bundle.Dockerfile b/bundle.Dockerfile index 5f783711..63e2d65d 100644 --- a/bundle.Dockerfile +++ b/bundle.Dockerfile @@ -4,7 +4,7 @@ LABEL operators.operatorframework.io.bundle.mediatype.v1=registry+v1 LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/ LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/ LABEL operators.operatorframework.io.bundle.package.v1=ibm-odlm -LABEL operators.operatorframework.io.bundle.channels.v1=v1,beta +LABEL operators.operatorframework.io.bundle.channels.v1=v3,beta LABEL operators.operatorframework.io.bundle.channel.default.v1=v3 LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.3.0 LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1 diff --git a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 8af56547..5b70930f 100644 --- a/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/bundle/manifests/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -121,6 +121,20 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - description: ComposableOperatorRequest is the Schema for the composableoperatorrequests API + displayName: Composable Operator Request + kind: ComposableOperatorRequest + name: composableoperatorrequests.operator.ibm.com + specDescriptors: + - displayName: Composable Components + path: composableComponents + statusDescriptors: + - description: Phase is the cluster running phase. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 - description: OperandBindInfo is the Schema for the operandbindinfoes API. displayName: OperandBindInfo kind: OperandBindInfo diff --git a/bundle/manifests/operator.ibm.com_composableoperatorrequests.yaml b/bundle/manifests/operator.ibm.com_composableoperatorrequests.yaml new file mode 100644 index 00000000..a2104cc5 --- /dev/null +++ b/bundle/manifests/operator.ibm.com_composableoperatorrequests.yaml @@ -0,0 +1,72 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.0 + creationTimestamp: null + labels: + app.kubernetes.io/instance: operand-deployment-lifecycle-manager + app.kubernetes.io/managed-by: operand-deployment-lifecycle-manager + app.kubernetes.io/name: operand-deployment-lifecycle-manager + name: composableoperatorrequests.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: ComposableOperatorRequest + listKind: ComposableOperatorRequestList + plural: composableoperatorrequests + singular: composableoperatorrequest + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ComposableOperatorRequest is the Schema for the composableoperatorrequests API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ComposableOperatorRequestSpec defines the desired state of ComposableOperatorRequest + properties: + composableComponents: + items: + description: Component is used to enable or disable operators. + properties: + enabled: + description: Enabled indicates if the operator is enabled + type: boolean + name: + description: OperatorName the name of the Operator. + type: string + required: + - enabled + - name + type: object + type: array + required: + - composableComponents + type: object + status: + description: ComposableOperatorRequestStatus defines the observed state of ComposableOperatorRequest + properties: + phase: + description: Phase is the cluster running phase. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/operator.ibm.com_composableoperatorrequests.yaml b/config/crd/bases/operator.ibm.com_composableoperatorrequests.yaml new file mode 100644 index 00000000..4c64076f --- /dev/null +++ b/config/crd/bases/operator.ibm.com_composableoperatorrequests.yaml @@ -0,0 +1,70 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.0 + creationTimestamp: null + name: composableoperatorrequests.operator.ibm.com +spec: + group: operator.ibm.com + names: + kind: ComposableOperatorRequest + listKind: ComposableOperatorRequestList + plural: composableoperatorrequests + singular: composableoperatorrequest + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ComposableOperatorRequest is the Schema for the composableoperatorrequests API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ComposableOperatorRequestSpec defines the desired state of ComposableOperatorRequest + properties: + composableComponents: + items: + description: Component is used to enable or disable operators. + properties: + enabled: + description: Enabled indicates if the operator is enabled + type: boolean + name: + description: OperatorName the name of the Operator. + type: string + required: + - enabled + - name + type: object + type: array + required: + - composableComponents + type: object + status: + description: ComposableOperatorRequestStatus defines the observed state of ComposableOperatorRequest + properties: + phase: + description: Phase is the cluster running phase. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index be422ac7..d9708626 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -6,6 +6,7 @@ resources: - bases/operator.ibm.com_operandconfigs.yaml - bases/operator.ibm.com_operandbindinfos.yaml - bases/operator.ibm.com_operandregistries.yaml +- bases/operator.ibm.com_composableoperatorrequests.yaml # +kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -15,6 +16,7 @@ patchesStrategicMerge: #- patches/webhook_in_operandconfigs.yaml #- patches/webhook_in_operandbindinfoes.yaml #- patches/webhook_in_operandregistries.yaml +#- patches/webhook_in_composableoperatorrequests.yaml # +kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. @@ -23,6 +25,7 @@ patchesStrategicMerge: #- patches/cainjection_in_operandconfigs.yaml #- patches/cainjection_in_operandbindinfoes.yaml #- patches/cainjection_in_operandregistries.yaml +#- patches/cainjection_in_composableoperatorrequests.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # patches here are for adding labels for each CRD @@ -30,6 +33,7 @@ patchesStrategicMerge: - patches/label_in_operandconfigs.yaml - patches/label_in_operandbindinfos.yaml - patches/label_in_operandregistries.yaml +- patches/label_in_composableoperatorrequests.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/label_in_composableoperatorrequests.yaml b/config/crd/patches/label_in_composableoperatorrequests.yaml new file mode 100644 index 00000000..b55fe690 --- /dev/null +++ b/config/crd/patches/label_in_composableoperatorrequests.yaml @@ -0,0 +1,8 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + labels: + app.kubernetes.io/instance: "operand-deployment-lifecycle-manager" + app.kubernetes.io/managed-by: "operand-deployment-lifecycle-manager" + app.kubernetes.io/name: "operand-deployment-lifecycle-manager" + name: composableoperatorrequests.operator.ibm.com diff --git a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml index 38a02cf8..2b620e36 100644 --- a/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml +++ b/config/manifests/bases/operand-deployment-lifecycle-manager.clusterserviceversion.yaml @@ -25,6 +25,20 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - description: ComposableOperatorRequest is the Schema for the composableoperatorrequests API + displayName: Composable Operator Request + kind: ComposableOperatorRequest + name: composableoperatorrequests.operator.ibm.com + specDescriptors: + - displayName: Composable Components + path: composableComponents + statusDescriptors: + - description: Phase is the cluster running phase. + displayName: Phase + path: phase + x-descriptors: + - urn:alm:descriptor:io.kubernetes.phase + version: v1alpha1 - description: OperandBindInfo is the Schema for the operandbindinfoes API. displayName: OperandBindInfo kind: OperandBindInfo diff --git a/config/rbac/composableoperatorrequest_editor_role.yaml b/config/rbac/composableoperatorrequest_editor_role.yaml new file mode 100644 index 00000000..e659c198 --- /dev/null +++ b/config/rbac/composableoperatorrequest_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit composableoperatorrequests. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: composableoperatorrequest-editor-role +rules: +- apiGroups: + - operator.ibm.com + resources: + - composableoperatorrequests + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - operator.ibm.com + resources: + - composableoperatorrequests/status + verbs: + - get diff --git a/config/rbac/composableoperatorrequest_viewer_role.yaml b/config/rbac/composableoperatorrequest_viewer_role.yaml new file mode 100644 index 00000000..48748d72 --- /dev/null +++ b/config/rbac/composableoperatorrequest_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view composableoperatorrequests. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: composableoperatorrequest-viewer-role +rules: +- apiGroups: + - operator.ibm.com + resources: + - composableoperatorrequests + verbs: + - get + - list + - watch +- apiGroups: + - operator.ibm.com + resources: + - composableoperatorrequests/status + verbs: + - get diff --git a/controllers/composableoperatorrequest/composableoperatorrequest_controller.go b/controllers/composableoperatorrequest/composableoperatorrequest_controller.go new file mode 100644 index 00000000..0baad5ba --- /dev/null +++ b/controllers/composableoperatorrequest/composableoperatorrequest_controller.go @@ -0,0 +1,128 @@ +// +// Copyright 2021 IBM Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package composableoperatorrequest + +import ( + "context" + "fmt" + "reflect" + + "github.com/pkg/errors" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/klog" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + deploy "github.com/IBM/operand-deployment-lifecycle-manager/controllers/operator" +) + +// Reconciler reconciles a ComposableOperatorRequest object +type Reconciler struct { + *deploy.ODLMOperator +} + +// Reconcile +func (r *Reconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reconcileErr error) { + + // Creat context for the ComposableOperatorRequest reconciler + ctx := context.Background() + + // Fetch the ComposableOperatorRequest instance + requestInstance := &operatorv1alpha1.ComposableOperatorRequest{} + if err := r.Client.Get(ctx, req.NamespacedName, requestInstance); err != nil { + // Error reading the object - requeue the request. + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + originalInstance := requestInstance.DeepCopy() + + // Always attempt to patch the status after each reconciliation. + defer func() { + if reflect.DeepEqual(originalInstance.Status, requestInstance.Status) { + return + } + if err := r.Client.Status().Patch(ctx, requestInstance, client.MergeFrom(originalInstance)); err != nil { + reconcileErr = utilerrors.NewAggregate([]error{reconcileErr, fmt.Errorf("error while patching OperandRequest.Status: %v", err)}) + } + }() + + // Initialize the status for OperandRequest instance + if !requestInstance.InitRequestStatus() { + requestInstance.Status.Phase = operatorv1alpha1.ComposableInstalling + return ctrl.Result{Requeue: true}, nil + } + + klog.V(1).Infof("Reconciling ComposableOperatorRequest: %s", req.NamespacedName) + + opreq, fn := r.buildOperandRequest(requestInstance) + + result, err := controllerutil.CreateOrUpdate(ctx, r.Client, opreq, fn) + if err != nil { + requestInstance.Status.Phase = operatorv1alpha1.ComposableFailed + return ctrl.Result{}, err + } else if result == controllerutil.OperationResultNone { + return ctrl.Result{Requeue: true}, nil + } + + requestInstance.Status.Phase = operatorv1alpha1.ComposableRunning + klog.V(1).Infof("ComposableOperatorRequest: %s has been reconciled: %s", req.NamespacedName, result) + return ctrl.Result{}, nil +} + +func (r *Reconciler) buildOperandRequest(instance *operatorv1alpha1.ComposableOperatorRequest) (*operatorv1alpha1.OperandRequest, controllerutil.MutateFn) { + opName := instance.Name + opNs := instance.Namespace + opreq := &operatorv1alpha1.OperandRequest{} + opreq.SetName(opName) + opreq.SetNamespace(opNs) + + fn := func() error { + opreq.Spec = operatorv1alpha1.OperandRequestSpec{ + Requests: []operatorv1alpha1.Request{ + { + Description: "It is a request created from ComposableOperatorRequest " + opNs + "/" + opName, + Registry: opName, + RegistryNamespace: opNs, + }, + }, + } + + for _, op := range instance.Spec.ComposableComponents { + if op.Enabled { + opreq.Spec.Requests[0].Operands = append(opreq.Spec.Requests[0].Operands, operatorv1alpha1.Operand{Name: op.OperatorName}) + } + } + + // Set the ComposableOperatorRequest as the controller of the OperandRequest + if err := controllerutil.SetControllerReference(instance, opreq, r.Scheme); err != nil { + return errors.Wrapf(err, "failed to set ComposableOperatorRequest %s/%s as the owner of OperatorRequest", instance.Namespace, instance.Name) + } + + return nil + } + + return opreq, fn +} + +// SetupWithManager sets up the controller with the Manager. +func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&operatorv1alpha1.ComposableOperatorRequest{}). + Complete(r) +} diff --git a/controllers/operandrequest/operandrequest_controller.go b/controllers/operandrequest/operandrequest_controller.go index b6983e12..4ead7432 100644 --- a/controllers/operandrequest/operandrequest_controller.go +++ b/controllers/operandrequest/operandrequest_controller.go @@ -60,7 +60,7 @@ type clusterObjects struct { // Result.Requeue is true, otherwise upon completion it will remove the work from the queue. func (r *Reconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reconcileErr error) { - // Creat context for the OperandBindInfo reconciler + // Creat context for the OperandRequest reconciler ctx := context.Background() // Fetch the OperandRequest instance diff --git a/go.mod b/go.mod index 4b297f55..96eb5c37 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/operator-framework/api v0.3.10 github.com/pkg/errors v0.9.1 k8s.io/api v0.18.6 - k8s.io/apiextensions-apiserver v0.18.6 k8s.io/apimachinery v0.18.6 k8s.io/client-go v0.18.6 k8s.io/klog v1.0.0 diff --git a/main.go b/main.go index a7ab26bd..3f80f592 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,9 @@ import ( cache "github.com/IBM/controller-filtered-cache/filteredcache" nssv1 "github.com/IBM/ibm-namespace-scope-operator/api/v1" + operatorv1alpha1 "github.com/IBM/operand-deployment-lifecycle-manager/api/v1alpha1" + "github.com/IBM/operand-deployment-lifecycle-manager/controllers/composableoperatorrequest" "github.com/IBM/operand-deployment-lifecycle-manager/controllers/constant" "github.com/IBM/operand-deployment-lifecycle-manager/controllers/k8sutil" "github.com/IBM/operand-deployment-lifecycle-manager/controllers/namespacescope" @@ -132,6 +134,12 @@ func main() { klog.Errorf("unable to create controller NamespaceScope: %v", err) os.Exit(1) } + if err = (&composableoperatorrequest.Reconciler{ + ODLMOperator: deploy.NewODLMOperator(mgr, "ComposableOperatorRequest"), + }).SetupWithManager(mgr); err != nil { + klog.Errorf("unable to create controller ComposableOperatorRequest: %v", err) + os.Exit(1) + } // +kubebuilder:scaffold:builder klog.Info("starting manager")