diff --git a/apis/bases/core.openstack.org_openstackcontrolplanes.yaml b/apis/bases/core.openstack.org_openstackcontrolplanes.yaml index 18031d6ec..41514d937 100644 --- a/apis/bases/core.openstack.org_openstackcontrolplanes.yaml +++ b/apis/bases/core.openstack.org_openstackcontrolplanes.yaml @@ -2107,6 +2107,107 @@ spec: type: object glance: 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 enabled: default: true type: boolean diff --git a/apis/core/v1beta1/openstackcontrolplane_types.go b/apis/core/v1beta1/openstackcontrolplane_types.go index 9c3eae2ea..ad134a31d 100644 --- a/apis/core/v1beta1/openstackcontrolplane_types.go +++ b/apis/core/v1beta1/openstackcontrolplane_types.go @@ -233,6 +233,11 @@ type GlanceSection struct { //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Glance Service Template glancev1.GlanceSpec `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"` } // CinderSection defines the desired state of Cinder service diff --git a/apis/core/v1beta1/zz_generated.deepcopy.go b/apis/core/v1beta1/zz_generated.deepcopy.go index 96ee0d99d..70a69e7e6 100644 --- a/apis/core/v1beta1/zz_generated.deepcopy.go +++ b/apis/core/v1beta1/zz_generated.deepcopy.go @@ -105,6 +105,7 @@ func (in *GaleraSection) DeepCopy() *GaleraSection { func (in *GlanceSection) DeepCopyInto(out *GlanceSection) { *out = *in in.Template.DeepCopyInto(&out.Template) + in.APIOverride.DeepCopyInto(&out.APIOverride) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlanceSection. diff --git a/apis/go.mod b/apis/go.mod index f4284c55f..7ee3ce7fb 100644 --- a/apis/go.mod +++ b/apis/go.mod @@ -105,7 +105,7 @@ replace github.com/openstack-k8s-operators/lib-common/modules/common => github.c replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/stuggi/keystone-operator/api v0.0.0-20230816122109-152862232878 -replace github.com/openstack-k8s-operators/glance-operator/api => github.com/stuggi/glance-operator/api v0.0.0-20230809094131-22913c6b4f1c +replace github.com/openstack-k8s-operators/glance-operator/api => github.com/stuggi/glance-operator/api v0.0.0-20230816132821-d39a79afee8a replace github.com/openstack-k8s-operators/placement-operator/api => github.com/stuggi/placement-operator/api v0.0.0-20230816134701-bfcdc098dab0 diff --git a/apis/go.sum b/apis/go.sum index 5c0820e79..76cb966f1 100644 --- a/apis/go.sum +++ b/apis/go.sum @@ -177,8 +177,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stuggi/cinder-operator/api v0.0.0-20230816140403-a075c26418b4 h1:AvmYgD3dsdc+gQ772Uvtnm1/iyRXH4o6DcJyFzJMy60= github.com/stuggi/cinder-operator/api v0.0.0-20230816140403-a075c26418b4/go.mod h1:3xQfQGmIzZeufZOpAuOe9i0pTSoxYvz0JsdAJjK2Kno= -github.com/stuggi/glance-operator/api v0.0.0-20230809094131-22913c6b4f1c h1:u4wDtY6wQNDV1RxhMfOwd85/lG5SzVm61Jemm9dHf0w= -github.com/stuggi/glance-operator/api v0.0.0-20230809094131-22913c6b4f1c/go.mod h1:2Dfm01p6uGeQF8rsMKz6qQRPxZCLNLKuT5Flju5jSB4= +github.com/stuggi/glance-operator/api v0.0.0-20230816132821-d39a79afee8a h1:sttkHGsZRdsXfKgVJA4LOc5wJOboeZ3U7YpDROUFinM= +github.com/stuggi/glance-operator/api v0.0.0-20230816132821-d39a79afee8a/go.mod h1:NXBA6L/qHCAxh5onMhv88fT1c/pZ3UXbr1eHr62CHQ8= github.com/stuggi/heat-operator/api v0.0.0-20230816145353-b17691c6b5f0 h1:NcsIDs5+Clt3DIFWlbhyBAAuslkY2ZF2Wpp6tT5vHa8= github.com/stuggi/heat-operator/api v0.0.0-20230816145353-b17691c6b5f0/go.mod h1:N3SRs4S/P1qqqjuje/6LupaqN5swXDDUlyRp9jSAJs8= github.com/stuggi/horizon-operator/api v0.0.0-20230816150035-5dfe29c00383 h1:FRPiUDdHOIKVT6xtv6gJucl/YlReAz0CiuhAGQa+PAQ= diff --git a/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml b/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml index 18031d6ec..41514d937 100644 --- a/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml +++ b/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml @@ -2107,6 +2107,107 @@ spec: type: object glance: 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 enabled: default: true type: boolean diff --git a/config/manifests/bases/openstack-operator.clusterserviceversion.yaml b/config/manifests/bases/openstack-operator.clusterserviceversion.yaml index 06e7017b4..e1e8dfd42 100644 --- a/config/manifests/bases/openstack-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/openstack-operator.clusterserviceversion.yaml @@ -81,6 +81,24 @@ spec: path: glance.enabled x-descriptors: - urn:alm:descriptor:com.tectonic.ui:booleanSwitch + - description: IPAddressPool expose VIP via MetalLB on the IPAddressPool + displayName: IPAddress Pool + path: glance.externalEndpoints[0].ipAddressPool + - description: LoadBalancerIPs, request given IPs from the pool if available. + Using a list to allow dual stack (IPv4/IPv6) support + displayName: Load Balancer IPs + path: glance.externalEndpoints[0].loadBalancerIPs + - description: SharedIP if true, VIP/VIPs get shared with multiple services + displayName: Shared IP + path: glance.externalEndpoints[0].sharedIP + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:booleanSwitch + - description: SharedIPKey specifies the sharing key which gets set as the annotation + on the LoadBalancer service. Services which share the same VIP must have + the same SharedIPKey. Defaults to the IPAddressPool if SharedIP is true, + but no SharedIPKey specified. + displayName: Shared IPKey + path: glance.externalEndpoints[0].sharedIPKey - description: Template - Overrides to use when creating the Glance Service displayName: Template path: glance.template diff --git a/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation.yaml b/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation.yaml index a69b70c9b..55ad1ae98 100644 --- a/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation.yaml +++ b/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation.yaml @@ -38,16 +38,17 @@ spec: - storage replicas: 0 # backend needs to be configured glance: + apiOverride: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 template: databaseInstance: openstack storageClass: "" storageRequest: 10G glanceAPIInternal: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 networkAttachments: - storage glanceAPIExternal: 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 13f130306..7586a86aa 100644 --- a/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation_3replicas.yaml +++ b/config/samples/core_v1beta1_openstackcontrolplane_galera_network_isolation_3replicas.yaml @@ -38,16 +38,17 @@ spec: - storage replicas: 0 # backend needs to be configured glance: + apiOverride: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 template: databaseInstance: openstack storageClass: "" storageRequest: 10G glanceAPIInternal: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 networkAttachments: - storage glanceAPIExternal: diff --git a/config/samples/core_v1beta1_openstackcontrolplane_network_isolation.yaml b/config/samples/core_v1beta1_openstackcontrolplane_network_isolation.yaml index ca3887b17..fe457ef6f 100644 --- a/config/samples/core_v1beta1_openstackcontrolplane_network_isolation.yaml +++ b/config/samples/core_v1beta1_openstackcontrolplane_network_isolation.yaml @@ -38,16 +38,22 @@ spec: - storage replicas: 0 # backend needs to be configured glance: + apiOverride: + route: {} template: databaseInstance: openstack storageClass: "" storageRequest: 10G glanceAPIInternal: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 + override: + service: + metadata: + annotations: + metallb.universe.tf/address-pool: internalapi + metallb.universe.tf/allow-shared-ip: internalapi + metallb.universe.tf/loadBalancerIPs: 172.17.0.80 + spec: + type: LoadBalancer networkAttachments: - storage glanceAPIExternal: diff --git a/config/samples/core_v1beta1_openstackcontrolplane_network_isolation_ceph.yaml b/config/samples/core_v1beta1_openstackcontrolplane_network_isolation_ceph.yaml index 38131c9bf..97fdf4b59 100644 --- a/config/samples/core_v1beta1_openstackcontrolplane_network_isolation_ceph.yaml +++ b/config/samples/core_v1beta1_openstackcontrolplane_network_isolation_ceph.yaml @@ -72,6 +72,12 @@ spec: - storage replicas: 0 # backend needs to be configured glance: + apiOverride: + externalEndpoints: + - endpoint: internal + ipAddressPool: internalapi + loadBalancerIPs: + - 172.17.0.80 template: databaseInstance: openstack customServiceConfig: | @@ -87,11 +93,6 @@ spec: storageClass: "" storageRequest: 10G glanceAPIInternal: - externalEndpoints: - - endpoint: internal - ipAddressPool: internalapi - loadBalancerIPs: - - 172.17.0.80 networkAttachments: - storage glanceAPIExternal: diff --git a/go.mod b/go.mod index 2c4416447..76710c4f7 100644 --- a/go.mod +++ b/go.mod @@ -117,7 +117,7 @@ replace github.com/openstack-k8s-operators/lib-common/modules/common => github.c replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/stuggi/keystone-operator/api v0.0.0-20230816122109-152862232878 -replace github.com/openstack-k8s-operators/glance-operator/api => github.com/stuggi/glance-operator/api v0.0.0-20230809094131-22913c6b4f1c +replace github.com/openstack-k8s-operators/glance-operator/api => github.com/stuggi/glance-operator/api v0.0.0-20230816132821-d39a79afee8a replace github.com/openstack-k8s-operators/placement-operator/api => github.com/stuggi/placement-operator/api v0.0.0-20230816134701-bfcdc098dab0 diff --git a/go.sum b/go.sum index fe20313aa..cac41958c 100644 --- a/go.sum +++ b/go.sum @@ -194,8 +194,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stuggi/cinder-operator/api v0.0.0-20230816140403-a075c26418b4 h1:AvmYgD3dsdc+gQ772Uvtnm1/iyRXH4o6DcJyFzJMy60= github.com/stuggi/cinder-operator/api v0.0.0-20230816140403-a075c26418b4/go.mod h1:3xQfQGmIzZeufZOpAuOe9i0pTSoxYvz0JsdAJjK2Kno= -github.com/stuggi/glance-operator/api v0.0.0-20230809094131-22913c6b4f1c h1:u4wDtY6wQNDV1RxhMfOwd85/lG5SzVm61Jemm9dHf0w= -github.com/stuggi/glance-operator/api v0.0.0-20230809094131-22913c6b4f1c/go.mod h1:2Dfm01p6uGeQF8rsMKz6qQRPxZCLNLKuT5Flju5jSB4= +github.com/stuggi/glance-operator/api v0.0.0-20230816132821-d39a79afee8a h1:sttkHGsZRdsXfKgVJA4LOc5wJOboeZ3U7YpDROUFinM= +github.com/stuggi/glance-operator/api v0.0.0-20230816132821-d39a79afee8a/go.mod h1:NXBA6L/qHCAxh5onMhv88fT1c/pZ3UXbr1eHr62CHQ8= github.com/stuggi/heat-operator/api v0.0.0-20230816145353-b17691c6b5f0 h1:NcsIDs5+Clt3DIFWlbhyBAAuslkY2ZF2Wpp6tT5vHa8= github.com/stuggi/heat-operator/api v0.0.0-20230816145353-b17691c6b5f0/go.mod h1:N3SRs4S/P1qqqjuje/6LupaqN5swXDDUlyRp9jSAJs8= github.com/stuggi/horizon-operator/api v0.0.0-20230816150035-5dfe29c00383 h1:FRPiUDdHOIKVT6xtv6gJucl/YlReAz0CiuhAGQa+PAQ= diff --git a/pkg/openstack/glance.go b/pkg/openstack/glance.go index 5decc025b..2266b1bd0 100644 --- a/pkg/openstack/glance.go +++ b/pkg/openstack/glance.go @@ -5,13 +5,16 @@ 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" glancev1 "github.com/openstack-k8s-operators/glance-operator/api/v1beta1" corev1beta1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" ) @@ -32,9 +35,57 @@ func ReconcileGlance(ctx context.Context, instance *corev1beta1.OpenStackControl 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: {}, + } + + serviceOverrides := map[string]service.OverrideSpec{} + serviceDetails := []ServiceDetails{} + + serviceOverrideSpec := map[string]service.OverrideSpec{} + if instance.Spec.Glance.Template.GlanceAPIExternal.Override.Service != nil { + serviceOverrideSpec[string(service.EndpointPublic)] = *instance.Spec.Glance.Template.GlanceAPIExternal.Override.Service + } + if instance.Spec.Glance.Template.GlanceAPIInternal.Override.Service != nil { + serviceOverrideSpec[string(service.EndpointInternal)] = *instance.Spec.Glance.Template.GlanceAPIInternal.Override.Service + } + + for endpointType := range endpoints { + sd := ServiceDetails{ + ServiceName: glance.Name, + Namespace: instance.Namespace, + Endpoint: endpointType, + ServiceOverrideSpec: serviceOverrideSpec, + RouteOverrideSpec: instance.Spec.Glance.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 { + serviceOverrides[string(endpointType)] = *svcOverride + } + } + instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneServiceOverrideReadyCondition, corev1beta1.OpenStackControlPlaneServiceOverrideReadyMessage) + helper.GetLogger().Info("Reconciling Glance", "Glance.Namespace", instance.Namespace, "Glance.Name", "glance") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), glance, func() error { instance.Spec.Glance.Template.DeepCopyInto(&glance.Spec) + glance.Spec.GlanceAPIExternal.Override.Service = ptr.To(serviceOverrides[string(service.EndpointPublic)]) + glance.Spec.GlanceAPIInternal.Override.Service = ptr.To(serviceOverrides[string(service.EndpointInternal)]) + if glance.Spec.Secret == "" { glance.Spec.Secret = instance.Spec.Secret } @@ -89,6 +140,18 @@ func ReconcileGlance(ctx context.Context, instance *corev1beta1.OpenStackControl corev1beta1.OpenStackControlPlaneGlanceReadyRunningMessage)) } + 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, glance) + if err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, nil }