From 80d41ae86cf83f7fc1462c3df16c3379debad574 Mon Sep 17 00:00:00 2001 From: Martin Schuppert Date: Mon, 7 Aug 2023 18:16:57 +0200 Subject: [PATCH] Create nova route and svc endpoint overrides Creates the route for the nova components, also allows to customize the route via override. Generats the service override for the env with what is configured in the externalEndpoints, or specified in the service template override. Depends-On: https://github.com/openstack-k8s-operators/lib-common/pull/313 Depends-On: https://github.com/openstack-k8s-operators/keystone-operator/pull/289 Depends-On: https://github.com/openstack-k8s-operators/nova-operator/pull/489 Jira: OSP-26690 --- ....openstack.org_openstackcontrolplanes.yaml | 223 +++++++++++++++++- .../v1beta1/openstackcontrolplane_types.go | 17 ++ apis/core/v1beta1/zz_generated.deepcopy.go | 24 ++ ....openstack.org_openstackcontrolplanes.yaml | 223 +++++++++++++++++- ...controlplane_galera_network_isolation.yaml | 26 +- ...ne_galera_network_isolation_3replicas.yaml | 26 +- ...enstackcontrolplane_network_isolation.yaml | 26 +- ...ckcontrolplane_network_isolation_ceph.yaml | 26 +- pkg/openstack/nova.go | 147 ++++++++++++ 9 files changed, 674 insertions(+), 64 deletions(-) diff --git a/apis/bases/core.openstack.org_openstackcontrolplanes.yaml b/apis/bases/core.openstack.org_openstackcontrolplanes.yaml index 7c5fd74e4..147a06749 100644 --- a/apis/bases/core.openstack.org_openstackcontrolplanes.yaml +++ b/apis/bases/core.openstack.org_openstackcontrolplanes.yaml @@ -6756,6 +6756,213 @@ spec: type: object nova: properties: + apiOverride: + properties: + route: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + spec: + properties: + alternateBackends: + items: + properties: + kind: + enum: + - Service + - "" + type: string + name: + type: string + weight: + format: int32 + maximum: 256 + minimum: 0 + type: integer + type: object + maxItems: 3 + type: array + host: + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + path: + pattern: ^/ + type: string + port: + properties: + targetPort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - targetPort + type: object + subdomain: + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + properties: + caCertificate: + type: string + certificate: + type: string + destinationCACertificate: + type: string + insecureEdgeTerminationPolicy: + type: string + key: + type: string + termination: + enum: + - edge + - reencrypt + - passthrough + type: string + required: + - termination + type: object + to: + properties: + kind: + enum: + - Service + - "" + type: string + name: + type: string + weight: + format: int32 + maximum: 256 + minimum: 0 + type: integer + type: object + wildcardPolicy: + enum: + - None + - Subdomain + - "" + type: string + type: object + type: object + type: object + cellOverride: + additionalProperties: + properties: + noVNCProxy: + properties: + route: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + spec: + properties: + alternateBackends: + items: + properties: + kind: + enum: + - Service + - "" + type: string + name: + type: string + weight: + format: int32 + maximum: 256 + minimum: 0 + type: integer + type: object + maxItems: 3 + type: array + host: + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + path: + pattern: ^/ + type: string + port: + properties: + targetPort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - targetPort + type: object + subdomain: + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + properties: + caCertificate: + type: string + certificate: + type: string + destinationCACertificate: + type: string + insecureEdgeTerminationPolicy: + type: string + key: + type: string + termination: + enum: + - edge + - reencrypt + - passthrough + type: string + required: + - termination + type: object + to: + properties: + kind: + enum: + - Service + - "" + type: string + name: + type: string + weight: + format: int32 + maximum: 256 + minimum: 0 + type: integer + type: object + wildcardPolicy: + enum: + - None + - Subdomain + - "" + type: string + type: object + type: object + type: object + type: object + type: object enabled: default: true type: boolean @@ -6793,7 +7000,7 @@ spec: override: properties: service: - items: + additionalProperties: properties: endpointURL: type: string @@ -6839,7 +7046,7 @@ spec: type: string type: object type: object - type: array + type: object type: object replicas: default: 1 @@ -6973,7 +7180,7 @@ spec: override: properties: service: - items: + additionalProperties: properties: endpointURL: type: string @@ -7019,7 +7226,7 @@ spec: type: string type: object type: object - type: array + type: object type: object replicas: default: 1 @@ -7080,7 +7287,7 @@ spec: override: properties: service: - items: + additionalProperties: properties: endpointURL: type: string @@ -7126,7 +7333,7 @@ spec: type: string type: object type: object - type: array + type: object type: object replicas: default: 1 @@ -7230,7 +7437,7 @@ spec: override: properties: service: - items: + additionalProperties: properties: endpointURL: type: string @@ -7276,7 +7483,7 @@ spec: type: string type: object type: object - type: array + type: object type: object replicas: default: 1 diff --git a/apis/core/v1beta1/openstackcontrolplane_types.go b/apis/core/v1beta1/openstackcontrolplane_types.go index b4d56340f..59f17614e 100644 --- a/apis/core/v1beta1/openstackcontrolplane_types.go +++ b/apis/core/v1beta1/openstackcontrolplane_types.go @@ -430,6 +430,23 @@ type NovaSection struct { //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Nova services Template novav1.NovaSpec `json:"template,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // APIOverride, provides the ability to override the generated manifest of several child resources. + APIOverride Override `json:"apiOverride,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // CellOverride, provides the ability to override the generated manifest of several child resources + // for a nova cell. + CellOverride map[string]NovaCellOverrideSpec `json:"cellOverride,omitempty"` +} + +// NovaCellOverrideSpec to override the generated manifest of several child resources. +type NovaCellOverrideSpec struct { + // +kubebuilder:validation:Optional + NoVNCProxy Override `json:"noVNCProxy,omitempty"` } // HeatSection defines the desired state of Heat services diff --git a/apis/core/v1beta1/zz_generated.deepcopy.go b/apis/core/v1beta1/zz_generated.deepcopy.go index 061524fe9..74831e057 100644 --- a/apis/core/v1beta1/zz_generated.deepcopy.go +++ b/apis/core/v1beta1/zz_generated.deepcopy.go @@ -281,10 +281,34 @@ func (in *NeutronSection) DeepCopy() *NeutronSection { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NovaCellOverrideSpec) DeepCopyInto(out *NovaCellOverrideSpec) { + *out = *in + in.NoVNCProxy.DeepCopyInto(&out.NoVNCProxy) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NovaCellOverrideSpec. +func (in *NovaCellOverrideSpec) DeepCopy() *NovaCellOverrideSpec { + if in == nil { + return nil + } + out := new(NovaCellOverrideSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NovaSection) DeepCopyInto(out *NovaSection) { *out = *in in.Template.DeepCopyInto(&out.Template) + in.APIOverride.DeepCopyInto(&out.APIOverride) + if in.CellOverride != nil { + in, out := &in.CellOverride, &out.CellOverride + *out = make(map[string]NovaCellOverrideSpec, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NovaSection. diff --git a/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml b/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml index 7c5fd74e4..147a06749 100644 --- a/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml +++ b/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml @@ -6756,6 +6756,213 @@ spec: type: object nova: properties: + apiOverride: + properties: + route: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + spec: + properties: + alternateBackends: + items: + properties: + kind: + enum: + - Service + - "" + type: string + name: + type: string + weight: + format: int32 + maximum: 256 + minimum: 0 + type: integer + type: object + maxItems: 3 + type: array + host: + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + path: + pattern: ^/ + type: string + port: + properties: + targetPort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - targetPort + type: object + subdomain: + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + properties: + caCertificate: + type: string + certificate: + type: string + destinationCACertificate: + type: string + insecureEdgeTerminationPolicy: + type: string + key: + type: string + termination: + enum: + - edge + - reencrypt + - passthrough + type: string + required: + - termination + type: object + to: + properties: + kind: + enum: + - Service + - "" + type: string + name: + type: string + weight: + format: int32 + maximum: 256 + minimum: 0 + type: integer + type: object + wildcardPolicy: + enum: + - None + - Subdomain + - "" + type: string + type: object + type: object + type: object + cellOverride: + additionalProperties: + properties: + noVNCProxy: + properties: + route: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + spec: + properties: + alternateBackends: + items: + properties: + kind: + enum: + - Service + - "" + type: string + name: + type: string + weight: + format: int32 + maximum: 256 + minimum: 0 + type: integer + type: object + maxItems: 3 + type: array + host: + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + path: + pattern: ^/ + type: string + port: + properties: + targetPort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - targetPort + type: object + subdomain: + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + properties: + caCertificate: + type: string + certificate: + type: string + destinationCACertificate: + type: string + insecureEdgeTerminationPolicy: + type: string + key: + type: string + termination: + enum: + - edge + - reencrypt + - passthrough + type: string + required: + - termination + type: object + to: + properties: + kind: + enum: + - Service + - "" + type: string + name: + type: string + weight: + format: int32 + maximum: 256 + minimum: 0 + type: integer + type: object + wildcardPolicy: + enum: + - None + - Subdomain + - "" + type: string + type: object + type: object + type: object + type: object + type: object enabled: default: true type: boolean @@ -6793,7 +7000,7 @@ spec: override: properties: service: - items: + additionalProperties: properties: endpointURL: type: string @@ -6839,7 +7046,7 @@ spec: type: string type: object type: object - type: array + type: object type: object replicas: default: 1 @@ -6973,7 +7180,7 @@ spec: override: properties: service: - items: + additionalProperties: properties: endpointURL: type: string @@ -7019,7 +7226,7 @@ spec: type: string type: object type: object - type: array + type: object type: object replicas: default: 1 @@ -7080,7 +7287,7 @@ spec: override: properties: service: - items: + additionalProperties: properties: endpointURL: type: string @@ -7126,7 +7333,7 @@ spec: type: string type: object type: object - type: array + type: object type: object replicas: default: 1 @@ -7230,7 +7437,7 @@ spec: override: properties: service: - items: + additionalProperties: properties: endpointURL: type: string @@ -7276,7 +7483,7 @@ spec: type: string type: object type: object - type: array + type: object type: object replicas: default: 1 diff --git a/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation.yaml b/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation.yaml index 3f5752735..df7b83c9b 100644 --- a/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation.yaml +++ b/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation.yaml @@ -104,20 +104,22 @@ spec: replicas: 1 secret: osp-secret nova: + apiOverride: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 + cellOverride: + cell0: + metadata: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 template: - apiServiceTemplate: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 secret: osp-secret - metadataServiceTemplate: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 manila: template: manilaAPI: diff --git a/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation_3replicas.yaml b/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation_3replicas.yaml index 908a58b2e..6649163b1 100644 --- a/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation_3replicas.yaml +++ b/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation_3replicas.yaml @@ -104,20 +104,22 @@ spec: replicas: 1 secret: osp-secret nova: + apiOverride: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 + cellOverride: + cell0: + metadata: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 template: - apiServiceTemplate: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 secret: osp-secret - metadataServiceTemplate: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 manila: template: manilaAPI: diff --git a/config/samples/core_v1beta1_openstackcontrolplane_network_isolation.yaml b/config/samples/core_v1beta1_openstackcontrolplane_network_isolation.yaml index d90467311..1421df693 100644 --- a/config/samples/core_v1beta1_openstackcontrolplane_network_isolation.yaml +++ b/config/samples/core_v1beta1_openstackcontrolplane_network_isolation.yaml @@ -106,20 +106,22 @@ spec: replicas: 1 secret: osp-secret nova: + apiOverride: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 + cellOverride: + cell0: + metadata: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 template: - apiServiceTemplate: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 secret: osp-secret - metadataServiceTemplate: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 manila: template: manilaAPI: diff --git a/config/samples/core_v1beta1_openstackcontrolplane_network_isolation_ceph.yaml b/config/samples/core_v1beta1_openstackcontrolplane_network_isolation_ceph.yaml index 143953694..aaece3488 100644 --- a/config/samples/core_v1beta1_openstackcontrolplane_network_isolation_ceph.yaml +++ b/config/samples/core_v1beta1_openstackcontrolplane_network_isolation_ceph.yaml @@ -136,20 +136,22 @@ spec: replicas: 1 secret: osp-secret nova: + apiOverride: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 + cellOverride: + cell0: + metadata: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 template: - apiServiceTemplate: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 secret: osp-secret - metadataServiceTemplate: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 manila: template: manilaAPI: diff --git a/pkg/openstack/nova.go b/pkg/openstack/nova.go index 6ff791b9d..ff7244a47 100644 --- a/pkg/openstack/nova.go +++ b/pkg/openstack/nova.go @@ -21,7 +21,9 @@ import ( "fmt" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" + "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" + "github.com/openstack-k8s-operators/lib-common/modules/common/service" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -48,6 +50,128 @@ func ReconcileNova(ctx context.Context, instance *corev1beta1.OpenStackControlPl return ctrl.Result{}, nil } + // Create service overrides to pass into the service CR + // and expose the public endpoint using a route per default. + // Any trailing path will be added on the service-operator level. + var endpoints = map[service.Endpoint]endpoint.Data{ + service.EndpointPublic: {}, + service.EndpointInternal: {}, + } + + apiServiceOverrides := map[string]service.OverrideSpec{} + serviceDetails := []ServiceDetails{} + + for endpointType := range endpoints { + sd := ServiceDetails{ + ServiceName: nova.Name, + Namespace: instance.Namespace, + Endpoint: endpointType, + ServiceOverrideSpec: instance.Spec.Nova.Template.APIServiceTemplate.Override.Service, + RouteOverrideSpec: instance.Spec.Nova.APIOverride.Route, + } + + svcOverride, ctrlResult, err := sd.CreateRouteAndServiceOverride(ctx, instance, helper) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + + serviceDetails = append( + serviceDetails, + sd, + ) + if svcOverride != nil { + apiServiceOverrides[string(endpointType)] = *svcOverride + } + + instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneServiceOverrideReadyCondition, corev1beta1.OpenStackControlPlaneServiceOverrideReadyMessage) + } + + // Create service overrides to pass into the service CR + // and expose the public endpoint using a route per default. + // Any trailing path will be added on the service-operator level. + var metadataEndpoints = map[service.Endpoint]endpoint.Data{ + service.EndpointInternal: {}, + } + metadataServiceOverrides := map[string]map[string]service.OverrideSpec{} + novncproxyServiceOverrides := map[string]map[string]service.OverrideSpec{} + + // cell service override + for cellName, template := range instance.Spec.Nova.Template.CellTemplates { + cellOverride := instance.Spec.Nova.CellOverride[cellName] + + for endpointType := range metadataEndpoints { + metadataServiceName := nova.Name + "-metadata" + if cellName != novav1.Cell0Name { + metadataServiceName = metadataServiceName + "-" + cellName + } + + metadataSD := ServiceDetails{ + ServiceName: metadataServiceName, + Namespace: instance.Namespace, + Endpoint: endpointType, + ServiceOverrideSpec: template.MetadataServiceTemplate.Override.Service, + RouteOverrideSpec: nil, + } + + metadataSVCOverride, ctrlResult, err := metadataSD.CreateRouteAndServiceOverride(ctx, instance, helper) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + + serviceDetails = append( + serviceDetails, + metadataSD, + ) + + if metadataServiceOverrides[cellName] == nil { + metadataServiceOverrides[cellName] = map[string]service.OverrideSpec{} + } + + if metadataSVCOverride != nil { + metadataServiceOverrides[cellName][string(endpointType)] = *metadataSVCOverride + } + } + + for endpointType := range endpoints { + // no novncproxy for cell0 + if cellName == novav1.Cell0Name { + break + } + novncProxySD := ServiceDetails{ + ServiceName: nova.Name + "-novncproxy" + "-" + cellName, + Namespace: instance.Namespace, + Endpoint: endpointType, + ServiceOverrideSpec: template.NoVNCProxyServiceTemplate.Override.Service, + RouteOverrideSpec: cellOverride.NoVNCProxy.Route, + } + + novncSVCOverride, ctrlResult, err := novncProxySD.CreateRouteAndServiceOverride(ctx, instance, helper) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + + serviceDetails = append( + serviceDetails, + novncProxySD, + ) + + if novncproxyServiceOverrides[cellName] == nil { + novncproxyServiceOverrides[cellName] = map[string]service.OverrideSpec{} + } + + if novncSVCOverride != nil { + novncproxyServiceOverrides[cellName][string(endpointType)] = *novncSVCOverride + } + } + } + instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneServiceOverrideReadyCondition, corev1beta1.OpenStackControlPlaneServiceOverrideReadyMessage) + helper.GetLogger().Info("Reconciling Nova", "Nova.Namespace", instance.Namespace, "Nova.Name", nova.Name) op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), nova, func() error { // 1) @@ -67,6 +191,17 @@ func ReconcileNova(ctx context.Context, instance *corev1beta1.OpenStackControlPl // we need to support either rabbitmq vhosts or deploy a separate // RabbitMQCluster per nova cell. instance.Spec.Nova.Template.DeepCopyInto(&nova.Spec) + nova.Spec.APIServiceTemplate.Override.Service = apiServiceOverrides + + for cellName, cellTemplate := range nova.Spec.CellTemplates { + if override, exist := metadataServiceOverrides[cellName]; exist { + cellTemplate.MetadataServiceTemplate.Override.Service = override + } + if override, exist := novncproxyServiceOverrides[cellName]; exist { + cellTemplate.NoVNCProxyServiceTemplate.Override.Service = override + } + nova.Spec.CellTemplates[cellName] = cellTemplate + } err := controllerutil.SetControllerReference(helper.GetBeforeObject(), nova, helper.GetScheme()) if err != nil { @@ -98,5 +233,17 @@ func ReconcileNova(ctx context.Context, instance *corev1beta1.OpenStackControlPl corev1beta1.OpenStackControlPlaneNovaReadyRunningMessage)) } + for _, sd := range serviceDetails { + // Add the service CR to the ownerRef list of the route to prevent the route being deleted + // before the service is deleted. Otherwise this can result cleanup issues which require + // the endpoint to be reachable. + // If ALL objects in the list have been deleted, this object will be garbage collected. + // https://github.com/kubernetes/apimachinery/blob/15d95c0b2af3f4fcf46dce24105e5fbb9379af5a/pkg/apis/meta/v1/types.go#L240-L247 + err = sd.AddOwnerRef(ctx, helper, nova) + if err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, nil }