From 771c4131cfbc09baedd16297fb965263604a4625 Mon Sep 17 00:00:00 2001 From: Luca Miccini Date: Thu, 12 Sep 2024 09:15:02 +0200 Subject: [PATCH] Rename InstanceHA to InstanceHa and use configmap for containerImage This commit renames the InstanceHA occurrences into InstanceHa to comply with the openstack-operator's openstackversion naming (case) convention. We also take the chance and use a configmap created by the openstack-operator to get the containerImage, so to orchestrate its update. --- PROJECT | 2 +- .../instanceha.openstack.org_instancehas.yaml | 24 +-- .../v1beta1/instanceha_conditions.go | 36 ++-- apis/instanceha/v1beta1/instanceha_types.go | 50 +++--- apis/instanceha/v1beta1/instanceha_webhook.go | 36 ++-- apis/instanceha/v1beta1/webhook_suite_test.go | 2 +- .../v1beta1/zz_generated.deepcopy.go | 46 +++--- .../instanceha.openstack.org_instancehas.yaml | 24 +-- .../instanceha_v1beta1_instanceha.yaml | 6 +- .../instanceha/instanceha_controller.go | 154 +++++++++++------- main.go | 6 +- pkg/instanceha/funcs.go | 11 +- templates/instanceha/bin/instanceha.py | 2 +- 13 files changed, 217 insertions(+), 182 deletions(-) diff --git a/PROJECT b/PROJECT index 21e43cdc..4a77a99c 100644 --- a/PROJECT +++ b/PROJECT @@ -36,7 +36,7 @@ resources: controller: true domain: openstack.org group: instanceha - kind: InstanceHA + kind: InstanceHa path: github.com/openstack-k8s-operators/infra-operator/apis/instanceha/v1beta1 version: v1beta1 webhooks: diff --git a/apis/bases/instanceha.openstack.org_instancehas.yaml b/apis/bases/instanceha.openstack.org_instancehas.yaml index 78f9d10d..50cfa175 100644 --- a/apis/bases/instanceha.openstack.org_instancehas.yaml +++ b/apis/bases/instanceha.openstack.org_instancehas.yaml @@ -9,8 +9,8 @@ metadata: spec: group: instanceha.openstack.org names: - kind: InstanceHA - listKind: InstanceHAList + kind: InstanceHa + listKind: InstanceHaList plural: instancehas singular: instanceha scope: Namespaced @@ -27,7 +27,7 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: InstanceHA is the Schema for the instancehas API + description: InstanceHa is the Schema for the instancehas API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation @@ -42,7 +42,7 @@ spec: metadata: type: object spec: - description: InstanceHASpec defines the desired state of InstanceHA + description: InstanceHaSpec defines the desired state of InstanceHa properties: caBundleSecretName: description: CaBundleSecretName - holding the CA certs in a pre-created @@ -50,7 +50,7 @@ spec: type: string containerImage: default: quay.io/podified-antelope-centos9/openstack-openstackclient:current-podified - description: ContainerImage for the the InstanceHA container (will + description: ContainerImage for the the InstanceHa container (will be set to environmental default if empty) type: string fencingSecret: @@ -58,12 +58,12 @@ spec: description: FencingSecret is the name of the Secret containing the fencing details type: string - instanceHAConfigMap: + instanceHaConfigMap: default: instanceha-config - description: InstanceHAConfigMap is the name of the ConfigMap containing - the InstanceHA config file + description: InstanceHaConfigMap is the name of the ConfigMap containing + the InstanceHa config file type: string - instanceHAKdumpPort: + instanceHaKdumpPort: default: 7410 format: int32 type: integer @@ -98,14 +98,14 @@ spec: required: - containerImage - fencingSecret - - instanceHAConfigMap - - instanceHAKdumpPort + - instanceHaConfigMap + - instanceHaKdumpPort - openStackCloud - openStackConfigMap - openStackConfigSecret type: object status: - description: InstanceHAStatus defines the observed state of InstanceHA + description: InstanceHaStatus defines the observed state of InstanceHa properties: conditions: description: Conditions diff --git a/apis/instanceha/v1beta1/instanceha_conditions.go b/apis/instanceha/v1beta1/instanceha_conditions.go index e46e0eff..25c40870 100644 --- a/apis/instanceha/v1beta1/instanceha_conditions.go +++ b/apis/instanceha/v1beta1/instanceha_conditions.go @@ -19,35 +19,35 @@ import ( condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" ) -// InstanceHA Condition Types used by API objects. +// InstanceHa Condition Types used by API objects. const ( - // InstanceHAReadyCondition Status=True condition which indicates if InstanceHA is configured and operational - InstanceHAReadyCondition condition.Type = "InstanceHAReady" + // InstanceHaReadyCondition Status=True condition which indicates if InstanceHa is configured and operational + InstanceHaReadyCondition condition.Type = "InstanceHaReady" ) -// InstanceHA Reasons used by API objects. +// InstanceHa Reasons used by API objects. const () // Common Messages used by API objects. const ( - // InstanceHAReadyInitMessage - InstanceHAReadyInitMessage = "Instance HA not started, waiting on keystone API" + // InstanceHaReadyInitMessage + InstanceHaReadyInitMessage = "Instance HA not started, waiting on keystone API" - // InstanceHAKeystoneWaitingMessage - InstanceHAKeystoneWaitingMessage = "Instance HA keystone API not yet ready" + // InstanceHaKeystoneWaitingMessage + InstanceHaKeystoneWaitingMessage = "Instance HA keystone API not yet ready" - // InstanceHAConfigMapWaitingMessage - InstanceHAConfigMapWaitingMessage = "Instance HA waiting for configmap" + // InstanceHaConfigMapWaitingMessage + InstanceHaConfigMapWaitingMessage = "Instance HA waiting for configmap" - // InstanceHASecretWaitingMessage - InstanceHASecretWaitingMessage = "Instance HA waiting for secret" + // InstanceHaSecretWaitingMessage + InstanceHaSecretWaitingMessage = "Instance HA waiting for secret" - // InstanceHAInputReady - InstanceHAInputReady = "Instance HA input ready" + // InstanceHaInputReady + InstanceHaInputReady = "Instance HA input ready" - // InstanceHAReadyMessage - InstanceHAReadyMessage = "Instance HA created" + // InstanceHaReadyMessage + InstanceHaReadyMessage = "Instance HA created" - // InstanceHAReadyErrorMessage - InstanceHAReadyErrorMessage = "Instance HA error occured %s" + // InstanceHaReadyErrorMessage + InstanceHaReadyErrorMessage = "Instance HA error occured %s" ) diff --git a/apis/instanceha/v1beta1/instanceha_types.go b/apis/instanceha/v1beta1/instanceha_types.go index d2ecc0e1..b1041b3f 100644 --- a/apis/instanceha/v1beta1/instanceha_types.go +++ b/apis/instanceha/v1beta1/instanceha_types.go @@ -26,16 +26,16 @@ import ( const ( // Container image fall-back defaults - // InstanceHAContainerImage is the fall-back container image for InstanceHA - InstanceHAContainerImage = "quay.io/podified-antelope-centos9/openstack-openstackclient:current-podified" + // InstanceHaContainerImage is the fall-back container image for InstanceHa + InstanceHaContainerImage = "quay.io/podified-antelope-centos9/openstack-openstackclient:current-podified" OpenStackCloud = "default" ) -// InstanceHASpec defines the desired state of InstanceHA -type InstanceHASpec struct { +// InstanceHaSpec defines the desired state of InstanceHa +type InstanceHaSpec struct { // +kubebuilder:validation:Required // +kubebuilder:default="quay.io/podified-antelope-centos9/openstack-openstackclient:current-podified" - // ContainerImage for the the InstanceHA container (will be set to environmental default if empty) + // ContainerImage for the the InstanceHa container (will be set to environmental default if empty) ContainerImage string `json:"containerImage"` // +kubebuilder:validation:Required @@ -60,12 +60,12 @@ type InstanceHASpec struct { // +kubebuilder:validation:Required // +kubebuilder:default=instanceha-config - // InstanceHAConfigMap is the name of the ConfigMap containing the InstanceHA config file - InstanceHAConfigMap string `json:"instanceHAConfigMap"` + // InstanceHaConfigMap is the name of the ConfigMap containing the InstanceHa config file + InstanceHaConfigMap string `json:"instanceHaConfigMap"` // +kubebuilder:validation:Required // +kubebuilder:default=7410 - InstanceHAKdumpPort int32 `json:"instanceHAKdumpPort"` + InstanceHaKdumpPort int32 `json:"instanceHaKdumpPort"` // +kubebuilder:validation:Optional // NodeSelector to target subset of worker nodes running control plane services (currently only applies to KeystoneAPI and PlacementAPI) @@ -82,8 +82,8 @@ type InstanceHASpec struct { tls.Ca `json:",inline"` } -// InstanceHAStatus defines the observed state of InstanceHA -type InstanceHAStatus struct { +// InstanceHaStatus defines the observed state of InstanceHa +type InstanceHaStatus struct { // PodName PodName string `json:"podName,omitempty"` @@ -102,49 +102,49 @@ type InstanceHAStatus struct { //+kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[0].status",description="Status" //+kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[0].message",description="Message" -// InstanceHA is the Schema for the instancehas API -type InstanceHA struct { +// InstanceHa is the Schema for the instancehas API +type InstanceHa struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec InstanceHASpec `json:"spec,omitempty"` - Status InstanceHAStatus `json:"status,omitempty"` + Spec InstanceHaSpec `json:"spec,omitempty"` + Status InstanceHaStatus `json:"status,omitempty"` } //+kubebuilder:object:root=true -// InstanceHAList contains a list of InstanceHA -type InstanceHAList struct { +// InstanceHaList contains a list of InstanceHa +type InstanceHaList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []InstanceHA `json:"items"` + Items []InstanceHa `json:"items"` } func init() { - SchemeBuilder.Register(&InstanceHA{}, &InstanceHAList{}) + SchemeBuilder.Register(&InstanceHa{}, &InstanceHaList{}) } // RbacConditionsSet - set the conditions for the rbac object -func (instance InstanceHA) RbacConditionsSet(c *condition.Condition) { +func (instance InstanceHa) RbacConditionsSet(c *condition.Condition) { instance.Status.Conditions.Set(c) } // RbacNamespace - return the namespace -func (instance InstanceHA) RbacNamespace() string { +func (instance InstanceHa) RbacNamespace() string { return instance.Namespace } // RbacResourceName - return the name to be used for rbac objects (serviceaccount, role, rolebinding) -func (instance InstanceHA) RbacResourceName() string { +func (instance InstanceHa) RbacResourceName() string { return "instanceha-" + instance.Name } // SetupDefaults - initializes any CRD field defaults based on environment variables (the defaulting mechanism itself is implemented via webhooks) func SetupDefaults() { - // Acquire environmental defaults and initialize InstanceHA defaults with them - instanceHADefaults := InstanceHADefaults{ - ContainerImageURL: util.GetEnvVar("RELATED_IMAGE_INSTANCE_HA_IMAGE_URL_DEFAULT", InstanceHAContainerImage), + // Acquire environmental defaults and initialize InstanceHa defaults with them + instanceHaDefaults := InstanceHaDefaults{ + ContainerImageURL: util.GetEnvVar("RELATED_IMAGE_INSTANCE_HA_IMAGE_URL_DEFAULT", InstanceHaContainerImage), } - SetupInstanceHADefaults(instanceHADefaults) + SetupInstanceHaDefaults(instanceHaDefaults) } diff --git a/apis/instanceha/v1beta1/instanceha_webhook.go b/apis/instanceha/v1beta1/instanceha_webhook.go index 4c9bc790..1430d90a 100644 --- a/apis/instanceha/v1beta1/instanceha_webhook.go +++ b/apis/instanceha/v1beta1/instanceha_webhook.go @@ -14,7 +14,7 @@ limitations under the License. // // Generated by: // -// operator-sdk create webhook --group client --version v1beta1 --kind InstanceHA --programmatic-validation --defaulting +// operator-sdk create webhook --group client --version v1beta1 --kind InstanceHa --programmatic-validation --defaulting // package v1beta1 @@ -27,24 +27,24 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" ) -// InstanceHADefaults - -type InstanceHADefaults struct { +// InstanceHaDefaults - +type InstanceHaDefaults struct { ContainerImageURL string } -var instanceHADefaults InstanceHADefaults +var instanceHaDefaults InstanceHaDefaults // log is for logging in this package. var instancehalog = logf.Log.WithName("instanceha-resource") -// SetupInstanceHADefaults - initialize InstanceHA spec defaults for use with either internal or external webhooks -func SetupInstanceHADefaults(defaults InstanceHADefaults) { - instanceHADefaults = defaults - instancehalog.Info("InstanceHA defaults initialized", "defaults", defaults) +// SetupInstanceHaDefaults - initialize InstanceHa spec defaults for use with either internal or external webhooks +func SetupInstanceHaDefaults(defaults InstanceHaDefaults) { + instanceHaDefaults = defaults + instancehalog.Info("InstanceHa defaults initialized", "defaults", defaults) } // SetupWebhookWithManager sets up the webhook with the Manager -func (r *InstanceHA) SetupWebhookWithManager(mgr ctrl.Manager) error { +func (r *InstanceHa) SetupWebhookWithManager(mgr ctrl.Manager) error { return ctrl.NewWebhookManagedBy(mgr). For(r). Complete() @@ -52,29 +52,29 @@ func (r *InstanceHA) SetupWebhookWithManager(mgr ctrl.Manager) error { //+kubebuilder:webhook:path=/mutate-client-openstack-org-v1beta1-instanceha,mutating=true,failurePolicy=fail,sideEffects=None,groups=client.openstack.org,resources=instancehas,verbs=create;update,versions=v1beta1,name=minstanceha.kb.io,admissionReviewVersions=v1 -var _ webhook.Defaulter = &InstanceHA{} +var _ webhook.Defaulter = &InstanceHa{} // Default implements webhook.Defaulter so a webhook will be registered for the type -func (r *InstanceHA) Default() { +func (r *InstanceHa) Default() { instancehalog.Info("default", "name", r.Name) r.Spec.Default() } -// Default - set defaults for this InstanceHA spec -func (spec *InstanceHASpec) Default() { +// Default - set defaults for this InstanceHa spec +func (spec *InstanceHaSpec) Default() { if spec.ContainerImage == "" { - spec.ContainerImage = instanceHADefaults.ContainerImageURL + spec.ContainerImage = instanceHaDefaults.ContainerImageURL } } // TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. //+kubebuilder:webhook:path=/validate-client-openstack-org-v1beta1-instanceha,mutating=false,failurePolicy=fail,sideEffects=None,groups=client.openstack.org,resources=instancehas,verbs=create;update,versions=v1beta1,name=vinstanceha.kb.io,admissionReviewVersions=v1 -var _ webhook.Validator = &InstanceHA{} +var _ webhook.Validator = &InstanceHa{} // ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (r *InstanceHA) ValidateCreate() (admission.Warnings, error) { +func (r *InstanceHa) ValidateCreate() (admission.Warnings, error) { instancehalog.Info("validate create", "name", r.Name) // TODO(user): fill in your validation logic upon object creation. @@ -82,7 +82,7 @@ func (r *InstanceHA) ValidateCreate() (admission.Warnings, error) { } // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (r *InstanceHA) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { +func (r *InstanceHa) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { instancehalog.Info("validate update", "name", r.Name) // TODO(user): fill in your validation logic upon object update. @@ -90,7 +90,7 @@ func (r *InstanceHA) ValidateUpdate(old runtime.Object) (admission.Warnings, err } // ValidateDelete implements webhook.Validator so a webhook will be registered for the type -func (r *InstanceHA) ValidateDelete() (admission.Warnings, error) { +func (r *InstanceHa) ValidateDelete() (admission.Warnings, error) { instancehalog.Info("validate delete", "name", r.Name) // TODO(user): fill in your validation logic upon object deletion. diff --git a/apis/instanceha/v1beta1/webhook_suite_test.go b/apis/instanceha/v1beta1/webhook_suite_test.go index 0649c1d0..e8e6c655 100644 --- a/apis/instanceha/v1beta1/webhook_suite_test.go +++ b/apis/instanceha/v1beta1/webhook_suite_test.go @@ -111,7 +111,7 @@ var _ = BeforeSuite(func() { }) Expect(err).NotTo(HaveOccurred()) - err = (&InstanceHA{}).SetupWebhookWithManager(mgr) + err = (&InstanceHa{}).SetupWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) //+kubebuilder:scaffold:webhook diff --git a/apis/instanceha/v1beta1/zz_generated.deepcopy.go b/apis/instanceha/v1beta1/zz_generated.deepcopy.go index 2bdf75c5..121d26a7 100644 --- a/apis/instanceha/v1beta1/zz_generated.deepcopy.go +++ b/apis/instanceha/v1beta1/zz_generated.deepcopy.go @@ -27,7 +27,7 @@ import ( ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InstanceHA) DeepCopyInto(out *InstanceHA) { +func (in *InstanceHa) DeepCopyInto(out *InstanceHa) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -35,18 +35,18 @@ func (in *InstanceHA) DeepCopyInto(out *InstanceHA) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHA. -func (in *InstanceHA) DeepCopy() *InstanceHA { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHa. +func (in *InstanceHa) DeepCopy() *InstanceHa { if in == nil { return nil } - out := new(InstanceHA) + out := new(InstanceHa) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InstanceHA) DeepCopyObject() runtime.Object { +func (in *InstanceHa) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -54,46 +54,46 @@ func (in *InstanceHA) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InstanceHADefaults) DeepCopyInto(out *InstanceHADefaults) { +func (in *InstanceHaDefaults) DeepCopyInto(out *InstanceHaDefaults) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHADefaults. -func (in *InstanceHADefaults) DeepCopy() *InstanceHADefaults { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHaDefaults. +func (in *InstanceHaDefaults) DeepCopy() *InstanceHaDefaults { if in == nil { return nil } - out := new(InstanceHADefaults) + out := new(InstanceHaDefaults) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InstanceHAList) DeepCopyInto(out *InstanceHAList) { +func (in *InstanceHaList) DeepCopyInto(out *InstanceHaList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]InstanceHA, len(*in)) + *out = make([]InstanceHa, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHAList. -func (in *InstanceHAList) DeepCopy() *InstanceHAList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHaList. +func (in *InstanceHaList) DeepCopy() *InstanceHaList { if in == nil { return nil } - out := new(InstanceHAList) + out := new(InstanceHaList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *InstanceHAList) DeepCopyObject() runtime.Object { +func (in *InstanceHaList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -101,7 +101,7 @@ func (in *InstanceHAList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InstanceHASpec) DeepCopyInto(out *InstanceHASpec) { +func (in *InstanceHaSpec) DeepCopyInto(out *InstanceHaSpec) { *out = *in if in.NodeSelector != nil { in, out := &in.NodeSelector, &out.NodeSelector @@ -118,18 +118,18 @@ func (in *InstanceHASpec) DeepCopyInto(out *InstanceHASpec) { out.Ca = in.Ca } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHASpec. -func (in *InstanceHASpec) DeepCopy() *InstanceHASpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHaSpec. +func (in *InstanceHaSpec) DeepCopy() *InstanceHaSpec { if in == nil { return nil } - out := new(InstanceHASpec) + out := new(InstanceHaSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *InstanceHAStatus) DeepCopyInto(out *InstanceHAStatus) { +func (in *InstanceHaStatus) DeepCopyInto(out *InstanceHaStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -155,12 +155,12 @@ func (in *InstanceHAStatus) DeepCopyInto(out *InstanceHAStatus) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHAStatus. -func (in *InstanceHAStatus) DeepCopy() *InstanceHAStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceHaStatus. +func (in *InstanceHaStatus) DeepCopy() *InstanceHaStatus { if in == nil { return nil } - out := new(InstanceHAStatus) + out := new(InstanceHaStatus) in.DeepCopyInto(out) return out } diff --git a/config/crd/bases/instanceha.openstack.org_instancehas.yaml b/config/crd/bases/instanceha.openstack.org_instancehas.yaml index 78f9d10d..50cfa175 100644 --- a/config/crd/bases/instanceha.openstack.org_instancehas.yaml +++ b/config/crd/bases/instanceha.openstack.org_instancehas.yaml @@ -9,8 +9,8 @@ metadata: spec: group: instanceha.openstack.org names: - kind: InstanceHA - listKind: InstanceHAList + kind: InstanceHa + listKind: InstanceHaList plural: instancehas singular: instanceha scope: Namespaced @@ -27,7 +27,7 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: InstanceHA is the Schema for the instancehas API + description: InstanceHa is the Schema for the instancehas API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation @@ -42,7 +42,7 @@ spec: metadata: type: object spec: - description: InstanceHASpec defines the desired state of InstanceHA + description: InstanceHaSpec defines the desired state of InstanceHa properties: caBundleSecretName: description: CaBundleSecretName - holding the CA certs in a pre-created @@ -50,7 +50,7 @@ spec: type: string containerImage: default: quay.io/podified-antelope-centos9/openstack-openstackclient:current-podified - description: ContainerImage for the the InstanceHA container (will + description: ContainerImage for the the InstanceHa container (will be set to environmental default if empty) type: string fencingSecret: @@ -58,12 +58,12 @@ spec: description: FencingSecret is the name of the Secret containing the fencing details type: string - instanceHAConfigMap: + instanceHaConfigMap: default: instanceha-config - description: InstanceHAConfigMap is the name of the ConfigMap containing - the InstanceHA config file + description: InstanceHaConfigMap is the name of the ConfigMap containing + the InstanceHa config file type: string - instanceHAKdumpPort: + instanceHaKdumpPort: default: 7410 format: int32 type: integer @@ -98,14 +98,14 @@ spec: required: - containerImage - fencingSecret - - instanceHAConfigMap - - instanceHAKdumpPort + - instanceHaConfigMap + - instanceHaKdumpPort - openStackCloud - openStackConfigMap - openStackConfigSecret type: object status: - description: InstanceHAStatus defines the observed state of InstanceHA + description: InstanceHaStatus defines the observed state of InstanceHa properties: conditions: description: Conditions diff --git a/config/samples/instanceha_v1beta1_instanceha.yaml b/config/samples/instanceha_v1beta1_instanceha.yaml index 5a1435bd..c2be449d 100644 --- a/config/samples/instanceha_v1beta1_instanceha.yaml +++ b/config/samples/instanceha_v1beta1_instanceha.yaml @@ -1,5 +1,5 @@ apiVersion: instanceha.openstack.org/v1beta1 -kind: InstanceHA +kind: InstanceHa metadata: name: instanceha spec: @@ -10,5 +10,5 @@ spec: #openStackConfigMap: #openStackConfigSecret: #fencingSecret: - #instanceHAConfigMap: - #instanceHAKdumpPort: + #instanceHaConfigMap: + #instanceHaKdumpPort: diff --git a/controllers/instanceha/instanceha_controller.go b/controllers/instanceha/instanceha_controller.go index d75843e4..f986880e 100644 --- a/controllers/instanceha/instanceha_controller.go +++ b/controllers/instanceha/instanceha_controller.go @@ -61,7 +61,7 @@ import ( instanceha "github.com/openstack-k8s-operators/infra-operator/pkg/instanceha" ) -// InstanceHAReconciler reconciles a InstanceHA object +// InstanceHaReconciler reconciles a InstanceHa object type Reconciler struct { client.Client Scheme *runtime.Scheme @@ -70,15 +70,15 @@ type Reconciler struct { // GetLog returns a logger object with a prefix of "conroller.name" and aditional controller context fields func (r *Reconciler) GetLogger(ctx context.Context) logr.Logger { - return log.FromContext(ctx).WithName("Controllers").WithName("InstanceHA") + return log.FromContext(ctx).WithName("Controllers").WithName("InstanceHa") } -//+kubebuilder:rbac:groups=instanceha.openstack.org,resources=instancehas,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=instanceha.openstack.org,resources=instancehas/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=instanceha.openstack.org,resources=instancehas/finalizers,verbs=update;patch -//+kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneapis,verbs=get;list;watch -//+kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch; -//+kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch; +// +kubebuilder:rbac:groups=instanceha.openstack.org,resources=instancehas,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=instanceha.openstack.org,resources=instancehas/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=instanceha.openstack.org,resources=instancehas/finalizers,verbs=update;patch +// +kubebuilder:rbac:groups=keystone.openstack.org,resources=keystoneapis,verbs=get;list;watch +// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch; +// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch; // service account, role, rolebinding // +kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch;create;update;patch // +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=roles,verbs=get;list;watch;create;update;patch @@ -92,11 +92,11 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct Log := r.GetLogger(ctx) - instance := &instancehav1.InstanceHA{} + instance := &instancehav1.InstanceHa{} err := r.Client.Get(context.TODO(), req.NamespacedName, instance) if err != nil { if k8s_errors.IsNotFound(err) { - Log.Info("InstanceHA CR not found") + Log.Info("InstanceHa CR not found") return ctrl.Result{}, nil } return ctrl.Result{}, err @@ -148,7 +148,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct }() cl := condition.CreateList( - condition.UnknownCondition(instancehav1.InstanceHAReadyCondition, condition.InitReason, instancehav1.InstanceHAReadyInitMessage), + condition.UnknownCondition(instancehav1.InstanceHaReadyCondition, condition.InitReason, instancehav1.InstanceHaReadyInitMessage), // service account, role, rolebinding conditions condition.UnknownCondition(condition.ServiceAccountReadyCondition, condition.InitReason, condition.ServiceAccountReadyInitMessage), condition.UnknownCondition(condition.RoleReadyCondition, condition.InitReason, condition.RoleReadyInitMessage), @@ -191,27 +191,27 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct if err != nil { if k8s_errors.IsNotFound(err) { instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.RequestedReason, condition.SeverityInfo, - instancehav1.InstanceHAKeystoneWaitingMessage)) + instancehav1.InstanceHaKeystoneWaitingMessage)) Log.Info("KeystoneAPI not found!") return ctrl.Result{RequeueAfter: time.Duration(5) * time.Second}, nil } instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.ErrorReason, condition.SeverityWarning, - instancehav1.InstanceHAReadyErrorMessage, + instancehav1.InstanceHaReadyErrorMessage, err.Error())) return ctrl.Result{}, err } if !keystoneAPI.IsReady() { instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.RequestedReason, condition.SeverityInfo, - instancehav1.InstanceHAKeystoneWaitingMessage)) + instancehav1.InstanceHaKeystoneWaitingMessage)) Log.Info("KeystoneAPI not yet ready") return ctrl.Result{RequeueAfter: time.Duration(5) * time.Second}, nil } @@ -226,17 +226,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct if err != nil { if k8s_errors.IsNotFound(err) { instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.RequestedReason, condition.SeverityInfo, - instancehav1.InstanceHAConfigMapWaitingMessage)) + instancehav1.InstanceHaConfigMapWaitingMessage)) return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil } instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.ErrorReason, condition.SeverityWarning, - instancehav1.InstanceHAReadyErrorMessage, + instancehav1.InstanceHaReadyErrorMessage, err.Error())) return ctrl.Result{}, err } @@ -246,17 +246,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct if err != nil { if k8s_errors.IsNotFound(err) { instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.RequestedReason, condition.SeverityInfo, - instancehav1.InstanceHASecretWaitingMessage)) + instancehav1.InstanceHaSecretWaitingMessage)) return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil } instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.ErrorReason, condition.SeverityWarning, - instancehav1.InstanceHAReadyErrorMessage, + instancehav1.InstanceHaReadyErrorMessage, err.Error())) return ctrl.Result{}, err } @@ -266,32 +266,32 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct if err != nil { if k8s_errors.IsNotFound(err) { instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.RequestedReason, condition.SeverityInfo, - instancehav1.InstanceHASecretWaitingMessage)) + instancehav1.InstanceHaSecretWaitingMessage)) return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil } instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.ErrorReason, condition.SeverityWarning, - instancehav1.InstanceHAReadyErrorMessage, + instancehav1.InstanceHaReadyErrorMessage, err.Error())) return ctrl.Result{}, err } configVars[instance.Spec.FencingSecret] = env.SetValue(secretHash) - // Check if instance.Spec.InstanceHAConfigMap is present, if not create it. + // Check if instance.Spec.InstanceHaConfigMap is present, if not create it. // The first time this will produce an error b/c GetConfigMapAndHashWithName doesn't support retries. - _, configMapHash, err = configmap.GetConfigMapAndHashWithName(ctx, helper, instance.Spec.InstanceHAConfigMap, instance.Namespace) + _, configMapHash, err = configmap.GetConfigMapAndHashWithName(ctx, helper, instance.Spec.InstanceHaConfigMap, instance.Namespace) if err != nil { if k8s_errors.IsNotFound(err) { cmLabels := labels.GetLabels(instance, labels.GetGroupLabel("instanceha"), map[string]string{}) envVars := make(map[string]env.Setter) cms := []util.Template{ { - Name: instance.Spec.InstanceHAConfigMap, + Name: instance.Spec.InstanceHaConfigMap, Namespace: instance.Namespace, Type: util.TemplateTypeConfig, InstanceType: instance.Kind, @@ -305,33 +305,33 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct return ctrl.Result{}, err } - _, configMapHash, err = configmap.GetConfigMapAndHashWithName(ctx, helper, instance.Spec.InstanceHAConfigMap, instance.Namespace) + _, configMapHash, err = configmap.GetConfigMapAndHashWithName(ctx, helper, instance.Spec.InstanceHaConfigMap, instance.Namespace) if err != nil { if k8s_errors.IsNotFound(err) { instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.RequestedReason, condition.SeverityInfo, - instancehav1.InstanceHAConfigMapWaitingMessage)) + instancehav1.InstanceHaConfigMapWaitingMessage)) return ctrl.Result{RequeueAfter: time.Duration(10) * time.Second}, nil } instance.Status.Conditions.Set(condition.FalseCondition( - instancehav1.InstanceHAReadyCondition, + instancehav1.InstanceHaReadyCondition, condition.ErrorReason, condition.SeverityWarning, - instancehav1.InstanceHAReadyErrorMessage, + instancehav1.InstanceHaReadyErrorMessage, err.Error())) return ctrl.Result{}, err } - configVars[instance.Spec.InstanceHAConfigMap] = env.SetValue(configMapHash) + configVars[instance.Spec.InstanceHaConfigMap] = env.SetValue(configMapHash) } else { // Catch and log generic error fetching the configmap - Log.Error(err, fmt.Sprintf("could not fetch configmap %s", instance.Spec.InstanceHAConfigMap)) + Log.Error(err, fmt.Sprintf("could not fetch configmap %s", instance.Spec.InstanceHaConfigMap)) return ctrl.Result{}, err } } - configVars[instance.Spec.InstanceHAConfigMap] = env.SetValue(configMapHash) + configVars[instance.Spec.InstanceHaConfigMap] = env.SetValue(configMapHash) if instance.Spec.CaBundleSecretName != "" { secretHash, err := tls.ValidateCACertSecret( @@ -396,14 +396,19 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct // Create netattachment serviceAnnotations, err := nad.CreateNetworksAnnotation(instance.Namespace, instance.Spec.NetworkAttachments) if err != nil { - return ctrl.Result{}, fmt.Errorf("failed create network annotation from %s: %w", + return ctrl.Result{}, fmt.Errorf("failed to create network annotation from %s: %w", instance.Spec.NetworkAttachments, err) } // TODO add check to make sure there is only a single copy of instanceha using the same OpenStackCloud cloud := instance.Spec.OpenStackCloud - commondeployment := commondeployment.NewDeployment(instanceha.Deployment(instance, Labels, serviceAnnotations, cloud, configVarsHash), time.Duration(5)*time.Second) + containerImage, err := r.GetContainerImage(ctx, instance.Spec.ContainerImage, instance) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to fetch containerImage from ConfigMap: %s", err) + } + + commondeployment := commondeployment.NewDeployment(instanceha.Deployment(instance, Labels, serviceAnnotations, cloud, configVarsHash, containerImage), time.Duration(5)*time.Second) sfres, sferr := commondeployment.CreateOrPatch(ctx, helper) if sferr != nil { return sfres, sferr @@ -434,7 +439,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ct } if deployment.Status.ReadyReplicas > 0 { - instance.Status.Conditions.MarkTrue(instancehav1.InstanceHAReadyCondition, instancehav1.InstanceHAReadyMessage) + instance.Status.Conditions.MarkTrue(instancehav1.InstanceHaReadyCondition, instancehav1.InstanceHaReadyMessage) } return ctrl.Result{}, nil @@ -447,7 +452,7 @@ const ( openStackConfigMapField = ".spec.openStackConfigMap" openStackConfigSecretField = ".spec.openStackConfigSecret" fencingSecretField = ".spec.fencingSecret" - instanceHAConfigMapField = ".spec.instanceHAConfigMap" + instanceHaConfigMapField = ".spec.instanceHaConfigMap" ) var ( @@ -456,7 +461,7 @@ var ( openStackConfigMapField, openStackConfigSecretField, fencingSecretField, - instanceHAConfigMapField, + instanceHaConfigMapField, } ) @@ -464,9 +469,9 @@ var ( func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { // index caBundleSecretNameField - if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHA{}, caBundleSecretNameField, func(rawObj client.Object) []string { + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHa{}, caBundleSecretNameField, func(rawObj client.Object) []string { // Extract the secret name from the spec, if one is provided - cr := rawObj.(*instancehav1.InstanceHA) + cr := rawObj.(*instancehav1.InstanceHa) if cr.Spec.CaBundleSecretName == "" { return nil } @@ -475,9 +480,9 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { return err } // index openStackConfigMap - if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHA{}, openStackConfigMapField, func(rawObj client.Object) []string { + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHa{}, openStackConfigMapField, func(rawObj client.Object) []string { // Extract the configmap name from the spec, if one is provided - cr := rawObj.(*instancehav1.InstanceHA) + cr := rawObj.(*instancehav1.InstanceHa) if cr.Spec.OpenStackConfigMap == "" { return nil } @@ -486,9 +491,9 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { return err } // index openStackConfigSecret - if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHA{}, openStackConfigSecretField, func(rawObj client.Object) []string { + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHa{}, openStackConfigSecretField, func(rawObj client.Object) []string { // Extract the configmap name from the spec, if one is provided - cr := rawObj.(*instancehav1.InstanceHA) + cr := rawObj.(*instancehav1.InstanceHa) if cr.Spec.OpenStackConfigSecret == "" { return nil } @@ -497,9 +502,9 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { return err } // index fencingSecret - if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHA{}, fencingSecretField, func(rawObj client.Object) []string { + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHa{}, fencingSecretField, func(rawObj client.Object) []string { // Extract the secret name from the spec, if one is provided - cr := rawObj.(*instancehav1.InstanceHA) + cr := rawObj.(*instancehav1.InstanceHa) if cr.Spec.FencingSecret == "" { return nil } @@ -507,20 +512,20 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { }); err != nil { return err } - // index instanceHAConfigMap - if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHA{}, instanceHAConfigMapField, func(rawObj client.Object) []string { + // index instanceHaConfigMap + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &instancehav1.InstanceHa{}, instanceHaConfigMapField, func(rawObj client.Object) []string { // Extract the configmap name from the spec, if one is provided - cr := rawObj.(*instancehav1.InstanceHA) - if cr.Spec.InstanceHAConfigMap == "" { + cr := rawObj.(*instancehav1.InstanceHa) + if cr.Spec.InstanceHaConfigMap == "" { return nil } - return []string{cr.Spec.InstanceHAConfigMap} + return []string{cr.Spec.InstanceHaConfigMap} }); err != nil { return err } return ctrl.NewControllerManagedBy(mgr). - For(&instancehav1.InstanceHA{}). + For(&instancehav1.InstanceHa{}). Owns(&appsv1.Deployment{}). Owns(&corev1.ServiceAccount{}). Owns(&rbacv1.Role{}). @@ -557,7 +562,7 @@ func (r *Reconciler) findObjectsForSrc(ctx context.Context, src client.Object) [ requests := []reconcile.Request{} for _, field := range allWatchFields { - crList := &instancehav1.InstanceHAList{} + crList := &instancehav1.InstanceHaList{} listOps := &client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(field, src.GetName()), Namespace: src.GetNamespace(), @@ -581,3 +586,32 @@ func (r *Reconciler) findObjectsForSrc(ctx context.Context, src client.Object) [ return requests } + +func (r *Reconciler) GetContainerImage( + ctx context.Context, + containerImage string, + src client.Object, +) (string, error) { + cm := &corev1.ConfigMap{} + instanceHaConfigMapName := "infra-instanceha-config" + + if len(containerImage) > 0 { + return containerImage, nil + } + + objectKey := client.ObjectKey{Namespace: src.GetNamespace(), Name: instanceHaConfigMapName} + err := r.Client.Get(ctx, objectKey, cm) + if err != nil { + return "", err + } + + if cm.Data == nil { + return util.GetEnvVar("RELATED_IMAGE_INFRA_INSTANCE_HA_IMAGE_URL_DEFAULT", ""), nil + } + + if cmImage, exists := cm.Data["instanceha-image"]; exists { + return cmImage, nil + } + + return "", nil +} diff --git a/main.go b/main.go index 3b784dea..3d0c2734 100644 --- a/main.go +++ b/main.go @@ -161,7 +161,7 @@ func main() { Kclient: kclient, Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "InstanceHA") + setupLog.Error(err, "unable to create controller", "controller", "InstanceHa") os.Exit(1) } if err = (&rediscontrollers.Reconciler{ @@ -220,8 +220,8 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "Memcached") os.Exit(1) } - if err = (&instancehav1.InstanceHA{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "InstanceHA") + if err = (&instancehav1.InstanceHa{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "InstanceHa") os.Exit(1) } if err = (&redisv1.Redis{}).SetupWebhookWithManager(mgr); err != nil { diff --git a/pkg/instanceha/funcs.go b/pkg/instanceha/funcs.go index 8dfc89d7..d02de909 100644 --- a/pkg/instanceha/funcs.go +++ b/pkg/instanceha/funcs.go @@ -23,11 +23,12 @@ import ( ) func Deployment( - instance *instancehav1.InstanceHA, + instance *instancehav1.InstanceHa, labels map[string]string, annotations map[string]string, openstackcloud string, configHash string, + containerImage string, ) *appsv1.Deployment { replicas := int32(1) @@ -71,7 +72,7 @@ func Deployment( NodeSelector: instance.Spec.NodeSelector, Containers: []corev1.Container{{ Name: "instanceha", - Image: instance.Spec.ContainerImage, + Image: containerImage, Command: []string{"/usr/bin/python3", "-u", "/var/lib/instanceha/instanceha.py"}, SecurityContext: &corev1.SecurityContext{ RunAsUser: ptr.To[int64](42401), @@ -86,7 +87,7 @@ func Deployment( }, Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), Ports: []corev1.ContainerPort{{ - ContainerPort: instance.Spec.InstanceHAKdumpPort, + ContainerPort: instance.Spec.InstanceHaKdumpPort, Protocol: "UDP", Name: "instanceha", }}, @@ -133,7 +134,7 @@ func instancehaPodVolumeMounts() []corev1.VolumeMount { } func instancehaPodVolumes( - instance *instancehav1.InstanceHA, + instance *instancehav1.InstanceHa, ) []corev1.Volume { var config0644AccessMode int32 = 0644 @@ -180,7 +181,7 @@ func instancehaPodVolumes( VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: instance.Spec.InstanceHAConfigMap, + Name: instance.Spec.InstanceHaConfigMap, }, }, }, diff --git a/templates/instanceha/bin/instanceha.py b/templates/instanceha/bin/instanceha.py index 7d1d20fe..94760c9d 100755 --- a/templates/instanceha/bin/instanceha.py +++ b/templates/instanceha/bin/instanceha.py @@ -744,7 +744,7 @@ def main(): logging.warning('Some services failed to evacuate. Retrying in 30 seconds.') else: - logging.info('InstanceHA DISABLE is true, not evacuating') + logging.info('InstanceHa DISABLE is true, not evacuating') # We need to wait until a compute is back and for the migrations to move from 'done' to 'completed' before we can force_down=false