From 099a8bde8f24d655a22d5e3eb2591591dec3a0ae Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 12 Dec 2023 14:27:17 -0500 Subject: [PATCH] Add initial OpenStackVersionUpdate CRD/Controller --- Makefile | 3 + PROJECT | 4 + ....openstack.org_openstackcontrolplanes.yaml | 367 +++++------ .../core.openstack.org_openstackversions.yaml | 553 +++++++++++++++++ apis/core/v1beta1/conditions.go | 92 ++- .../v1beta1/openstackcontrolplane_types.go | 56 +- .../v1beta1/openstackcontrolplane_webhook.go | 12 - apis/core/v1beta1/openstackversion_types.go | 153 ++++- apis/core/v1beta1/openstackversion_webhook.go | 134 ++++ apis/core/v1beta1/zz_generated.deepcopy.go | 577 +++++++++++++++++- apis/go.mod | 3 + apis/go.sum | 4 +- cmd/csv-merger/csv-merger.go | 2 +- ....openstack.org_openstackcontrolplanes.yaml | 367 +++++------ .../core.openstack.org_openstackversions.yaml | 553 +++++++++++++++++ config/manager/manager.yaml | 3 + ...nstack-operator.clusterserviceversion.yaml | 21 + config/rbac/role.yaml | 26 + ...ta1_openstackcontrolplane_lightweight.yaml | 195 ------ .../core_v1beta1_openstackversion.yaml | 19 +- config/webhook/manifests.yaml | 40 ++ .../core/openstackcontrolplane_controller.go | 125 +++- .../core/openstackversion_controller.go | 251 +++++++- go.mod | 3 + go.sum | 4 +- hack/export_related_images.sh | 82 +++ hack/fake_minor_update.sh | 9 + main.go | 26 +- pkg/openstack/barbican.go | 14 +- pkg/openstack/cinder.go | 39 +- pkg/openstack/designate.go | 40 +- pkg/openstack/dnsmasq.go | 6 +- pkg/openstack/galera.go | 15 +- pkg/openstack/glance.go | 8 +- pkg/openstack/heat.go | 16 +- pkg/openstack/horizon.go | 9 +- pkg/openstack/ironic.go | 20 +- pkg/openstack/keystone.go | 8 +- pkg/openstack/manila.go | 35 +- pkg/openstack/memcached.go | 13 +- pkg/openstack/neutron.go | 9 +- pkg/openstack/nova.go | 16 +- pkg/openstack/octavia.go | 20 +- pkg/openstack/openstackclient.go | 7 +- pkg/openstack/ovn.go | 69 ++- pkg/openstack/placement.go | 6 +- pkg/openstack/rabbitmq.go | 43 +- pkg/openstack/redis.go | 12 +- pkg/openstack/swift.go | 20 +- pkg/openstack/telemetry.go | 35 +- pkg/openstack/version.go | 212 +++++++ tests/functional/base_test.go | 46 ++ .../openstackoperator_controller_test.go | 233 +++++++ .../openstackversion_controller_test.go | 141 +++++ tests/functional/suite_test.go | 11 + 55 files changed, 3956 insertions(+), 831 deletions(-) create mode 100644 apis/bases/core.openstack.org_openstackversions.yaml create mode 100644 apis/core/v1beta1/openstackversion_webhook.go create mode 100644 config/crd/bases/core.openstack.org_openstackversions.yaml delete mode 100644 config/samples/core_v1beta1_openstackcontrolplane_lightweight.yaml create mode 100755 hack/export_related_images.sh create mode 100644 hack/fake_minor_update.sh create mode 100644 pkg/openstack/version.go create mode 100644 tests/functional/openstackversion_controller_test.go diff --git a/Makefile b/Makefile index e9ebd171d..7d1914eb9 100644 --- a/Makefile +++ b/Makefile @@ -134,6 +134,7 @@ golangci-lint: .PHONY: test test: manifests generate gowork fmt vet envtest ginkgo ## Run tests. + source hack/export_related_images.sh && \ KUBEBUILDER_ASSETS="$(shell $(ENVTEST) -v debug --bin-dir $(LOCALBIN) use $(ENVTEST_K8S_VERSION) -p path)" \ OPERATOR_TEMPLATES="$(PWD)/templates" \ $(GINKGO) --trace --cover --coverpkg=../../pkg/openstack,../../pkg/openstackclient,../../pkg/util,../../controllers,../../apis/client/v1beta1,../../apis/core/v1beta1 --coverprofile cover.out --covermode=atomic ${PROC_CMD} $(GINKGO_ARGS) ./tests/... ./apis/client/... @@ -151,6 +152,7 @@ run: export HEALTH_PORT?=8081 run: export ENABLE_WEBHOOKS?=false run: manifests generate fmt vet ## Run a controller from your host. /bin/bash hack/clean_local_webhook.sh + source hack/export_related_images.sh && \ go run ./main.go -metrics-bind-address ":$(METRICS_PORT)" -health-probe-bind-address ":$(HEALTH_PORT)" .PHONY: docker-build @@ -389,6 +391,7 @@ run-with-webhook: export METRICS_PORT?=8080 run-with-webhook: export HEALTH_PORT?=8081 run-with-webhook: manifests generate fmt vet ## Run a controller from your host. /bin/bash hack/configure_local_webhook.sh + source hack/export_related_images.sh && \ go run ./main.go -metrics-bind-address ":$(METRICS_PORT)" -health-probe-bind-address ":$(HEALTH_PORT)" # refresh the bundle extra data based on go.mod entries diff --git a/PROJECT b/PROJECT index afbb95eb2..27e77b65b 100644 --- a/PROJECT +++ b/PROJECT @@ -42,4 +42,8 @@ resources: kind: OpenStackVersion path: github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1 version: v1beta1 + webhooks: + defaulting: true + validation: true + webhookVersion: v1 version: "3" diff --git a/apis/bases/core.openstack.org_openstackcontrolplanes.yaml b/apis/bases/core.openstack.org_openstackcontrolplanes.yaml index ad5c1c3ab..7c79814d2 100644 --- a/apis/bases/core.openstack.org_openstackcontrolplanes.yaml +++ b/apis/bases/core.openstack.org_openstackcontrolplanes.yaml @@ -156,8 +156,6 @@ spec: properties: barbicanAPI: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -285,13 +283,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object barbicanKeystoneListener: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -347,13 +341,9 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object barbicanWorker: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -409,8 +399,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object customServiceConfig: type: string @@ -580,8 +568,6 @@ spec: properties: cinderAPI: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -701,13 +687,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object cinderBackup: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -758,13 +740,9 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object cinderScheduler: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -815,14 +793,10 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object cinderVolumes: additionalProperties: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -874,8 +848,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object type: object customServiceConfig: @@ -1825,8 +1797,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -1955,8 +1925,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateBackendbind9: properties: @@ -1966,8 +1934,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2045,8 +2011,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateCentral: properties: @@ -2056,8 +2020,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2135,8 +2097,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateMdns: properties: @@ -2146,8 +2106,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2225,8 +2183,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateProducer: properties: @@ -2236,8 +2192,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2315,13 +2269,9 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateUnbound: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2379,8 +2329,6 @@ spec: type: object serviceAccount: type: string - required: - - containerImage type: object designateWorker: properties: @@ -2390,8 +2338,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2469,8 +2415,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object nodeSelector: additionalProperties: @@ -3405,8 +3349,6 @@ spec: host: type: string type: object - containerImage: - type: string customServiceConfig: type: string disableNonTLSListeners: @@ -3437,7 +3379,6 @@ spec: type: string type: object required: - - containerImage - replicas - secret - storageClass @@ -3560,8 +3501,6 @@ spec: type: boolean template: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -4561,7 +4500,6 @@ spec: storageRequest: type: string required: - - containerImage - databaseInstance - glanceAPIs - imageCache @@ -4803,8 +4741,6 @@ spec: type: object heatAPI: properties: - containerImage: - type: string customServiceConfig: type: string defaultConfigOverwrite: @@ -4921,13 +4857,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object heatCfnAPI: properties: - containerImage: - type: string customServiceConfig: type: string defaultConfigOverwrite: @@ -5044,13 +4976,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object heatEngine: properties: - containerImage: - type: string customServiceConfig: type: string defaultConfigOverwrite: @@ -5098,8 +5026,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object memcachedInstance: default: memcached @@ -5254,8 +5180,6 @@ spec: type: boolean template: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -6125,7 +6049,6 @@ spec: type: string type: object required: - - containerImage - memcachedInstance - secret type: object @@ -6361,21 +6284,6 @@ spec: additionalProperties: type: string type: object - images: - properties: - api: - type: string - conductor: - type: string - inspector: - type: string - ironicPythonAgent: - type: string - neutronAgent: - type: string - pxe: - type: string - type: object ironicAPI: properties: customServiceConfig: @@ -6978,8 +6886,6 @@ spec: adminUser: default: admin type: string - containerImage: - type: string customServiceConfig: type: string databaseAccount: @@ -7143,7 +7049,6 @@ spec: default: false type: boolean required: - - containerImage - databaseInstance - memcachedInstance - rabbitMqClusterName @@ -8045,8 +7950,6 @@ spec: type: array manilaAPI: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -8168,13 +8071,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object manilaScheduler: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -8227,14 +8126,10 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object manilaShares: additionalProperties: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -8287,8 +8182,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object type: object memcachedInstance: @@ -8332,8 +8225,6 @@ spec: templates: additionalProperties: properties: - containerImage: - type: string replicas: default: 1 format: int32 @@ -8345,8 +8236,6 @@ spec: secretName: type: string type: object - required: - - containerImage type: object type: object type: object @@ -8463,8 +8352,6 @@ spec: type: boolean template: properties: - containerImage: - type: string customServiceConfig: type: string databaseAccount: @@ -9374,7 +9261,6 @@ spec: type: object type: object required: - - containerImage - databaseInstance - memcachedInstance - rabbitMqClusterName @@ -10505,8 +10391,6 @@ spec: type: object octaviaAPI: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -10662,7 +10546,6 @@ spec: transportURLSecret: type: string required: - - containerImage - databaseInstance - secret - serviceAccount @@ -10691,8 +10574,6 @@ spec: - name type: object type: array - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -10819,8 +10700,6 @@ spec: - name type: object type: array - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -10947,8 +10826,6 @@ spec: - name type: object type: array - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -11193,10 +11070,6 @@ spec: additionalProperties: type: string type: object - ovnContainerImage: - type: string - ovsContainerImage: - type: string resources: properties: claims: @@ -11235,15 +11108,10 @@ spec: secretName: type: string type: object - required: - - ovnContainerImage - - ovsContainerImage type: object ovnDBCluster: additionalProperties: properties: - containerImage: - type: string dbType: default: NB pattern: ^NB|SB$ @@ -11318,15 +11186,12 @@ spec: type: string type: object required: - - containerImage - dbType - storageRequest type: object type: object ovnNorthd: properties: - containerImage: - type: string logLevel: default: info type: string @@ -11384,8 +11249,6 @@ spec: secretName: type: string type: object - required: - - containerImage type: object type: object type: object @@ -11502,8 +11365,6 @@ spec: type: boolean template: properties: - containerImage: - type: string customServiceConfig: type: string databaseAccount: @@ -11646,7 +11507,6 @@ spec: type: string type: object required: - - containerImage - databaseInstance - secret type: object @@ -12029,16 +11889,6 @@ spec: format: int32 minimum: 0 type: integer - image: - type: string - imagePullSecrets: - items: - properties: - name: - type: string - type: object - x-kubernetes-map-type: atomic - type: array override: properties: service: @@ -15694,8 +15544,6 @@ spec: type: object type: object service: - default: - type: ClusterIP properties: annotations: additionalProperties: @@ -15758,8 +15606,6 @@ spec: templates: additionalProperties: properties: - containerImage: - type: string replicas: default: 1 format: int32 @@ -15771,8 +15617,6 @@ spec: secretName: type: string type: object - required: - - containerImage type: object type: object type: object @@ -15908,8 +15752,6 @@ spec: ceilometerEnabled: default: false type: boolean - containerImageProxy: - type: string defaultConfigOverwrite: additionalProperties: type: string @@ -16016,7 +15858,6 @@ spec: type: string type: object required: - - containerImageProxy - memcachedServers - rabbitMqClusterName - replicas @@ -16025,8 +15866,6 @@ spec: type: object swiftRing: properties: - containerImage: - type: string minPartHours: default: 1 format: int64 @@ -16048,21 +15887,12 @@ spec: type: string type: object required: - - containerImage - minPartHours - partPower - ringReplicas type: object swiftStorage: properties: - containerImageAccount: - type: string - containerImageContainer: - type: string - containerImageObject: - type: string - containerImageProxy: - type: string containerSharderEnabled: default: false type: boolean @@ -16089,10 +15919,6 @@ spec: default: 10Gi type: string required: - - containerImageAccount - - containerImageContainer - - containerImageObject - - containerImageProxy - memcachedServers - replicas - storageClass @@ -16435,8 +16261,6 @@ spec: properties: aodh: properties: - apiImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -16449,10 +16273,6 @@ spec: additionalProperties: type: string type: object - evaluatorImage: - type: string - listenerImage: - type: string memcachedInstance: default: memcached type: string @@ -16460,8 +16280,6 @@ spec: items: type: string type: array - notifierImage: - type: string override: properties: service: @@ -16554,12 +16372,8 @@ spec: type: string type: object required: - - apiImage - databaseInstance - - evaluatorImage - - listenerImage - memcachedInstance - - notifierImage - secret type: object enabled: @@ -16582,10 +16396,6 @@ spec: type: object ceilometer: properties: - centralImage: - type: string - computeImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -16596,14 +16406,10 @@ spec: enabled: default: true type: boolean - ipmiImage: - type: string networkAttachmentDefinitions: items: type: string type: array - notificationImage: - type: string passwordSelector: default: service: CeilometerPassword @@ -16615,8 +16421,6 @@ spec: default: CeilometerPassword type: string type: object - proxyImage: - type: string rabbitMqClusterName: default: rabbitmq type: string @@ -16625,8 +16429,6 @@ spec: serviceUser: default: ceilometer type: string - sgCoreImage: - type: string tls: properties: caBundleSecretName: @@ -16635,13 +16437,7 @@ spec: type: string type: object required: - - centralImage - - computeImage - - ipmiImage - - notificationImage - - proxyImage - secret - - sgCoreImage type: object logging: properties: @@ -17443,6 +17239,169 @@ spec: - type type: object type: array + containerImages: + properties: + agentImage: + type: string + ansibleeeImage: + type: string + aodhAPIImage: + type: string + aodhEvaluatorImage: + type: string + aodhListenerImage: + type: string + aodhNotifierImage: + type: string + apacheImage: + type: string + barbicanAPIImage: + type: string + barbicanKeystoneListenerImage: + type: string + barbicanWorkerImage: + type: string + ceilometerCentralImage: + type: string + ceilometerComputeImage: + type: string + ceilometerIpmiImage: + type: string + ceilometerNotificationImage: + type: string + ceilometerSgcoreImage: + type: string + cinderAPIImage: + type: string + cinderBackupImage: + type: string + cinderSchedulerImage: + type: string + cinderVolumeImages: + additionalProperties: + type: string + type: object + designateAPIImage: + type: string + designateBackendbind9Image: + type: string + designateCentralImage: + type: string + designateMdnsImage: + type: string + designateProducerImage: + type: string + designateUnboundImage: + type: string + designateWorkerImage: + type: string + edpmFrrImage: + type: string + edpmIscsidImage: + type: string + edpmLogrotateCrondImage: + type: string + edpmNeutronMetadataAgentImage: + type: string + edpmNeutronSriovAgentImage: + type: string + edpmNodeExporterImage: + type: string + edpmOvnBgpAgentImage: + type: string + glanceAPIImage: + type: string + heatAPIImage: + type: string + heatCfnapiImage: + type: string + heatEngineImage: + type: string + horizonImage: + type: string + infraDnsmasqImage: + type: string + infraMemcachedImage: + type: string + infraRedisImage: + type: string + ironicAPIImage: + type: string + ironicConductorImage: + type: string + ironicInspectorImage: + type: string + ironicNeutronAgentImage: + type: string + ironicPxeImage: + type: string + ironicPythonAgentImage: + type: string + keystoneAPIImage: + type: string + manilaAPIImage: + type: string + manilaSchedulerImage: + type: string + manilaShareImages: + additionalProperties: + type: string + type: object + mariadbImage: + type: string + neutronAPIImage: + type: string + novaAPIImage: + type: string + novaComputeImage: + type: string + novaConductorImage: + type: string + novaNovncImage: + type: string + novaSchedulerImage: + type: string + octaviaAPIImage: + type: string + octaviaHealthmanagerImage: + type: string + octaviaHousekeepingImage: + type: string + octaviaWorkerImage: + type: string + openstackClientImage: + type: string + osContainerImage: + type: string + ovnControllerImage: + type: string + ovnControllerOvsImage: + type: string + ovnNbDbclusterImage: + type: string + ovnNorthdImage: + type: string + ovnSbDbclusterImage: + type: string + placementAPIImage: + type: string + rabbitmqImage: + type: string + swiftAccountImage: + type: string + swiftContainerImage: + type: string + swiftObjectImage: + type: string + swiftProxyImage: + type: string + telemetryNodeExporterImage: + type: string + type: object + deployedOVNVersion: + type: string + deployedVersion: + type: string tls: properties: caBundleSecretName: diff --git a/apis/bases/core.openstack.org_openstackversions.yaml b/apis/bases/core.openstack.org_openstackversions.yaml new file mode 100644 index 000000000..84205f3b9 --- /dev/null +++ b/apis/bases/core.openstack.org_openstackversions.yaml @@ -0,0 +1,553 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: openstackversions.core.openstack.org +spec: + group: core.openstack.org + names: + kind: OpenStackVersion + listKind: OpenStackVersionList + plural: openstackversions + singular: openstackversion + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetVersion + name: Target Version + type: string + - jsonPath: .status.availableVersion + name: Available Version + type: string + - jsonPath: .status.deployedVersion + name: Deployed Version + type: string + name: v1beta1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + customContainerImages: + properties: + agentImage: + type: string + ansibleeeImage: + type: string + aodhAPIImage: + type: string + aodhEvaluatorImage: + type: string + aodhListenerImage: + type: string + aodhNotifierImage: + type: string + apacheImage: + type: string + barbicanAPIImage: + type: string + barbicanKeystoneListenerImage: + type: string + barbicanWorkerImage: + type: string + ceilometerCentralImage: + type: string + ceilometerComputeImage: + type: string + ceilometerIpmiImage: + type: string + ceilometerNotificationImage: + type: string + ceilometerSgcoreImage: + type: string + cinderAPIImage: + type: string + cinderBackupImage: + type: string + cinderSchedulerImage: + type: string + cinderVolumeImages: + additionalProperties: + type: string + type: object + designateAPIImage: + type: string + designateBackendbind9Image: + type: string + designateCentralImage: + type: string + designateMdnsImage: + type: string + designateProducerImage: + type: string + designateUnboundImage: + type: string + designateWorkerImage: + type: string + edpmFrrImage: + type: string + edpmIscsidImage: + type: string + edpmLogrotateCrondImage: + type: string + edpmNeutronMetadataAgentImage: + type: string + edpmNeutronSriovAgentImage: + type: string + edpmNodeExporterImage: + type: string + edpmOvnBgpAgentImage: + type: string + glanceAPIImage: + type: string + heatAPIImage: + type: string + heatCfnapiImage: + type: string + heatEngineImage: + type: string + horizonImage: + type: string + infraDnsmasqImage: + type: string + infraMemcachedImage: + type: string + infraRedisImage: + type: string + ironicAPIImage: + type: string + ironicConductorImage: + type: string + ironicInspectorImage: + type: string + ironicNeutronAgentImage: + type: string + ironicPxeImage: + type: string + ironicPythonAgentImage: + type: string + keystoneAPIImage: + type: string + manilaAPIImage: + type: string + manilaSchedulerImage: + type: string + manilaShareImages: + additionalProperties: + type: string + type: object + mariadbImage: + type: string + neutronAPIImage: + type: string + novaAPIImage: + type: string + novaComputeImage: + type: string + novaConductorImage: + type: string + novaNovncImage: + type: string + novaSchedulerImage: + type: string + octaviaAPIImage: + type: string + octaviaHealthmanagerImage: + type: string + octaviaHousekeepingImage: + type: string + octaviaWorkerImage: + type: string + openstackClientImage: + type: string + osContainerImage: + type: string + ovnControllerImage: + type: string + ovnControllerOvsImage: + type: string + ovnNbDbclusterImage: + type: string + ovnNorthdImage: + type: string + ovnSbDbclusterImage: + type: string + placementAPIImage: + type: string + rabbitmqImage: + type: string + swiftAccountImage: + type: string + swiftContainerImage: + type: string + swiftObjectImage: + type: string + swiftProxyImage: + type: string + telemetryNodeExporterImage: + type: string + type: object + targetVersion: + type: string + required: + - targetVersion + type: object + status: + properties: + availableVersion: + type: string + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + severity: + type: string + status: + type: string + type: + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + containerImageVersionDefaults: + additionalProperties: + properties: + agentImage: + type: string + ansibleeeImage: + type: string + aodhAPIImage: + type: string + aodhEvaluatorImage: + type: string + aodhListenerImage: + type: string + aodhNotifierImage: + type: string + apacheImage: + type: string + barbicanAPIImage: + type: string + barbicanKeystoneListenerImage: + type: string + barbicanWorkerImage: + type: string + ceilometerCentralImage: + type: string + ceilometerComputeImage: + type: string + ceilometerIpmiImage: + type: string + ceilometerNotificationImage: + type: string + ceilometerSgcoreImage: + type: string + cinderAPIImage: + type: string + cinderBackupImage: + type: string + cinderSchedulerImage: + type: string + cinderVolumeImage: + type: string + designateAPIImage: + type: string + designateBackendbind9Image: + type: string + designateCentralImage: + type: string + designateMdnsImage: + type: string + designateProducerImage: + type: string + designateUnboundImage: + type: string + designateWorkerImage: + type: string + edpmFrrImage: + type: string + edpmIscsidImage: + type: string + edpmLogrotateCrondImage: + type: string + edpmNeutronMetadataAgentImage: + type: string + edpmNeutronSriovAgentImage: + type: string + edpmNodeExporterImage: + type: string + edpmOvnBgpAgentImage: + type: string + glanceAPIImage: + type: string + heatAPIImage: + type: string + heatCfnapiImage: + type: string + heatEngineImage: + type: string + horizonImage: + type: string + infraDnsmasqImage: + type: string + infraMemcachedImage: + type: string + infraRedisImage: + type: string + ironicAPIImage: + type: string + ironicConductorImage: + type: string + ironicInspectorImage: + type: string + ironicNeutronAgentImage: + type: string + ironicPxeImage: + type: string + ironicPythonAgentImage: + type: string + keystoneAPIImage: + type: string + manilaAPIImage: + type: string + manilaSchedulerImage: + type: string + manilaShareImage: + type: string + mariadbImage: + type: string + neutronAPIImage: + type: string + novaAPIImage: + type: string + novaComputeImage: + type: string + novaConductorImage: + type: string + novaNovncImage: + type: string + novaSchedulerImage: + type: string + octaviaAPIImage: + type: string + octaviaHealthmanagerImage: + type: string + octaviaHousekeepingImage: + type: string + octaviaWorkerImage: + type: string + openstackClientImage: + type: string + osContainerImage: + type: string + ovnControllerImage: + type: string + ovnControllerOvsImage: + type: string + ovnNbDbclusterImage: + type: string + ovnNorthdImage: + type: string + ovnSbDbclusterImage: + type: string + placementAPIImage: + type: string + rabbitmqImage: + type: string + swiftAccountImage: + type: string + swiftContainerImage: + type: string + swiftObjectImage: + type: string + swiftProxyImage: + type: string + telemetryNodeExporterImage: + type: string + type: object + type: object + containerImages: + properties: + agentImage: + type: string + ansibleeeImage: + type: string + aodhAPIImage: + type: string + aodhEvaluatorImage: + type: string + aodhListenerImage: + type: string + aodhNotifierImage: + type: string + apacheImage: + type: string + barbicanAPIImage: + type: string + barbicanKeystoneListenerImage: + type: string + barbicanWorkerImage: + type: string + ceilometerCentralImage: + type: string + ceilometerComputeImage: + type: string + ceilometerIpmiImage: + type: string + ceilometerNotificationImage: + type: string + ceilometerSgcoreImage: + type: string + cinderAPIImage: + type: string + cinderBackupImage: + type: string + cinderSchedulerImage: + type: string + cinderVolumeImages: + additionalProperties: + type: string + type: object + designateAPIImage: + type: string + designateBackendbind9Image: + type: string + designateCentralImage: + type: string + designateMdnsImage: + type: string + designateProducerImage: + type: string + designateUnboundImage: + type: string + designateWorkerImage: + type: string + edpmFrrImage: + type: string + edpmIscsidImage: + type: string + edpmLogrotateCrondImage: + type: string + edpmNeutronMetadataAgentImage: + type: string + edpmNeutronSriovAgentImage: + type: string + edpmNodeExporterImage: + type: string + edpmOvnBgpAgentImage: + type: string + glanceAPIImage: + type: string + heatAPIImage: + type: string + heatCfnapiImage: + type: string + heatEngineImage: + type: string + horizonImage: + type: string + infraDnsmasqImage: + type: string + infraMemcachedImage: + type: string + infraRedisImage: + type: string + ironicAPIImage: + type: string + ironicConductorImage: + type: string + ironicInspectorImage: + type: string + ironicNeutronAgentImage: + type: string + ironicPxeImage: + type: string + ironicPythonAgentImage: + type: string + keystoneAPIImage: + type: string + manilaAPIImage: + type: string + manilaSchedulerImage: + type: string + manilaShareImages: + additionalProperties: + type: string + type: object + mariadbImage: + type: string + neutronAPIImage: + type: string + novaAPIImage: + type: string + novaComputeImage: + type: string + novaConductorImage: + type: string + novaNovncImage: + type: string + novaSchedulerImage: + type: string + octaviaAPIImage: + type: string + octaviaHealthmanagerImage: + type: string + octaviaHousekeepingImage: + type: string + octaviaWorkerImage: + type: string + openstackClientImage: + type: string + osContainerImage: + type: string + ovnControllerImage: + type: string + ovnControllerOvsImage: + type: string + ovnNbDbclusterImage: + type: string + ovnNorthdImage: + type: string + ovnSbDbclusterImage: + type: string + placementAPIImage: + type: string + rabbitmqImage: + type: string + swiftAccountImage: + type: string + swiftContainerImage: + type: string + swiftObjectImage: + type: string + swiftProxyImage: + type: string + telemetryNodeExporterImage: + type: string + type: object + deployedVersion: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/apis/core/v1beta1/conditions.go b/apis/core/v1beta1/conditions.go index 80d566065..622076dc9 100644 --- a/apis/core/v1beta1/conditions.go +++ b/apis/core/v1beta1/conditions.go @@ -114,36 +114,12 @@ const ( // OpenStackControlPlaneServiceOverrideReadyCondition Status=True condition which indicates if OpenStack service override has created ok OpenStackControlPlaneServiceOverrideReadyCondition condition.Type = "OpenStackControlPlaneServiceOverrideReady" - // OpenStackControlPlaneManilaReadyInitMessage - OpenStackControlPlaneManilaReadyInitMessage = "OpenStackControlPlane Manila not started" - - // OpenStackControlPlaneManilaReadyMessage - OpenStackControlPlaneManilaReadyMessage = "OpenStackControlPlane Manila completed" - - // OpenStackControlPlaneManilaReadyRunningMessage - OpenStackControlPlaneManilaReadyRunningMessage = "OpenStackControlPlane Manila in progress" - - // OpenStackControlPlaneManilaReadyErrorMessage - OpenStackControlPlaneManilaReadyErrorMessage = "OpenStackControlPlane Manila error occured %s" - // OpenStackControlPlaneSwiftReadyCondition Status=True condition which indicates if Swift is configured and operational OpenStackControlPlaneSwiftReadyCondition condition.Type = "OpenStackControlPlaneSwiftReady" // OpenStackControlPlaneExposeSwiftReadyCondition Status=True condition which indicates if Swift is exposed via a route OpenStackControlPlaneExposeSwiftReadyCondition condition.Type = "OpenStackControlPlaneExposeSwiftReady" - // OpenStackControlPlaneSwiftReadyInitMessage - OpenStackControlPlaneSwiftReadyInitMessage = "OpenStackControlPlane Swift not started" - - // OpenStackControlPlaneSwiftReadyMessage - OpenStackControlPlaneSwiftReadyMessage = "OpenStackControlPlane Swift completed" - - // OpenStackControlPlaneSwiftReadyRunningMessage - OpenStackControlPlaneSwiftReadyRunningMessage = "OpenStackControlPlane Swift in progress" - - // OpenStackControlPlaneSwiftReadyErrorMessage - OpenStackControlPlaneSwiftReadyErrorMessage = "OpenStackControlPlane Swift error occured %s" - // OpenStackControlPlaneOctaviaReadyCondition Status=True condition which indicates if Octavia is configured and operational OpenStackControlPlaneOctaviaReadyCondition condition.Type = "OpenStackControlPlaneOctaviaReady" @@ -166,9 +142,6 @@ const ( OpenStackControlPlaneExposeBarbicanReadyCondition condition.Type = "OpenStackControlPlaneExposeBarbicanReady" ) -// OpenStackControlPlane Reasons used by API objects. -const () - // Common Messages used by API objects. const ( // @@ -406,6 +379,30 @@ const ( // OpenStackControlPlaneBarbicanReadyErrorMessage OpenStackControlPlaneBarbicanReadyErrorMessage = "OpenStackControlPlane Barbican error occured %s" + // OpenStackControlPlaneSwiftReadyInitMessage + OpenStackControlPlaneSwiftReadyInitMessage = "OpenStackControlPlane Swift not started" + + // OpenStackControlPlaneSwiftReadyMessage + OpenStackControlPlaneSwiftReadyMessage = "OpenStackControlPlane Swift completed" + + // OpenStackControlPlaneSwiftReadyRunningMessage + OpenStackControlPlaneSwiftReadyRunningMessage = "OpenStackControlPlane Swift in progress" + + // OpenStackControlPlaneSwiftReadyErrorMessage + OpenStackControlPlaneSwiftReadyErrorMessage = "OpenStackControlPlane Swift error occured %s" + + // OpenStackControlPlaneManilaReadyInitMessage + OpenStackControlPlaneManilaReadyInitMessage = "OpenStackControlPlane Manila not started" + + // OpenStackControlPlaneManilaReadyMessage + OpenStackControlPlaneManilaReadyMessage = "OpenStackControlPlane Manila completed" + + // OpenStackControlPlaneManilaReadyRunningMessage + OpenStackControlPlaneManilaReadyRunningMessage = "OpenStackControlPlane Manila in progress" + + // OpenStackControlPlaneManilaReadyErrorMessage + OpenStackControlPlaneManilaReadyErrorMessage = "OpenStackControlPlane Manila error occured %s" + // OpenStackControlPlaneRedisReadyInitMessage OpenStackControlPlaneRedisReadyInitMessage = "OpenStackControlPlane Redis not started" @@ -439,3 +436,44 @@ const ( // OpenStackControlPlaneCAReadyErrorMessage OpenStackControlPlaneCAReadyErrorMessage = "OpenStackControlPlane CAs %s %s error occured %s" ) + +// Version Conditions used by API objects. +const ( + OpenStackVersionInitialized condition.Type = "Initialized" + + OpenStackVersionMinorUpdateOVNDataplane condition.Type = "MinorUpdateOVNDataplane" + + OpenStackVersionMinorUpdateOVNControlplane condition.Type = "MinorUpdateOVNControlplane" + + OpenStackVersionMinorUpdateControlplane condition.Type = "MinorUpdateControlplane" + + OpenStackVersionMinorUpdateDataplane condition.Type = "MinorUpdateDataplane" +) + +// Version Messages used by API objects. +const ( + + // OpenStackVersionInitializedInitMessage + OpenStackVersionInitializedInitMessage = "not started" + + // OpenStackVersionInitializedReadyMessage + OpenStackVersionInitializedReadyMessage = "completed" + + // OpenStackVersionInitializedReadyRunningMessage + OpenStackVersionInitializedReadyRunningMessage = "in progress" + + // OpenStackVersionInitializedReadyErrorMessage + OpenStackVersionInitializedReadyErrorMessage = "error occured %s" + + // OpenStackVersionMinorUpdateInitMessage + OpenStackVersionMinorUpdateInitMessage = "not started" + + // OpenStackVersionMinorUpdateReadyMessage + OpenStackVersionMinorUpdateReadyMessage = "completed" + + // OpenStackVersionMinorUpdateReadyRunningMessage + OpenStackVersionMinorUpdateReadyRunningMessage = "in progress" + + // OpenStackVersionMinorUpdateReadyErrorMessage + //OpenStackVersionMinorUpdateReadyErrorMessage = "error occured %s" +) diff --git a/apis/core/v1beta1/openstackcontrolplane_types.go b/apis/core/v1beta1/openstackcontrolplane_types.go index b6d59c3d2..f4562ce57 100644 --- a/apis/core/v1beta1/openstackcontrolplane_types.go +++ b/apis/core/v1beta1/openstackcontrolplane_types.go @@ -55,6 +55,7 @@ const ( // RabbitMqContainerImage is the fall-back container image for RabbitMQ RabbitMqContainerImage = "quay.io/podified-antelope-centos9/openstack-rabbitmq:current-podified" + // OvnDbCaName - OvnDbCaName = tls.DefaultCAPrefix + "ovn" ) @@ -305,7 +306,7 @@ type KeystoneSection struct { // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Keystone service - Template keystonev1.KeystoneAPISpec `json:"template,omitempty"` + Template keystonev1.KeystoneAPISpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -345,7 +346,7 @@ type PlacementSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Placement API - Template placementv1.PlacementAPISpec `json:"template,omitempty"` + Template placementv1.PlacementAPISpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -364,7 +365,7 @@ type GlanceSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Glance Service - Template glancev1.GlanceSpec `json:"template,omitempty"` + Template glancev1.GlanceSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -383,7 +384,7 @@ type CinderSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating Cinder Resources - Template cinderv1.CinderSpec `json:"template,omitempty"` + Template cinderv1.CinderSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -402,7 +403,7 @@ type GaleraSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Templates - Overrides to use when creating the Galera databases - Templates map[string]mariadbv1.GaleraSpec `json:"templates,omitempty"` + Templates map[string]mariadbv1.GaleraSpecCore `json:"templates,omitempty"` } // RabbitmqSection defines the desired state of RabbitMQ service @@ -430,7 +431,7 @@ type MemcachedSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Templates - Overrides to use when creating the Memcached databases - Templates map[string]memcachedv1.MemcachedSpec `json:"templates,omitempty"` + Templates map[string]memcachedv1.MemcachedSpecCore `json:"templates,omitempty"` } // RabbitmqTemplate definition @@ -438,7 +439,7 @@ type RabbitmqTemplate struct { // +kubebuilder:validation:Required //+operator-sdk:csv:customresourcedefinitions:type=spec // Overrides to use when creating the Rabbitmq clusters - rabbitmqv2.RabbitmqClusterSpec `json:",inline"` + rabbitmqv2.RabbitmqClusterSpecCore `json:",inline"` } // OvnSection defines the desired state of OVN services @@ -460,17 +461,17 @@ type OvnResources struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // OVNDBCluster - Overrides to use when creating the OVNDBCluster services - OVNDBCluster map[string]ovnv1.OVNDBClusterSpec `json:"ovnDBCluster,omitempty"` + OVNDBCluster map[string]ovnv1.OVNDBClusterSpecCore `json:"ovnDBCluster,omitempty"` // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // OVNNorthd - Overrides to use when creating the OVNNorthd service - OVNNorthd ovnv1.OVNNorthdSpec `json:"ovnNorthd,omitempty"` + OVNNorthd ovnv1.OVNNorthdSpecCore `json:"ovnNorthd,omitempty"` // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // OVNController - Overrides to use when creating the OVNController service - OVNController ovnv1.OVNControllerSpec `json:"ovnController,omitempty"` + OVNController ovnv1.OVNControllerSpecCore `json:"ovnController,omitempty"` } // NeutronSection defines the desired state of Neutron service @@ -484,7 +485,7 @@ type NeutronSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Neutron Service - Template neutronv1.NeutronAPISpec `json:"template,omitempty"` + Template neutronv1.NeutronAPISpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -535,7 +536,7 @@ type HeatSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Heat services - Template heatv1.HeatSpec `json:"template,omitempty"` + Template heatv1.HeatSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -559,7 +560,7 @@ type IronicSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Ironic services - Template ironicv1.IronicSpec `json:"template,omitempty"` + Template ironicv1.IronicSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -582,7 +583,7 @@ type ManilaSection struct { // +kubebuilder:validation:Optional // Template - Overrides to use when creating Manila Resources - Template manilav1.ManilaSpec `json:"template,omitempty"` + Template manilav1.ManilaSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -599,7 +600,7 @@ type HorizonSection struct { // +kubebuilder:validation:Optional // Template - Overrides to use when creating the Horizon services - Template horizonv1.HorizonSpec `json:"template,omitempty"` + Template horizonv1.HorizonSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -618,7 +619,7 @@ type TelemetrySection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the OpenStack Telemetry services - Template telemetryv1.TelemetrySpec `json:"template,omitempty"` + Template telemetryv1.TelemetrySpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -647,7 +648,7 @@ type SwiftSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating Swift Resources - Template swiftv1.SwiftSpec `json:"template,omitempty"` + Template swiftv1.SwiftSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -666,7 +667,7 @@ type OctaviaSection struct { // +kubebuilder:valdiation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating Octavia Resources - Template octaviav1.OctaviaSpec `json:"template,omitempty"` + Template octaviav1.OctaviaSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -685,7 +686,7 @@ type DesignateSection struct { // +kubebuilder:valdiation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating Designate Resources - Template designatev1.DesignateSpec `json:"template,omitempty"` + Template designatev1.DesignateSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -704,7 +705,7 @@ type BarbicanSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Template - Overrides to use when creating the Barbican Service - Template barbicanv1.BarbicanSpec `json:"template,omitempty"` + Template barbicanv1.BarbicanSpecCore `json:"template,omitempty"` // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -723,7 +724,7 @@ type RedisSection struct { // +kubebuilder:validation:Optional //+operator-sdk:csv:customresourcedefinitions:type=spec // Templates - Overrides to use when creating the Redis Resources - Templates map[string]redisv1.RedisSpec `json:"templates,omitempty"` + Templates map[string]redisv1.RedisSpecCore `json:"templates,omitempty"` } // OpenStackClientSection defines the desired state of the OpenStackClient @@ -740,9 +741,20 @@ type OpenStackControlPlaneStatus struct { // Conditions Conditions condition.Conditions `json:"conditions,omitempty" optional:"true"` - //+operator-sdk:csv:customresourcedefinitions:type=spec + //+operator-sdk:csv:customresourcedefinitions:type=status // TLS TLS TLSStatus `json:"tls,omitempty" optional:"true"` + + //+operator-sdk:csv:customresourcedefinitions:type=status + // DeployedVersion + DeployedVersion *string `json:"deployedVersion,omitempty"` + + //+operator-sdk:csv:customresourcedefinitions:type=status + // DeployedOVNVersion + DeployedOVNVersion *string `json:"deployedOVNVersion,omitempty"` + + // ContainerImages + ContainerImages ContainerImages `json:"containerImages,omitempty"` } // TLSStatus defines the observed state of TLS diff --git a/apis/core/v1beta1/openstackcontrolplane_webhook.go b/apis/core/v1beta1/openstackcontrolplane_webhook.go index 7985e6874..47fc259b4 100644 --- a/apis/core/v1beta1/openstackcontrolplane_webhook.go +++ b/apis/core/v1beta1/openstackcontrolplane_webhook.go @@ -329,18 +329,6 @@ func initializeOverrideSpec(override **route.OverrideSpec, anno map[string]strin // DefaultServices - common function for calling individual services' defaulting functions func (r *OpenStackControlPlane) DefaultServices() { - // RabbitMQ - // This is a special case in that we don't own the RabbitMQ operator, - // so we aren't able to add and call a Default function on its spec. - // Instead we just directly set the defaults we need. - for key, template := range r.Spec.Rabbitmq.Templates { - if template.Image == "" { - template.Image = openstackControlPlaneDefaults.RabbitMqImageURL - // By-value copy, need to update - r.Spec.Rabbitmq.Templates[key] = template - } - } - // Cinder r.Spec.Cinder.Template.Default() diff --git a/apis/core/v1beta1/openstackversion_types.go b/apis/core/v1beta1/openstackversion_types.go index 9c0b53af3..6ad05013d 100644 --- a/apis/core/v1beta1/openstackversion_types.go +++ b/apis/core/v1beta1/openstackversion_types.go @@ -1,5 +1,5 @@ /* -Copyright 2022. +Copyright 2024. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,31 +17,157 @@ limitations under the License. package v1beta1 import ( + condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +const ( + // MinorUpdateOvnControlPlane - + MinorUpdateOvnControlPlane string = "Minor Update OVN Controlplane In Progress" + // MinorUpdateControlPlane - + MinorUpdateControlPlane string = "Minor Update Controlplane In Progress" + // MinorUpdateComplete - + MinorUpdateComplete string = "Complete" +) -// OpenStackVersionSpec defines the desired state of OpenStackVersion +// OpenStackVersionSpec - defines the desired state of OpenStackVersion type OpenStackVersionSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - // Foo is an example field of OpenStackVersion. Edit openstackversion_types.go to remove/update - Foo string `json:"foo,omitempty"` + // +kubebuilder:validation:Required + // TargetVersion is the version of OpenStack to install (based on the availableVersion in the OpenStackVersion CR status) + TargetVersion string `json:"targetVersion"` + + // CustomContainerImages is a list of containerImages to customize for deployment + CustomContainerImages CustomContainerImages `json:"customContainerImages,omitempty"` +} + +// CustomContainerImages - struct for custom container images +type CustomContainerImages struct { + ContainerTemplate `json:",inline"` + CinderVolumeImages map[string]*string `json:"cinderVolumeImages,omitempty"` + ManilaShareImages map[string]*string `json:"manilaShareImages,omitempty"` +} + +// ContainerDefaults - struct that contains container image default URLs for each service (internal use only) +type ContainerDefaults struct { + ContainerTemplate `json:",inline"` + CinderVolumeImage *string `json:"cinderVolumeImage,omitempty"` + ManilaShareImage *string `json:"manilaShareImage,omitempty"` +} + +// ContainerImages - struct acts as the source of truth for container image URLs to be deployed +type ContainerImages struct { + ContainerTemplate `json:",inline"` + // CinderVolumeImages custom Cinder Volume images for each backend (default Cinder volume image is stored 'default' key) + // TODO: add validation to cinder-operator to prevent backend being named 'default' + CinderVolumeImages map[string]*string `json:"cinderVolumeImages,omitempty"` + // ManilaShareImages custom Manila Share images for each backend (default Manila share image is stored 'default' key) + // TODO: add validation to cinder-operator to prevent backend being named 'default' + ManilaShareImages map[string]*string `json:"manilaShareImages,omitempty"` +} + +// ContainerTemplate - struct that contains container image URLs for each service in OpenStackControlplane +type ContainerTemplate struct { + AgentImage *string `json:"agentImage,omitempty"` + AnsibleeeImage *string `json:"ansibleeeImage,omitempty"` + AodhAPIImage *string `json:"aodhAPIImage,omitempty"` + AodhEvaluatorImage *string `json:"aodhEvaluatorImage,omitempty"` + AodhListenerImage *string `json:"aodhListenerImage,omitempty"` + AodhNotifierImage *string `json:"aodhNotifierImage,omitempty"` + ApacheImage *string `json:"apacheImage,omitempty"` + BarbicanAPIImage *string `json:"barbicanAPIImage,omitempty"` + BarbicanKeystoneListenerImage *string `json:"barbicanKeystoneListenerImage,omitempty"` + BarbicanWorkerImage *string `json:"barbicanWorkerImage,omitempty"` + CeilometerCentralImage *string `json:"ceilometerCentralImage,omitempty"` + CeilometerComputeImage *string `json:"ceilometerComputeImage,omitempty"` + CeilometerIpmiImage *string `json:"ceilometerIpmiImage,omitempty"` + CeilometerNotificationImage *string `json:"ceilometerNotificationImage,omitempty"` + CeilometerSgcoreImage *string `json:"ceilometerSgcoreImage,omitempty"` + CinderAPIImage *string `json:"cinderAPIImage,omitempty"` + CinderBackupImage *string `json:"cinderBackupImage,omitempty"` + CinderSchedulerImage *string `json:"cinderSchedulerImage,omitempty"` + DesignateAPIImage *string `json:"designateAPIImage,omitempty"` + DesignateBackendbind9Image *string `json:"designateBackendbind9Image,omitempty"` + DesignateCentralImage *string `json:"designateCentralImage,omitempty"` + DesignateMdnsImage *string `json:"designateMdnsImage,omitempty"` + DesignateProducerImage *string `json:"designateProducerImage,omitempty"` + DesignateUnboundImage *string `json:"designateUnboundImage,omitempty"` + DesignateWorkerImage *string `json:"designateWorkerImage,omitempty"` + EdpmFrrImage *string `json:"edpmFrrImage,omitempty"` + EdpmIscsidImage *string `json:"edpmIscsidImage,omitempty"` + EdpmLogrotateCrondImage *string `json:"edpmLogrotateCrondImage,omitempty"` + EdpmNeutronMetadataAgentImage *string `json:"edpmNeutronMetadataAgentImage,omitempty"` + EdpmNeutronSriovAgentImage *string `json:"edpmNeutronSriovAgentImage,omitempty"` + EdpmOvnBgpAgentImage *string `json:"edpmOvnBgpAgentImage,omitempty"` + EdpmNodeExporterImage *string `json:"edpmNodeExporterImage,omitempty"` + GlanceAPIImage *string `json:"glanceAPIImage,omitempty"` + HeatAPIImage *string `json:"heatAPIImage,omitempty"` + HeatCfnapiImage *string `json:"heatCfnapiImage,omitempty"` + HeatEngineImage *string `json:"heatEngineImage,omitempty"` + HorizonImage *string `json:"horizonImage,omitempty"` + InfraDnsmasqImage *string `json:"infraDnsmasqImage,omitempty"` + InfraMemcachedImage *string `json:"infraMemcachedImage,omitempty"` + InfraRedisImage *string `json:"infraRedisImage,omitempty"` + IronicAPIImage *string `json:"ironicAPIImage,omitempty"` + IronicConductorImage *string `json:"ironicConductorImage,omitempty"` + IronicInspectorImage *string `json:"ironicInspectorImage,omitempty"` + IronicNeutronAgentImage *string `json:"ironicNeutronAgentImage,omitempty"` + IronicPxeImage *string `json:"ironicPxeImage,omitempty"` + IronicPythonAgentImage *string `json:"ironicPythonAgentImage,omitempty"` + KeystoneAPIImage *string `json:"keystoneAPIImage,omitempty"` + ManilaAPIImage *string `json:"manilaAPIImage,omitempty"` + ManilaSchedulerImage *string `json:"manilaSchedulerImage,omitempty"` + MariadbImage *string `json:"mariadbImage,omitempty"` + NeutronAPIImage *string `json:"neutronAPIImage,omitempty"` + NovaAPIImage *string `json:"novaAPIImage,omitempty"` + NovaComputeImage *string `json:"novaComputeImage,omitempty"` + NovaConductorImage *string `json:"novaConductorImage,omitempty"` + NovaNovncImage *string `json:"novaNovncImage,omitempty"` + NovaSchedulerImage *string `json:"novaSchedulerImage,omitempty"` + OctaviaAPIImage *string `json:"octaviaAPIImage,omitempty"` + OctaviaHealthmanagerImage *string `json:"octaviaHealthmanagerImage,omitempty"` + OctaviaHousekeepingImage *string `json:"octaviaHousekeepingImage,omitempty"` + OctaviaWorkerImage *string `json:"octaviaWorkerImage,omitempty"` + OpenstackClientImage *string `json:"openstackClientImage,omitempty"` + OsContainerImage *string `json:"osContainerImage,omitempty"` //fixme wire this in? + OvnControllerImage *string `json:"ovnControllerImage,omitempty"` + OvnControllerOvsImage *string `json:"ovnControllerOvsImage,omitempty"` + OvnNbDbclusterImage *string `json:"ovnNbDbclusterImage,omitempty"` + OvnNorthdImage *string `json:"ovnNorthdImage,omitempty"` + OvnSbDbclusterImage *string `json:"ovnSbDbclusterImage,omitempty"` + PlacementAPIImage *string `json:"placementAPIImage,omitempty"` + RabbitmqImage *string `json:"rabbitmqImage,omitempty"` + SwiftAccountImage *string `json:"swiftAccountImage,omitempty"` + SwiftContainerImage *string `json:"swiftContainerImage,omitempty"` + SwiftObjectImage *string `json:"swiftObjectImage,omitempty"` + SwiftProxyImage *string `json:"swiftProxyImage,omitempty"` + TelemetryNodeExporterImage *string `json:"telemetryNodeExporterImage,omitempty"` } // OpenStackVersionStatus defines the observed state of OpenStackVersion type OpenStackVersionStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file + //+operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} + // Conditions + Conditions condition.Conditions `json:"conditions,omitempty" optional:"true"` + + DeployedVersion *string `json:"deployedVersion,omitempty"` + AvailableVersion *string `json:"availableVersion,omitempty"` + + // This is the source of truth for the container images to be deployed. + ContainerImages ContainerImages `json:"containerImages,omitempty"` + + // where we keep track of the container images for previous versions + ContainerImageVersionDefaults map[string]*ContainerDefaults `json:"containerImageVersionDefaults,omitempty"` } //+kubebuilder:object:root=true //+kubebuilder:subresource:status +// +operator-sdk:csv:customresourcedefinitions:displayName="OpenStack Version" +// +kubebuilder:printcolumn:name="Target Version",type=string,JSONPath=`.spec.targetVersion` +// +kubebuilder:printcolumn:name="Available Version",type=string,JSONPath=`.status.availableVersion` +// +kubebuilder:printcolumn:name="Deployed Version",type=string,JSONPath=`.status.deployedVersion` -// OpenStackVersion is the Schema for the openstackversions API +// OpenStackVersion is the Schema for the openstackversionupdates API type OpenStackVersion struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -62,3 +188,8 @@ type OpenStackVersionList struct { func init() { SchemeBuilder.Register(&OpenStackVersion{}, &OpenStackVersionList{}) } + +// IsReady - returns true if service is ready to serve requests +func (instance OpenStackVersion) IsReady() bool { + return instance.Status.Conditions.IsTrue(condition.ReadyCondition) +} diff --git a/apis/core/v1beta1/openstackversion_webhook.go b/apis/core/v1beta1/openstackversion_webhook.go new file mode 100644 index 000000000..a4e6f37fc --- /dev/null +++ b/apis/core/v1beta1/openstackversion_webhook.go @@ -0,0 +1,134 @@ +/* +Copyright 2022. + +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 v1beta1 + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" + + "github.com/openstack-k8s-operators/lib-common/modules/common/util" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// OpenStackVersionDefaults - +type OpenStackVersionDefaults struct { + availableVersion string +} + +var openstackVersionDefaults OpenStackVersionDefaults + +// log is for logging in this package. +var openstackversionlog = logf.Log.WithName("openstackversion-resource") + +// SetupOpenStackVersionDefaults - initialize OpenStackControlPlane spec defaults for use with internal webhooks +func SetupOpenStackVersionDefaults(defaults OpenStackVersionDefaults) { + openstackVersionDefaults = defaults + openstackversionlog.Info("OpenStackVersion defaults initialized", "defaults", defaults) +} + +// SetupWebhookWithManager - register OpenStackVersion with the controller manager +func (r *OpenStackVersion) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(r). + Complete() +} + +// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! + +//+kubebuilder:webhook:path=/mutate-core-openstack-org-v1beta1-openstackversion,mutating=true,failurePolicy=fail,sideEffects=None,groups=core.openstack.org,resources=openstackversions,verbs=create;update,versions=v1beta1,name=mopenstackversion.kb.io,admissionReviewVersions=v1 + +var _ webhook.Defaulter = &OpenStackVersion{} + +// Default implements webhook.Defaulter so a webhook will be registered for the type +func (r *OpenStackVersion) Default() { + openstackversionlog.Info("default", "name", r.Name) + if r.Spec.TargetVersion == "" { + r.Spec.TargetVersion = openstackVersionDefaults.availableVersion + } + + // TODO(user): fill in your defaulting logic. +} + +// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. +//+kubebuilder:webhook:path=/validate-core-openstack-org-v1beta1-openstackversion,mutating=false,failurePolicy=fail,sideEffects=None,groups=core.openstack.org,resources=openstackversions,verbs=create;update,versions=v1beta1,name=vopenstackversion.kb.io,admissionReviewVersions=v1 + +var _ webhook.Validator = &OpenStackVersion{} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (r *OpenStackVersion) ValidateCreate() (admission.Warnings, error) { + openstackversionlog.Info("validate create", "name", r.Name) + + if r.Spec.TargetVersion != openstackVersionDefaults.availableVersion { + return nil, apierrors.NewForbidden( + schema.GroupResource{ + Group: GroupVersion.WithKind("OpenStackVersion").Group, + Resource: GroupVersion.WithKind("OpenStackVersion").Kind, + }, r.GetName(), &field.Error{ + Type: field.ErrorTypeForbidden, + Field: "TargetVersion", + BadValue: r.Spec.TargetVersion, + Detail: "Invalid value: " + r.Spec.TargetVersion + " must equal available version.", + }, + ) + } + + return nil, nil +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (r *OpenStackVersion) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { + openstackversionlog.Info("validate update", "name", r.Name) + + _, ok := r.Status.ContainerImageVersionDefaults[r.Spec.TargetVersion] + if r.Spec.TargetVersion != openstackVersionDefaults.availableVersion && !ok { + return nil, apierrors.NewForbidden( + schema.GroupResource{ + Group: GroupVersion.WithKind("OpenStackVersion").Group, + Resource: GroupVersion.WithKind("OpenStackVersion").Kind, + }, r.GetName(), &field.Error{ + Type: field.ErrorTypeForbidden, + Field: "TargetVersion", + BadValue: r.Spec.TargetVersion, + Detail: "Invalid value: " + r.Spec.TargetVersion + " must be in the list of current or previous available versions.", + }, + ) + } + + return nil, nil +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (r *OpenStackVersion) ValidateDelete() (admission.Warnings, error) { + openstackversionlog.Info("validate delete", "name", r.Name) + + // TODO(user): fill in your validation logic upon object deletion. + return nil, nil +} + +// SetupVersionDefaults - +func SetupVersionDefaults() { + openstackVersionDefaults := OpenStackVersionDefaults{ + availableVersion: util.GetEnvVar("OPENSTACK_RELEASE_VERSION", ""), + } + + SetupOpenStackVersionDefaults(openstackVersionDefaults) +} diff --git a/apis/core/v1beta1/zz_generated.deepcopy.go b/apis/core/v1beta1/zz_generated.deepcopy.go index 6cc8dedb8..46b13e8fb 100644 --- a/apis/core/v1beta1/zz_generated.deepcopy.go +++ b/apis/core/v1beta1/zz_generated.deepcopy.go @@ -130,6 +130,509 @@ func (in *CinderSection) DeepCopy() *CinderSection { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerDefaults) DeepCopyInto(out *ContainerDefaults) { + *out = *in + in.ContainerTemplate.DeepCopyInto(&out.ContainerTemplate) + if in.CinderVolumeImage != nil { + in, out := &in.CinderVolumeImage, &out.CinderVolumeImage + *out = new(string) + **out = **in + } + if in.ManilaShareImage != nil { + in, out := &in.ManilaShareImage, &out.ManilaShareImage + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerDefaults. +func (in *ContainerDefaults) DeepCopy() *ContainerDefaults { + if in == nil { + return nil + } + out := new(ContainerDefaults) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerImages) DeepCopyInto(out *ContainerImages) { + *out = *in + in.ContainerTemplate.DeepCopyInto(&out.ContainerTemplate) + if in.CinderVolumeImages != nil { + in, out := &in.CinderVolumeImages, &out.CinderVolumeImages + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } + if in.ManilaShareImages != nil { + in, out := &in.ManilaShareImages, &out.ManilaShareImages + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerImages. +func (in *ContainerImages) DeepCopy() *ContainerImages { + if in == nil { + return nil + } + out := new(ContainerImages) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerTemplate) DeepCopyInto(out *ContainerTemplate) { + *out = *in + if in.AgentImage != nil { + in, out := &in.AgentImage, &out.AgentImage + *out = new(string) + **out = **in + } + if in.AnsibleeeImage != nil { + in, out := &in.AnsibleeeImage, &out.AnsibleeeImage + *out = new(string) + **out = **in + } + if in.AodhAPIImage != nil { + in, out := &in.AodhAPIImage, &out.AodhAPIImage + *out = new(string) + **out = **in + } + if in.AodhEvaluatorImage != nil { + in, out := &in.AodhEvaluatorImage, &out.AodhEvaluatorImage + *out = new(string) + **out = **in + } + if in.AodhListenerImage != nil { + in, out := &in.AodhListenerImage, &out.AodhListenerImage + *out = new(string) + **out = **in + } + if in.AodhNotifierImage != nil { + in, out := &in.AodhNotifierImage, &out.AodhNotifierImage + *out = new(string) + **out = **in + } + if in.ApacheImage != nil { + in, out := &in.ApacheImage, &out.ApacheImage + *out = new(string) + **out = **in + } + if in.BarbicanAPIImage != nil { + in, out := &in.BarbicanAPIImage, &out.BarbicanAPIImage + *out = new(string) + **out = **in + } + if in.BarbicanKeystoneListenerImage != nil { + in, out := &in.BarbicanKeystoneListenerImage, &out.BarbicanKeystoneListenerImage + *out = new(string) + **out = **in + } + if in.BarbicanWorkerImage != nil { + in, out := &in.BarbicanWorkerImage, &out.BarbicanWorkerImage + *out = new(string) + **out = **in + } + if in.CeilometerCentralImage != nil { + in, out := &in.CeilometerCentralImage, &out.CeilometerCentralImage + *out = new(string) + **out = **in + } + if in.CeilometerComputeImage != nil { + in, out := &in.CeilometerComputeImage, &out.CeilometerComputeImage + *out = new(string) + **out = **in + } + if in.CeilometerIpmiImage != nil { + in, out := &in.CeilometerIpmiImage, &out.CeilometerIpmiImage + *out = new(string) + **out = **in + } + if in.CeilometerNotificationImage != nil { + in, out := &in.CeilometerNotificationImage, &out.CeilometerNotificationImage + *out = new(string) + **out = **in + } + if in.CeilometerSgcoreImage != nil { + in, out := &in.CeilometerSgcoreImage, &out.CeilometerSgcoreImage + *out = new(string) + **out = **in + } + if in.CinderAPIImage != nil { + in, out := &in.CinderAPIImage, &out.CinderAPIImage + *out = new(string) + **out = **in + } + if in.CinderBackupImage != nil { + in, out := &in.CinderBackupImage, &out.CinderBackupImage + *out = new(string) + **out = **in + } + if in.CinderSchedulerImage != nil { + in, out := &in.CinderSchedulerImage, &out.CinderSchedulerImage + *out = new(string) + **out = **in + } + if in.DesignateAPIImage != nil { + in, out := &in.DesignateAPIImage, &out.DesignateAPIImage + *out = new(string) + **out = **in + } + if in.DesignateBackendbind9Image != nil { + in, out := &in.DesignateBackendbind9Image, &out.DesignateBackendbind9Image + *out = new(string) + **out = **in + } + if in.DesignateCentralImage != nil { + in, out := &in.DesignateCentralImage, &out.DesignateCentralImage + *out = new(string) + **out = **in + } + if in.DesignateMdnsImage != nil { + in, out := &in.DesignateMdnsImage, &out.DesignateMdnsImage + *out = new(string) + **out = **in + } + if in.DesignateProducerImage != nil { + in, out := &in.DesignateProducerImage, &out.DesignateProducerImage + *out = new(string) + **out = **in + } + if in.DesignateUnboundImage != nil { + in, out := &in.DesignateUnboundImage, &out.DesignateUnboundImage + *out = new(string) + **out = **in + } + if in.DesignateWorkerImage != nil { + in, out := &in.DesignateWorkerImage, &out.DesignateWorkerImage + *out = new(string) + **out = **in + } + if in.EdpmFrrImage != nil { + in, out := &in.EdpmFrrImage, &out.EdpmFrrImage + *out = new(string) + **out = **in + } + if in.EdpmIscsidImage != nil { + in, out := &in.EdpmIscsidImage, &out.EdpmIscsidImage + *out = new(string) + **out = **in + } + if in.EdpmLogrotateCrondImage != nil { + in, out := &in.EdpmLogrotateCrondImage, &out.EdpmLogrotateCrondImage + *out = new(string) + **out = **in + } + if in.EdpmNeutronMetadataAgentImage != nil { + in, out := &in.EdpmNeutronMetadataAgentImage, &out.EdpmNeutronMetadataAgentImage + *out = new(string) + **out = **in + } + if in.EdpmNeutronSriovAgentImage != nil { + in, out := &in.EdpmNeutronSriovAgentImage, &out.EdpmNeutronSriovAgentImage + *out = new(string) + **out = **in + } + if in.EdpmOvnBgpAgentImage != nil { + in, out := &in.EdpmOvnBgpAgentImage, &out.EdpmOvnBgpAgentImage + *out = new(string) + **out = **in + } + if in.EdpmNodeExporterImage != nil { + in, out := &in.EdpmNodeExporterImage, &out.EdpmNodeExporterImage + *out = new(string) + **out = **in + } + if in.GlanceAPIImage != nil { + in, out := &in.GlanceAPIImage, &out.GlanceAPIImage + *out = new(string) + **out = **in + } + if in.HeatAPIImage != nil { + in, out := &in.HeatAPIImage, &out.HeatAPIImage + *out = new(string) + **out = **in + } + if in.HeatCfnapiImage != nil { + in, out := &in.HeatCfnapiImage, &out.HeatCfnapiImage + *out = new(string) + **out = **in + } + if in.HeatEngineImage != nil { + in, out := &in.HeatEngineImage, &out.HeatEngineImage + *out = new(string) + **out = **in + } + if in.HorizonImage != nil { + in, out := &in.HorizonImage, &out.HorizonImage + *out = new(string) + **out = **in + } + if in.InfraDnsmasqImage != nil { + in, out := &in.InfraDnsmasqImage, &out.InfraDnsmasqImage + *out = new(string) + **out = **in + } + if in.InfraMemcachedImage != nil { + in, out := &in.InfraMemcachedImage, &out.InfraMemcachedImage + *out = new(string) + **out = **in + } + if in.InfraRedisImage != nil { + in, out := &in.InfraRedisImage, &out.InfraRedisImage + *out = new(string) + **out = **in + } + if in.IronicAPIImage != nil { + in, out := &in.IronicAPIImage, &out.IronicAPIImage + *out = new(string) + **out = **in + } + if in.IronicConductorImage != nil { + in, out := &in.IronicConductorImage, &out.IronicConductorImage + *out = new(string) + **out = **in + } + if in.IronicInspectorImage != nil { + in, out := &in.IronicInspectorImage, &out.IronicInspectorImage + *out = new(string) + **out = **in + } + if in.IronicNeutronAgentImage != nil { + in, out := &in.IronicNeutronAgentImage, &out.IronicNeutronAgentImage + *out = new(string) + **out = **in + } + if in.IronicPxeImage != nil { + in, out := &in.IronicPxeImage, &out.IronicPxeImage + *out = new(string) + **out = **in + } + if in.IronicPythonAgentImage != nil { + in, out := &in.IronicPythonAgentImage, &out.IronicPythonAgentImage + *out = new(string) + **out = **in + } + if in.KeystoneAPIImage != nil { + in, out := &in.KeystoneAPIImage, &out.KeystoneAPIImage + *out = new(string) + **out = **in + } + if in.ManilaAPIImage != nil { + in, out := &in.ManilaAPIImage, &out.ManilaAPIImage + *out = new(string) + **out = **in + } + if in.ManilaSchedulerImage != nil { + in, out := &in.ManilaSchedulerImage, &out.ManilaSchedulerImage + *out = new(string) + **out = **in + } + if in.MariadbImage != nil { + in, out := &in.MariadbImage, &out.MariadbImage + *out = new(string) + **out = **in + } + if in.NeutronAPIImage != nil { + in, out := &in.NeutronAPIImage, &out.NeutronAPIImage + *out = new(string) + **out = **in + } + if in.NovaAPIImage != nil { + in, out := &in.NovaAPIImage, &out.NovaAPIImage + *out = new(string) + **out = **in + } + if in.NovaComputeImage != nil { + in, out := &in.NovaComputeImage, &out.NovaComputeImage + *out = new(string) + **out = **in + } + if in.NovaConductorImage != nil { + in, out := &in.NovaConductorImage, &out.NovaConductorImage + *out = new(string) + **out = **in + } + if in.NovaNovncImage != nil { + in, out := &in.NovaNovncImage, &out.NovaNovncImage + *out = new(string) + **out = **in + } + if in.NovaSchedulerImage != nil { + in, out := &in.NovaSchedulerImage, &out.NovaSchedulerImage + *out = new(string) + **out = **in + } + if in.OctaviaAPIImage != nil { + in, out := &in.OctaviaAPIImage, &out.OctaviaAPIImage + *out = new(string) + **out = **in + } + if in.OctaviaHealthmanagerImage != nil { + in, out := &in.OctaviaHealthmanagerImage, &out.OctaviaHealthmanagerImage + *out = new(string) + **out = **in + } + if in.OctaviaHousekeepingImage != nil { + in, out := &in.OctaviaHousekeepingImage, &out.OctaviaHousekeepingImage + *out = new(string) + **out = **in + } + if in.OctaviaWorkerImage != nil { + in, out := &in.OctaviaWorkerImage, &out.OctaviaWorkerImage + *out = new(string) + **out = **in + } + if in.OpenstackClientImage != nil { + in, out := &in.OpenstackClientImage, &out.OpenstackClientImage + *out = new(string) + **out = **in + } + if in.OsContainerImage != nil { + in, out := &in.OsContainerImage, &out.OsContainerImage + *out = new(string) + **out = **in + } + if in.OvnControllerImage != nil { + in, out := &in.OvnControllerImage, &out.OvnControllerImage + *out = new(string) + **out = **in + } + if in.OvnControllerOvsImage != nil { + in, out := &in.OvnControllerOvsImage, &out.OvnControllerOvsImage + *out = new(string) + **out = **in + } + if in.OvnNbDbclusterImage != nil { + in, out := &in.OvnNbDbclusterImage, &out.OvnNbDbclusterImage + *out = new(string) + **out = **in + } + if in.OvnNorthdImage != nil { + in, out := &in.OvnNorthdImage, &out.OvnNorthdImage + *out = new(string) + **out = **in + } + if in.OvnSbDbclusterImage != nil { + in, out := &in.OvnSbDbclusterImage, &out.OvnSbDbclusterImage + *out = new(string) + **out = **in + } + if in.PlacementAPIImage != nil { + in, out := &in.PlacementAPIImage, &out.PlacementAPIImage + *out = new(string) + **out = **in + } + if in.RabbitmqImage != nil { + in, out := &in.RabbitmqImage, &out.RabbitmqImage + *out = new(string) + **out = **in + } + if in.SwiftAccountImage != nil { + in, out := &in.SwiftAccountImage, &out.SwiftAccountImage + *out = new(string) + **out = **in + } + if in.SwiftContainerImage != nil { + in, out := &in.SwiftContainerImage, &out.SwiftContainerImage + *out = new(string) + **out = **in + } + if in.SwiftObjectImage != nil { + in, out := &in.SwiftObjectImage, &out.SwiftObjectImage + *out = new(string) + **out = **in + } + if in.SwiftProxyImage != nil { + in, out := &in.SwiftProxyImage, &out.SwiftProxyImage + *out = new(string) + **out = **in + } + if in.TelemetryNodeExporterImage != nil { + in, out := &in.TelemetryNodeExporterImage, &out.TelemetryNodeExporterImage + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerTemplate. +func (in *ContainerTemplate) DeepCopy() *ContainerTemplate { + if in == nil { + return nil + } + out := new(ContainerTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomContainerImages) DeepCopyInto(out *CustomContainerImages) { + *out = *in + in.ContainerTemplate.DeepCopyInto(&out.ContainerTemplate) + if in.CinderVolumeImages != nil { + in, out := &in.CinderVolumeImages, &out.CinderVolumeImages + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } + if in.ManilaShareImages != nil { + in, out := &in.ManilaShareImages, &out.ManilaShareImages + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomContainerImages. +func (in *CustomContainerImages) DeepCopy() *CustomContainerImages { + if in == nil { + return nil + } + out := new(CustomContainerImages) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DNSMasqSection) DeepCopyInto(out *DNSMasqSection) { *out = *in @@ -168,7 +671,7 @@ func (in *GaleraSection) DeepCopyInto(out *GaleraSection) { *out = *in if in.Templates != nil { in, out := &in.Templates, &out.Templates - *out = make(map[string]apiv1beta1.GaleraSpec, len(*in)) + *out = make(map[string]apiv1beta1.GaleraSpecCore, len(*in)) for key, val := range *in { (*out)[key] = *val.DeepCopy() } @@ -300,7 +803,7 @@ func (in *MemcachedSection) DeepCopyInto(out *MemcachedSection) { *out = *in if in.Templates != nil { in, out := &in.Templates, &out.Templates - *out = make(map[string]memcachedv1beta1.MemcachedSpec, len(*in)) + *out = make(map[string]memcachedv1beta1.MemcachedSpecCore, len(*in)) for key, val := range *in { (*out)[key] = *val.DeepCopy() } @@ -544,6 +1047,17 @@ func (in *OpenStackControlPlaneStatus) DeepCopyInto(out *OpenStackControlPlaneSt } } in.TLS.DeepCopyInto(&out.TLS) + if in.DeployedVersion != nil { + in, out := &in.DeployedVersion, &out.DeployedVersion + *out = new(string) + **out = **in + } + if in.DeployedOVNVersion != nil { + in, out := &in.DeployedOVNVersion, &out.DeployedOVNVersion + *out = new(string) + **out = **in + } + in.ContainerImages.DeepCopyInto(&out.ContainerImages) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackControlPlaneStatus. @@ -583,8 +1097,8 @@ func (in *OpenStackVersion) DeepCopyInto(out *OpenStackVersion) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackVersion. @@ -605,6 +1119,21 @@ func (in *OpenStackVersion) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenStackVersionDefaults) DeepCopyInto(out *OpenStackVersionDefaults) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackVersionDefaults. +func (in *OpenStackVersionDefaults) DeepCopy() *OpenStackVersionDefaults { + if in == nil { + return nil + } + out := new(OpenStackVersionDefaults) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackVersionList) DeepCopyInto(out *OpenStackVersionList) { *out = *in @@ -640,6 +1169,7 @@ func (in *OpenStackVersionList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackVersionSpec) DeepCopyInto(out *OpenStackVersionSpec) { *out = *in + in.CustomContainerImages.DeepCopyInto(&out.CustomContainerImages) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackVersionSpec. @@ -655,6 +1185,39 @@ func (in *OpenStackVersionSpec) DeepCopy() *OpenStackVersionSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackVersionStatus) DeepCopyInto(out *OpenStackVersionStatus) { *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(condition.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.DeployedVersion != nil { + in, out := &in.DeployedVersion, &out.DeployedVersion + *out = new(string) + **out = **in + } + if in.AvailableVersion != nil { + in, out := &in.AvailableVersion, &out.AvailableVersion + *out = new(string) + **out = **in + } + in.ContainerImages.DeepCopyInto(&out.ContainerImages) + if in.ContainerImageVersionDefaults != nil { + in, out := &in.ContainerImageVersionDefaults, &out.ContainerImageVersionDefaults + *out = make(map[string]*ContainerDefaults, len(*in)) + for key, val := range *in { + var outVal *ContainerDefaults + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(ContainerDefaults) + (*in).DeepCopyInto(*out) + } + (*out)[key] = outVal + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackVersionStatus. @@ -697,7 +1260,7 @@ func (in *OvnResources) DeepCopyInto(out *OvnResources) { *out = *in if in.OVNDBCluster != nil { in, out := &in.OVNDBCluster, &out.OVNDBCluster - *out = make(map[string]ovn_operatorapiv1beta1.OVNDBClusterSpec, len(*in)) + *out = make(map[string]ovn_operatorapiv1beta1.OVNDBClusterSpecCore, len(*in)) for key, val := range *in { (*out)[key] = *val.DeepCopy() } @@ -774,7 +1337,7 @@ func (in *RabbitmqSection) DeepCopy() *RabbitmqSection { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RabbitmqTemplate) DeepCopyInto(out *RabbitmqTemplate) { *out = *in - in.RabbitmqClusterSpec.DeepCopyInto(&out.RabbitmqClusterSpec) + in.RabbitmqClusterSpecCore.DeepCopyInto(&out.RabbitmqClusterSpecCore) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitmqTemplate. @@ -792,7 +1355,7 @@ func (in *RedisSection) DeepCopyInto(out *RedisSection) { *out = *in if in.Templates != nil { in, out := &in.Templates, &out.Templates - *out = make(map[string]redisv1beta1.RedisSpec, len(*in)) + *out = make(map[string]redisv1beta1.RedisSpecCore, len(*in)) for key, val := range *in { (*out)[key] = *val.DeepCopy() } diff --git a/apis/go.mod b/apis/go.mod index 64aed8163..679b38119 100644 --- a/apis/go.mod +++ b/apis/go.mod @@ -101,3 +101,6 @@ require ( // mschuppert: map to latest commit from release-4.13 tag // must consistent within modules and service operators replace github.com/openshift/api => github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7 //allow-merging + +// custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.6.0_patches_tag) +replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20240313124519-961a0ee8bf7f //allow-merging diff --git a/apis/go.sum b/apis/go.sum index dfa8926ad..b2d17fcb0 100644 --- a/apis/go.sum +++ b/apis/go.sum @@ -111,6 +111,8 @@ github.com/openstack-k8s-operators/ovn-operator/api v0.3.1-0.20240403151939-f1ae github.com/openstack-k8s-operators/ovn-operator/api v0.3.1-0.20240403151939-f1aeebd1f2e0/go.mod h1:gouaaSPxUBLC1ifDBAdFsbl1njab50Uc2cBE8M6oKGc= github.com/openstack-k8s-operators/placement-operator/api v0.3.1-0.20240404140050-69252e99daaf h1:O7RzcKH3qRORucojkKZc1vIpQv5naYoWn34zhVzTs0E= github.com/openstack-k8s-operators/placement-operator/api v0.3.1-0.20240404140050-69252e99daaf/go.mod h1:NYOgk2HS4mSR+4WwsiexepNU1pjxeo7h2WTs8qtS9/0= +github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20240313124519-961a0ee8bf7f h1:wWaOCAkCym4t+NZWXYT/LErGhKujDdKgc7Qy/3vX4uU= +github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20240313124519-961a0ee8bf7f/go.mod h1:Zryxg5YgbPUFcLSCcKpf10il8kIRAK5HloNo6khhdis= github.com/openstack-k8s-operators/swift-operator/api v0.3.1-0.20240405150212-f8cecba5f227 h1:aX8lFcr9d7SzsP9MUvHzrki1jUPqYbAFlfdlu4OWxl0= github.com/openstack-k8s-operators/swift-operator/api v0.3.1-0.20240405150212-f8cecba5f227/go.mod h1:kl+TdEExQwr7OCZaOilotlGlz9rzGxC75rUBL0P35f8= github.com/openstack-k8s-operators/telemetry-operator/api v0.3.1-0.20240404090348-ab779da79e83 h1:/YiMXzTLTehsSlDHliiJiDr3n/j1krxRHlP0A2ca41k= @@ -127,8 +129,6 @@ github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqSc github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rabbitmq/cluster-operator/v2 v2.6.0 h1:pr42elurQgi4DVmLTI1cOh8VZRNkfFKZK9+FgQuM/8w= -github.com/rabbitmq/cluster-operator/v2 v2.6.0/go.mod h1:Zryxg5YgbPUFcLSCcKpf10il8kIRAK5HloNo6khhdis= github.com/rhobs/obo-prometheus-operator/pkg/apis/monitoring v0.69.0-rhobs1 h1:d6UamuHl8GaEXcQqM7VO8jMnnhzHmTA0f6h4dQTQsGk= github.com/rhobs/obo-prometheus-operator/pkg/apis/monitoring v0.69.0-rhobs1/go.mod h1:SDL0R6499oleOOVL5ovIxHpyLOh2sR2g0rvBuuqHyQM= github.com/rhobs/observability-operator v0.0.28 h1:FFMBkmI1LWJVWyJKJqelYbV5iUc4u/wJClqowRJZRoU= diff --git a/cmd/csv-merger/csv-merger.go b/cmd/csv-merger/csv-merger.go index 02596ab5f..2b9d22346 100644 --- a/cmd/csv-merger/csv-merger.go +++ b/cmd/csv-merger/csv-merger.go @@ -100,7 +100,7 @@ var ( importEnvFiles = flag.String("import-env-files", "", "Comma separated list of file names to read default operator ENVs from. Used for inter-bundle ENV merging.") exportEnvFile = flag.String("export-env-file", "", "Name the external file to write operator ENVs to. Used for inter-bundle ENV merging.") almExamples = flag.Bool("alm-examples", false, "Merge almExamples into the CSV") - visibleCRDList = flag.String("visible-crds-list", "openstackcontrolplanes.core.openstack.org,openstackdataplanenodesets.dataplane.openstack.org,openstackdataplanedeployments.dataplane.openstack.org", + visibleCRDList = flag.String("visible-crds-list", "openstackversions.core.openstack.org,openstackcontrolplanes.core.openstack.org,openstackdataplanenodesets.dataplane.openstack.org,openstackdataplanedeployments.dataplane.openstack.org", "Comma separated list of all the CRDs that should be visible in OLM console") ) diff --git a/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml b/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml index ad5c1c3ab..7c79814d2 100644 --- a/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml +++ b/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml @@ -156,8 +156,6 @@ spec: properties: barbicanAPI: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -285,13 +283,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object barbicanKeystoneListener: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -347,13 +341,9 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object barbicanWorker: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -409,8 +399,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object customServiceConfig: type: string @@ -580,8 +568,6 @@ spec: properties: cinderAPI: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -701,13 +687,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object cinderBackup: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -758,13 +740,9 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object cinderScheduler: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -815,14 +793,10 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object cinderVolumes: additionalProperties: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -874,8 +848,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object type: object customServiceConfig: @@ -1825,8 +1797,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -1955,8 +1925,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateBackendbind9: properties: @@ -1966,8 +1934,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2045,8 +2011,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateCentral: properties: @@ -2056,8 +2020,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2135,8 +2097,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateMdns: properties: @@ -2146,8 +2106,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2225,8 +2183,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateProducer: properties: @@ -2236,8 +2192,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2315,13 +2269,9 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object designateUnbound: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2379,8 +2329,6 @@ spec: type: object serviceAccount: type: string - required: - - containerImage type: object designateWorker: properties: @@ -2390,8 +2338,6 @@ spec: type: string backendWorkerServerProtocol: type: string - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -2469,8 +2415,6 @@ spec: type: string transportURLSecret: type: string - required: - - containerImage type: object nodeSelector: additionalProperties: @@ -3405,8 +3349,6 @@ spec: host: type: string type: object - containerImage: - type: string customServiceConfig: type: string disableNonTLSListeners: @@ -3437,7 +3379,6 @@ spec: type: string type: object required: - - containerImage - replicas - secret - storageClass @@ -3560,8 +3501,6 @@ spec: type: boolean template: properties: - containerImage: - type: string customServiceConfig: type: string customServiceConfigSecrets: @@ -4561,7 +4500,6 @@ spec: storageRequest: type: string required: - - containerImage - databaseInstance - glanceAPIs - imageCache @@ -4803,8 +4741,6 @@ spec: type: object heatAPI: properties: - containerImage: - type: string customServiceConfig: type: string defaultConfigOverwrite: @@ -4921,13 +4857,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object heatCfnAPI: properties: - containerImage: - type: string customServiceConfig: type: string defaultConfigOverwrite: @@ -5044,13 +4976,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object heatEngine: properties: - containerImage: - type: string customServiceConfig: type: string defaultConfigOverwrite: @@ -5098,8 +5026,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object memcachedInstance: default: memcached @@ -5254,8 +5180,6 @@ spec: type: boolean template: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -6125,7 +6049,6 @@ spec: type: string type: object required: - - containerImage - memcachedInstance - secret type: object @@ -6361,21 +6284,6 @@ spec: additionalProperties: type: string type: object - images: - properties: - api: - type: string - conductor: - type: string - inspector: - type: string - ironicPythonAgent: - type: string - neutronAgent: - type: string - pxe: - type: string - type: object ironicAPI: properties: customServiceConfig: @@ -6978,8 +6886,6 @@ spec: adminUser: default: admin type: string - containerImage: - type: string customServiceConfig: type: string databaseAccount: @@ -7143,7 +7049,6 @@ spec: default: false type: boolean required: - - containerImage - databaseInstance - memcachedInstance - rabbitMqClusterName @@ -8045,8 +7950,6 @@ spec: type: array manilaAPI: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -8168,13 +8071,9 @@ spec: caBundleSecretName: type: string type: object - required: - - containerImage type: object manilaScheduler: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -8227,14 +8126,10 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object manilaShares: additionalProperties: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -8287,8 +8182,6 @@ spec: x-kubernetes-int-or-string: true type: object type: object - required: - - containerImage type: object type: object memcachedInstance: @@ -8332,8 +8225,6 @@ spec: templates: additionalProperties: properties: - containerImage: - type: string replicas: default: 1 format: int32 @@ -8345,8 +8236,6 @@ spec: secretName: type: string type: object - required: - - containerImage type: object type: object type: object @@ -8463,8 +8352,6 @@ spec: type: boolean template: properties: - containerImage: - type: string customServiceConfig: type: string databaseAccount: @@ -9374,7 +9261,6 @@ spec: type: object type: object required: - - containerImage - databaseInstance - memcachedInstance - rabbitMqClusterName @@ -10505,8 +10391,6 @@ spec: type: object octaviaAPI: properties: - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -10662,7 +10546,6 @@ spec: transportURLSecret: type: string required: - - containerImage - databaseInstance - secret - serviceAccount @@ -10691,8 +10574,6 @@ spec: - name type: object type: array - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -10819,8 +10700,6 @@ spec: - name type: object type: array - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -10947,8 +10826,6 @@ spec: - name type: object type: array - containerImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -11193,10 +11070,6 @@ spec: additionalProperties: type: string type: object - ovnContainerImage: - type: string - ovsContainerImage: - type: string resources: properties: claims: @@ -11235,15 +11108,10 @@ spec: secretName: type: string type: object - required: - - ovnContainerImage - - ovsContainerImage type: object ovnDBCluster: additionalProperties: properties: - containerImage: - type: string dbType: default: NB pattern: ^NB|SB$ @@ -11318,15 +11186,12 @@ spec: type: string type: object required: - - containerImage - dbType - storageRequest type: object type: object ovnNorthd: properties: - containerImage: - type: string logLevel: default: info type: string @@ -11384,8 +11249,6 @@ spec: secretName: type: string type: object - required: - - containerImage type: object type: object type: object @@ -11502,8 +11365,6 @@ spec: type: boolean template: properties: - containerImage: - type: string customServiceConfig: type: string databaseAccount: @@ -11646,7 +11507,6 @@ spec: type: string type: object required: - - containerImage - databaseInstance - secret type: object @@ -12029,16 +11889,6 @@ spec: format: int32 minimum: 0 type: integer - image: - type: string - imagePullSecrets: - items: - properties: - name: - type: string - type: object - x-kubernetes-map-type: atomic - type: array override: properties: service: @@ -15694,8 +15544,6 @@ spec: type: object type: object service: - default: - type: ClusterIP properties: annotations: additionalProperties: @@ -15758,8 +15606,6 @@ spec: templates: additionalProperties: properties: - containerImage: - type: string replicas: default: 1 format: int32 @@ -15771,8 +15617,6 @@ spec: secretName: type: string type: object - required: - - containerImage type: object type: object type: object @@ -15908,8 +15752,6 @@ spec: ceilometerEnabled: default: false type: boolean - containerImageProxy: - type: string defaultConfigOverwrite: additionalProperties: type: string @@ -16016,7 +15858,6 @@ spec: type: string type: object required: - - containerImageProxy - memcachedServers - rabbitMqClusterName - replicas @@ -16025,8 +15866,6 @@ spec: type: object swiftRing: properties: - containerImage: - type: string minPartHours: default: 1 format: int64 @@ -16048,21 +15887,12 @@ spec: type: string type: object required: - - containerImage - minPartHours - partPower - ringReplicas type: object swiftStorage: properties: - containerImageAccount: - type: string - containerImageContainer: - type: string - containerImageObject: - type: string - containerImageProxy: - type: string containerSharderEnabled: default: false type: boolean @@ -16089,10 +15919,6 @@ spec: default: 10Gi type: string required: - - containerImageAccount - - containerImageContainer - - containerImageObject - - containerImageProxy - memcachedServers - replicas - storageClass @@ -16435,8 +16261,6 @@ spec: properties: aodh: properties: - apiImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -16449,10 +16273,6 @@ spec: additionalProperties: type: string type: object - evaluatorImage: - type: string - listenerImage: - type: string memcachedInstance: default: memcached type: string @@ -16460,8 +16280,6 @@ spec: items: type: string type: array - notifierImage: - type: string override: properties: service: @@ -16554,12 +16372,8 @@ spec: type: string type: object required: - - apiImage - databaseInstance - - evaluatorImage - - listenerImage - memcachedInstance - - notifierImage - secret type: object enabled: @@ -16582,10 +16396,6 @@ spec: type: object ceilometer: properties: - centralImage: - type: string - computeImage: - type: string customServiceConfig: default: '# add your customization here' type: string @@ -16596,14 +16406,10 @@ spec: enabled: default: true type: boolean - ipmiImage: - type: string networkAttachmentDefinitions: items: type: string type: array - notificationImage: - type: string passwordSelector: default: service: CeilometerPassword @@ -16615,8 +16421,6 @@ spec: default: CeilometerPassword type: string type: object - proxyImage: - type: string rabbitMqClusterName: default: rabbitmq type: string @@ -16625,8 +16429,6 @@ spec: serviceUser: default: ceilometer type: string - sgCoreImage: - type: string tls: properties: caBundleSecretName: @@ -16635,13 +16437,7 @@ spec: type: string type: object required: - - centralImage - - computeImage - - ipmiImage - - notificationImage - - proxyImage - secret - - sgCoreImage type: object logging: properties: @@ -17443,6 +17239,169 @@ spec: - type type: object type: array + containerImages: + properties: + agentImage: + type: string + ansibleeeImage: + type: string + aodhAPIImage: + type: string + aodhEvaluatorImage: + type: string + aodhListenerImage: + type: string + aodhNotifierImage: + type: string + apacheImage: + type: string + barbicanAPIImage: + type: string + barbicanKeystoneListenerImage: + type: string + barbicanWorkerImage: + type: string + ceilometerCentralImage: + type: string + ceilometerComputeImage: + type: string + ceilometerIpmiImage: + type: string + ceilometerNotificationImage: + type: string + ceilometerSgcoreImage: + type: string + cinderAPIImage: + type: string + cinderBackupImage: + type: string + cinderSchedulerImage: + type: string + cinderVolumeImages: + additionalProperties: + type: string + type: object + designateAPIImage: + type: string + designateBackendbind9Image: + type: string + designateCentralImage: + type: string + designateMdnsImage: + type: string + designateProducerImage: + type: string + designateUnboundImage: + type: string + designateWorkerImage: + type: string + edpmFrrImage: + type: string + edpmIscsidImage: + type: string + edpmLogrotateCrondImage: + type: string + edpmNeutronMetadataAgentImage: + type: string + edpmNeutronSriovAgentImage: + type: string + edpmNodeExporterImage: + type: string + edpmOvnBgpAgentImage: + type: string + glanceAPIImage: + type: string + heatAPIImage: + type: string + heatCfnapiImage: + type: string + heatEngineImage: + type: string + horizonImage: + type: string + infraDnsmasqImage: + type: string + infraMemcachedImage: + type: string + infraRedisImage: + type: string + ironicAPIImage: + type: string + ironicConductorImage: + type: string + ironicInspectorImage: + type: string + ironicNeutronAgentImage: + type: string + ironicPxeImage: + type: string + ironicPythonAgentImage: + type: string + keystoneAPIImage: + type: string + manilaAPIImage: + type: string + manilaSchedulerImage: + type: string + manilaShareImages: + additionalProperties: + type: string + type: object + mariadbImage: + type: string + neutronAPIImage: + type: string + novaAPIImage: + type: string + novaComputeImage: + type: string + novaConductorImage: + type: string + novaNovncImage: + type: string + novaSchedulerImage: + type: string + octaviaAPIImage: + type: string + octaviaHealthmanagerImage: + type: string + octaviaHousekeepingImage: + type: string + octaviaWorkerImage: + type: string + openstackClientImage: + type: string + osContainerImage: + type: string + ovnControllerImage: + type: string + ovnControllerOvsImage: + type: string + ovnNbDbclusterImage: + type: string + ovnNorthdImage: + type: string + ovnSbDbclusterImage: + type: string + placementAPIImage: + type: string + rabbitmqImage: + type: string + swiftAccountImage: + type: string + swiftContainerImage: + type: string + swiftObjectImage: + type: string + swiftProxyImage: + type: string + telemetryNodeExporterImage: + type: string + type: object + deployedOVNVersion: + type: string + deployedVersion: + type: string tls: properties: caBundleSecretName: diff --git a/config/crd/bases/core.openstack.org_openstackversions.yaml b/config/crd/bases/core.openstack.org_openstackversions.yaml new file mode 100644 index 000000000..84205f3b9 --- /dev/null +++ b/config/crd/bases/core.openstack.org_openstackversions.yaml @@ -0,0 +1,553 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: openstackversions.core.openstack.org +spec: + group: core.openstack.org + names: + kind: OpenStackVersion + listKind: OpenStackVersionList + plural: openstackversions + singular: openstackversion + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetVersion + name: Target Version + type: string + - jsonPath: .status.availableVersion + name: Available Version + type: string + - jsonPath: .status.deployedVersion + name: Deployed Version + type: string + name: v1beta1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + customContainerImages: + properties: + agentImage: + type: string + ansibleeeImage: + type: string + aodhAPIImage: + type: string + aodhEvaluatorImage: + type: string + aodhListenerImage: + type: string + aodhNotifierImage: + type: string + apacheImage: + type: string + barbicanAPIImage: + type: string + barbicanKeystoneListenerImage: + type: string + barbicanWorkerImage: + type: string + ceilometerCentralImage: + type: string + ceilometerComputeImage: + type: string + ceilometerIpmiImage: + type: string + ceilometerNotificationImage: + type: string + ceilometerSgcoreImage: + type: string + cinderAPIImage: + type: string + cinderBackupImage: + type: string + cinderSchedulerImage: + type: string + cinderVolumeImages: + additionalProperties: + type: string + type: object + designateAPIImage: + type: string + designateBackendbind9Image: + type: string + designateCentralImage: + type: string + designateMdnsImage: + type: string + designateProducerImage: + type: string + designateUnboundImage: + type: string + designateWorkerImage: + type: string + edpmFrrImage: + type: string + edpmIscsidImage: + type: string + edpmLogrotateCrondImage: + type: string + edpmNeutronMetadataAgentImage: + type: string + edpmNeutronSriovAgentImage: + type: string + edpmNodeExporterImage: + type: string + edpmOvnBgpAgentImage: + type: string + glanceAPIImage: + type: string + heatAPIImage: + type: string + heatCfnapiImage: + type: string + heatEngineImage: + type: string + horizonImage: + type: string + infraDnsmasqImage: + type: string + infraMemcachedImage: + type: string + infraRedisImage: + type: string + ironicAPIImage: + type: string + ironicConductorImage: + type: string + ironicInspectorImage: + type: string + ironicNeutronAgentImage: + type: string + ironicPxeImage: + type: string + ironicPythonAgentImage: + type: string + keystoneAPIImage: + type: string + manilaAPIImage: + type: string + manilaSchedulerImage: + type: string + manilaShareImages: + additionalProperties: + type: string + type: object + mariadbImage: + type: string + neutronAPIImage: + type: string + novaAPIImage: + type: string + novaComputeImage: + type: string + novaConductorImage: + type: string + novaNovncImage: + type: string + novaSchedulerImage: + type: string + octaviaAPIImage: + type: string + octaviaHealthmanagerImage: + type: string + octaviaHousekeepingImage: + type: string + octaviaWorkerImage: + type: string + openstackClientImage: + type: string + osContainerImage: + type: string + ovnControllerImage: + type: string + ovnControllerOvsImage: + type: string + ovnNbDbclusterImage: + type: string + ovnNorthdImage: + type: string + ovnSbDbclusterImage: + type: string + placementAPIImage: + type: string + rabbitmqImage: + type: string + swiftAccountImage: + type: string + swiftContainerImage: + type: string + swiftObjectImage: + type: string + swiftProxyImage: + type: string + telemetryNodeExporterImage: + type: string + type: object + targetVersion: + type: string + required: + - targetVersion + type: object + status: + properties: + availableVersion: + type: string + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + severity: + type: string + status: + type: string + type: + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + containerImageVersionDefaults: + additionalProperties: + properties: + agentImage: + type: string + ansibleeeImage: + type: string + aodhAPIImage: + type: string + aodhEvaluatorImage: + type: string + aodhListenerImage: + type: string + aodhNotifierImage: + type: string + apacheImage: + type: string + barbicanAPIImage: + type: string + barbicanKeystoneListenerImage: + type: string + barbicanWorkerImage: + type: string + ceilometerCentralImage: + type: string + ceilometerComputeImage: + type: string + ceilometerIpmiImage: + type: string + ceilometerNotificationImage: + type: string + ceilometerSgcoreImage: + type: string + cinderAPIImage: + type: string + cinderBackupImage: + type: string + cinderSchedulerImage: + type: string + cinderVolumeImage: + type: string + designateAPIImage: + type: string + designateBackendbind9Image: + type: string + designateCentralImage: + type: string + designateMdnsImage: + type: string + designateProducerImage: + type: string + designateUnboundImage: + type: string + designateWorkerImage: + type: string + edpmFrrImage: + type: string + edpmIscsidImage: + type: string + edpmLogrotateCrondImage: + type: string + edpmNeutronMetadataAgentImage: + type: string + edpmNeutronSriovAgentImage: + type: string + edpmNodeExporterImage: + type: string + edpmOvnBgpAgentImage: + type: string + glanceAPIImage: + type: string + heatAPIImage: + type: string + heatCfnapiImage: + type: string + heatEngineImage: + type: string + horizonImage: + type: string + infraDnsmasqImage: + type: string + infraMemcachedImage: + type: string + infraRedisImage: + type: string + ironicAPIImage: + type: string + ironicConductorImage: + type: string + ironicInspectorImage: + type: string + ironicNeutronAgentImage: + type: string + ironicPxeImage: + type: string + ironicPythonAgentImage: + type: string + keystoneAPIImage: + type: string + manilaAPIImage: + type: string + manilaSchedulerImage: + type: string + manilaShareImage: + type: string + mariadbImage: + type: string + neutronAPIImage: + type: string + novaAPIImage: + type: string + novaComputeImage: + type: string + novaConductorImage: + type: string + novaNovncImage: + type: string + novaSchedulerImage: + type: string + octaviaAPIImage: + type: string + octaviaHealthmanagerImage: + type: string + octaviaHousekeepingImage: + type: string + octaviaWorkerImage: + type: string + openstackClientImage: + type: string + osContainerImage: + type: string + ovnControllerImage: + type: string + ovnControllerOvsImage: + type: string + ovnNbDbclusterImage: + type: string + ovnNorthdImage: + type: string + ovnSbDbclusterImage: + type: string + placementAPIImage: + type: string + rabbitmqImage: + type: string + swiftAccountImage: + type: string + swiftContainerImage: + type: string + swiftObjectImage: + type: string + swiftProxyImage: + type: string + telemetryNodeExporterImage: + type: string + type: object + type: object + containerImages: + properties: + agentImage: + type: string + ansibleeeImage: + type: string + aodhAPIImage: + type: string + aodhEvaluatorImage: + type: string + aodhListenerImage: + type: string + aodhNotifierImage: + type: string + apacheImage: + type: string + barbicanAPIImage: + type: string + barbicanKeystoneListenerImage: + type: string + barbicanWorkerImage: + type: string + ceilometerCentralImage: + type: string + ceilometerComputeImage: + type: string + ceilometerIpmiImage: + type: string + ceilometerNotificationImage: + type: string + ceilometerSgcoreImage: + type: string + cinderAPIImage: + type: string + cinderBackupImage: + type: string + cinderSchedulerImage: + type: string + cinderVolumeImages: + additionalProperties: + type: string + type: object + designateAPIImage: + type: string + designateBackendbind9Image: + type: string + designateCentralImage: + type: string + designateMdnsImage: + type: string + designateProducerImage: + type: string + designateUnboundImage: + type: string + designateWorkerImage: + type: string + edpmFrrImage: + type: string + edpmIscsidImage: + type: string + edpmLogrotateCrondImage: + type: string + edpmNeutronMetadataAgentImage: + type: string + edpmNeutronSriovAgentImage: + type: string + edpmNodeExporterImage: + type: string + edpmOvnBgpAgentImage: + type: string + glanceAPIImage: + type: string + heatAPIImage: + type: string + heatCfnapiImage: + type: string + heatEngineImage: + type: string + horizonImage: + type: string + infraDnsmasqImage: + type: string + infraMemcachedImage: + type: string + infraRedisImage: + type: string + ironicAPIImage: + type: string + ironicConductorImage: + type: string + ironicInspectorImage: + type: string + ironicNeutronAgentImage: + type: string + ironicPxeImage: + type: string + ironicPythonAgentImage: + type: string + keystoneAPIImage: + type: string + manilaAPIImage: + type: string + manilaSchedulerImage: + type: string + manilaShareImages: + additionalProperties: + type: string + type: object + mariadbImage: + type: string + neutronAPIImage: + type: string + novaAPIImage: + type: string + novaComputeImage: + type: string + novaConductorImage: + type: string + novaNovncImage: + type: string + novaSchedulerImage: + type: string + octaviaAPIImage: + type: string + octaviaHealthmanagerImage: + type: string + octaviaHousekeepingImage: + type: string + octaviaWorkerImage: + type: string + openstackClientImage: + type: string + osContainerImage: + type: string + ovnControllerImage: + type: string + ovnControllerOvsImage: + type: string + ovnNbDbclusterImage: + type: string + ovnNorthdImage: + type: string + ovnSbDbclusterImage: + type: string + placementAPIImage: + type: string + rabbitmqImage: + type: string + swiftAccountImage: + type: string + swiftContainerImage: + type: string + swiftObjectImage: + type: string + swiftProxyImage: + type: string + telemetryNodeExporterImage: + type: string + type: object + deployedVersion: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 114617be1..b5f05ac15 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -41,6 +41,9 @@ spec: - /manager args: - --leader-elect + env: + - name: OPENSTACK_RELEASE_VERSION + value: 0.0.1 image: controller:latest name: manager securityContext: diff --git a/config/manifests/bases/openstack-operator.clusterserviceversion.yaml b/config/manifests/bases/openstack-operator.clusterserviceversion.yaml index cb1012746..fbd72ea0e 100644 --- a/config/manifests/bases/openstack-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/openstack-operator.clusterserviceversion.yaml @@ -440,6 +440,27 @@ spec: displayName: Cert path: tls.podLevel.ovn.cert statusDescriptors: + - description: Conditions + displayName: Conditions + path: conditions + x-descriptors: + - urn:alm:descriptor:io.kubernetes.conditions + - description: DeployedOVNVersion + displayName: Deployed OVNVersion + path: deployedOVNVersion + - description: DeployedVersion + displayName: Deployed Version + path: deployedVersion + - description: TLS + displayName: TLS + path: tls + version: v1beta1 + - description: OpenStackVersion is the Schema for the openstackversionupdates + API + displayName: OpenStack Version + kind: OpenStackVersion + name: openstackversions.core.openstack.org + statusDescriptors: - description: Conditions displayName: Conditions path: conditions diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 349f26dab..bdf559f35 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -154,6 +154,32 @@ rules: - get - patch - update +- apiGroups: + - core.openstack.org + resources: + - openstackversions + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - core.openstack.org + resources: + - openstackversions/finalizers + verbs: + - update +- apiGroups: + - core.openstack.org + resources: + - openstackversions/status + verbs: + - get + - patch + - update - apiGroups: - designate.openstack.org resources: diff --git a/config/samples/core_v1beta1_openstackcontrolplane_lightweight.yaml b/config/samples/core_v1beta1_openstackcontrolplane_lightweight.yaml deleted file mode 100644 index 2abc19560..000000000 --- a/config/samples/core_v1beta1_openstackcontrolplane_lightweight.yaml +++ /dev/null @@ -1,195 +0,0 @@ -apiVersion: core.openstack.org/v1beta1 -kind: OpenStackControlPlane -metadata: - name: openstack-basic -spec: - secret: osp-secret - storageClass: local-storage - #tls: - # endpoint: - # internal: - # enabled: false - # public: - # enabled: true - keystone: - template: - databaseInstance: openstack - secret: osp-secret - mariadb: - templates: - openstack: - storageRequest: 500M - openstack-cell1: - storageRequest: 500M - galera: - enabled: false - templates: - openstack: - storageClass: local-storage - storageRequest: 500M - secret: osp-secret - replicas: 1 - openstack-cell1: - storageClass: local-storage - storageRequest: 500M - secret: osp-secret - replicas: 1 - rabbitmq: - templates: - rabbitmq: - replicas: 1 - #resources: - # requests: - # cpu: 500m - # memory: 1Gi - # limits: - # cpu: 800m - # memory: 1Gi - rabbitmq-cell1: - replicas: 1 - memcached: - templates: - memcached: - replicas: 1 - barbican: - enabled: false - template: - databaseInstance: openstack - secret: osp-secret - barbicanAPI: - replicas: 1 - barbicanWorker: - replicas: 1 - barbicanKeystoneListener: - replicas: 1 - placement: - template: - databaseInstance: openstack - secret: osp-secret - glance: - template: - secret: osp-secret - databaseInstance: openstack - storageClass: "" - storageRequest: 10G - glanceAPI: - type: single - replicas: 1 - cinder: - template: - databaseInstance: openstack - secret: osp-secret - cinderAPI: - replicas: 1 - cinderScheduler: - replicas: 1 - cinderBackup: - replicas: 0 # backend needs to be configured - cinderVolumes: - volume1: - replicas: 0 # backend needs to be configured - manila: - enabled: false - template: - manilaAPI: - replicas: 1 - manilaScheduler: - replicas: 1 - manilaShares: - share1: - replicas: 1 - ovn: - template: - ovnDBCluster: - ovndbcluster-nb: - replicas: 1 - dbType: NB - storageRequest: 10G - ovndbcluster-sb: - replicas: 1 - dbType: SB - storageRequest: 10G - ovnNorthd: - replicas: 1 - ovnController: - external-ids: - system-id: "random" - ovn-bridge: "br-int" - ovn-encap-type: "geneve" - neutron: - template: - databaseInstance: openstack - secret: osp-secret - horizon: - enabled: false - template: - replicas: 1 - secret: osp-secret - nova: - template: - secret: osp-secret - heat: - enabled: false - template: - databaseInstance: openstack - heatAPI: - replicas: 1 - heatEngine: - replicas: 1 - secret: osp-secret - ironic: - enabled: false - template: - databaseInstance: openstack - ironicAPI: - replicas: 1 - ironicConductors: - - replicas: 1 - storageRequest: 10G - ironicInspector: - replicas: 1 - ironicNeutronAgent: - replicas: 1 - secret: osp-secret - ceilometer: - enabled: false - template: - passwordSelector: - service: CeilometerPassword - secret: osp-secret - serviceUser: ceilometer - swift: - enabled: false - template: - swiftRing: - ringReplicas: 1 - swiftStorage: - replicas: 1 - swiftProxy: - replicas: 1 - octavia: - enabled: false - template: - databaseInstance: openstack - octaviaAPI: - replicas: 1 - secret: osp-secret - redis: - enabled: false - designate: - enabled: false - template: - databaseInstance: openstack - secret: osp-secret - designateAPI: - replicas: 1 - designateCentral: - replicas: 0 # backend needs to be configured - designateWorker: - replicas: 0 # backend needs to be configured - designateProducer: - replicas: 0 # backend needs to be configured - designateMdns: - replicas: 0 # backend needs to be configured - designateBackendbind9: - replicas: 0 # backend needs to be configured diff --git a/config/samples/core_v1beta1_openstackversion.yaml b/config/samples/core_v1beta1_openstackversion.yaml index 0649671d8..cd1d13170 100644 --- a/config/samples/core_v1beta1_openstackversion.yaml +++ b/config/samples/core_v1beta1_openstackversion.yaml @@ -2,11 +2,16 @@ apiVersion: core.openstack.org/v1beta1 kind: OpenStackVersion metadata: labels: - app.kubernetes.io/name: openstackversion - app.kubernetes.io/instance: openstackversion-sample - app.kubernetes.io/part-of: openstack-operator - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: openstack-operator - name: openstackversion-sample + #app.kubernetes.io/name: openstackversionupdate + #app.kubernetes.io/instance: openstackversionupdate-sample + #app.kubernetes.io/part-of: openstack-operator + #app.kubernetes.io/managed-by: kustomize + #app.kubernetes.io/created-by: openstack-operator + name: openstack spec: - # TODO(user): Add fields here + targetVersion: 1.0.1 + customContainerImages: + cinderApiImage: + cinderVolumeImages: + netapp: + dell: diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index c483ffaac..b5d33b665 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -45,6 +45,26 @@ webhooks: resources: - openstackcontrolplanes sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-core-openstack-org-v1beta1-openstackversion + failurePolicy: Fail + name: mopenstackversion.kb.io + rules: + - apiGroups: + - core.openstack.org + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - openstackversions + sideEffects: None --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration @@ -92,3 +112,23 @@ webhooks: resources: - openstackcontrolplanes sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-core-openstack-org-v1beta1-openstackversion + failurePolicy: Fail + name: vopenstackversion.kb.io + rules: + - apiGroups: + - core.openstack.org + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - openstackversions + sideEffects: None diff --git a/controllers/core/openstackcontrolplane_controller.go b/controllers/core/openstackcontrolplane_controller.go index 6c23f0199..e5ec0c1a0 100644 --- a/controllers/core/openstackcontrolplane_controller.go +++ b/controllers/core/openstackcontrolplane_controller.go @@ -57,6 +57,7 @@ import ( "k8s.io/client-go/kubernetes" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" ) @@ -75,6 +76,7 @@ func (r *OpenStackControlPlaneReconciler) GetLogger(ctx context.Context) logr.Lo //+kubebuilder:rbac:groups=core.openstack.org,resources=openstackcontrolplanes,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=core.openstack.org,resources=openstackcontrolplanes/status,verbs=get;update;patch //+kubebuilder:rbac:groups=core.openstack.org,resources=openstackcontrolplanes/finalizers,verbs=update +//+kubebuilder:rbac:groups=core.openstack.org,resources=openstackversions,verbs=get;list;create //+kubebuilder:rbac:groups=ironic.openstack.org,resources=ironics,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=client.openstack.org,resources=openstackclients,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=horizon.openstack.org,resources=horizons,verbs=get;list;watch;create;update;patch;delete @@ -164,16 +166,83 @@ func (r *OpenStackControlPlaneReconciler) Reconcile(ctx context.Context, req ctr } }() - if instance.Status.Conditions == nil { - instance.InitConditions() - // Register overall status immediately to have an early feedback e.g. in the cli + instance.InitConditions() + + Log.Info("Looking up the current OpenStackVersion") + ctrlResult, version, err := openstack.ReconcileVersion(ctx, instance, helper) + if err != nil { + return ctrl.Result{}, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + + // wait until the version is initialized so we have images on the version.Status + if !version.Status.Conditions.IsTrue(corev1beta1.OpenStackVersionInitialized) { + return ctrlResult, nil + } + + if instance.Status.DeployedVersion == nil || version.Spec.TargetVersion == *instance.Status.DeployedVersion { + // green field deployment or no minor update in progress + ctrlResult, err := r.reconcileNormal(ctx, instance, version, helper) + if err != nil { + Log.Info("Error reconciling normal", "error", err) + return ctrl.Result{}, err + } else if (ctrlResult != ctrl.Result{}) { + Log.Info("Reconciling normal") + return ctrlResult, nil + } + // this will allow reconcileNormal to proceed in subsequent reconciles + instance.Status.DeployedVersion = &version.Spec.TargetVersion return ctrl.Result{}, nil + } else { + if !version.Status.Conditions.IsTrue(corev1beta1.OpenStackVersionMinorUpdateOVNControlplane) { + Log.Info("Minor update OVN on the ControlPlane") + ctrlResult, err := r.reconcileOVNControllers(ctx, instance, version, helper) + if err != nil { + return ctrl.Result{}, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + instance.Status.DeployedOVNVersion = &version.Spec.TargetVersion + return ctrl.Result{}, nil + } else if !version.Status.Conditions.IsTrue(corev1beta1.OpenStackVersionMinorUpdateControlplane) { + Log.Info("Minor update on the ControlPlane") + ctrlResult, err := r.reconcileNormal(ctx, instance, version, helper) + if err != nil { + return ctrl.Result{}, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + // this will allow reconcileNormal to proceed in subsequent reconciles + instance.Status.DeployedVersion = &version.Spec.TargetVersion + return ctrl.Result{}, nil + } else { + Log.Info("Skipping reconcile. Waiting on minor update to proceed.") + return ctrl.Result{}, nil + } } - return r.reconcileNormal(ctx, instance, helper) } -func (r *OpenStackControlPlaneReconciler) reconcileNormal(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func (r *OpenStackControlPlaneReconciler) reconcileOVNControllers(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { + + OVNControllerReady, err := openstack.ReconcileOVNController(ctx, instance, version, helper) + if err != nil { + return ctrl.Result{}, err + } else if !OVNControllerReady { + instance.Status.Conditions.Set(condition.FalseCondition( + corev1beta1.OpenStackControlPlaneOVNReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + corev1beta1.OpenStackControlPlaneOVNReadyRunningMessage)) + } else { + instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneOVNReadyCondition, corev1beta1.OpenStackControlPlaneOVNReadyMessage) + } + return ctrl.Result{}, nil + +} + +func (r *OpenStackControlPlaneReconciler) reconcileNormal(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { ctrlResult, err := openstack.ReconcileCAs(ctx, instance, helper) if err != nil { @@ -182,154 +251,154 @@ func (r *OpenStackControlPlaneReconciler) reconcileNormal(ctx context.Context, i return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileDNSMasqs(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileDNSMasqs(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileRabbitMQs(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileRabbitMQs(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileGaleras(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileGaleras(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileMemcacheds(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileMemcacheds(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileKeystoneAPI(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileKeystoneAPI(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcilePlacementAPI(ctx, instance, helper) + ctrlResult, err = openstack.ReconcilePlacementAPI(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileGlance(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileGlance(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileCinder(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileCinder(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileOVN(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileOVN(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileNeutron(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileNeutron(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileNova(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileNova(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileHeat(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileHeat(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileIronic(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileIronic(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileOpenStackClient(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileOpenStackClient(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileManila(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileManila(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileHorizon(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileHorizon(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileTelemetry(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileTelemetry(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileBarbican(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileBarbican(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileRedis(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileRedis(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileOctavia(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileOctavia(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileDesignate(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileDesignate(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { return ctrlResult, nil } - ctrlResult, err = openstack.ReconcileSwift(ctx, instance, helper) + ctrlResult, err = openstack.ReconcileSwift(ctx, instance, version, helper) if err != nil { return ctrl.Result{}, err } else if (ctrlResult != ctrl.Result{}) { @@ -341,6 +410,7 @@ func (r *OpenStackControlPlaneReconciler) reconcileNormal(ctx context.Context, i // SetupWithManager sets up the controller with the Manager. func (r *OpenStackControlPlaneReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). For(&corev1beta1.OpenStackControlPlane{}). Owns(&clientv1.OpenStackClient{}). @@ -370,5 +440,6 @@ func (r *OpenStackControlPlaneReconciler) SetupWithManager(mgr ctrl.Manager) err Owns(&certmgrv1.Issuer{}). Owns(&certmgrv1.Certificate{}). Owns(&barbicanv1.Barbican{}). + Owns(&corev1beta1.OpenStackVersion{}). Complete(r) } diff --git a/controllers/core/openstackversion_controller.go b/controllers/core/openstackversion_controller.go index 6e30284db..2c0ff6515 100644 --- a/controllers/core/openstackversion_controller.go +++ b/controllers/core/openstackversion_controller.go @@ -1,5 +1,5 @@ /* -Copyright 2022. +Copyright 2023. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,19 +18,64 @@ package core import ( "context" + "os" + "strings" + k8s_errors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/go-logr/logr" + condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition" + "github.com/openstack-k8s-operators/lib-common/modules/common/helper" corev1beta1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" + "github.com/openstack-k8s-operators/openstack-operator/pkg/openstack" ) +var envContainerImages (map[string]*string) +var envAvailableVersion string + +// SetupVersionDefaults - +func SetupVersionDefaults() { + localVars := make(map[string]*string) + for _, name := range os.Environ() { + envArr := strings.Split(name, "=") + if envArr[0] == "OPENSTACK_RELEASE_VERSION" { + envAvailableVersion = envArr[1] + } + if strings.HasPrefix(envArr[0], "RELATED_IMAGE_") { + localVars[envArr[0]] = &envArr[1] + } + } + envContainerImages = localVars +} + +func compareStringPointers(a, b *string) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + return *a == *b +} + // OpenStackVersionReconciler reconciles a OpenStackVersion object type OpenStackVersionReconciler struct { client.Client - Scheme *runtime.Scheme + Kclient kubernetes.Interface + Scheme *runtime.Scheme + Log logr.Logger +} + +// GetLogger returns a logger object with a prefix of "controller.name" and additional controller context fields +func (r *OpenStackVersionReconciler) GetLogger(ctx context.Context) logr.Logger { + return log.FromContext(ctx).WithName("Controllers").WithName("OpenStackVersion") } //+kubebuilder:rbac:groups=core.openstack.org,resources=openstackversions,verbs=get;list;watch;create;update;patch;delete @@ -39,24 +84,212 @@ type OpenStackVersionReconciler struct { // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the OpenStackVersion object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile -func (r *OpenStackVersionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx) +func (r *OpenStackVersionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, _err error) { + + Log := r.GetLogger(ctx) + Log.Info("Reconciling OpenStackVersion") + // Fetch the instance + instance := &corev1beta1.OpenStackVersion{} + err := r.Client.Get(ctx, req.NamespacedName, instance) + if err != nil { + if k8s_errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. + // For additional cleanup logic use finalizers. Return and don't requeue. + return ctrl.Result{}, nil + } + // Error reading the object - requeue the request. + return ctrl.Result{}, err + } + + isNewInstance := instance.Status.Conditions == nil + if isNewInstance { + instance.Status.Conditions = condition.Conditions{} + } + + versionHelper, err := helper.NewHelper( + instance, + r.Client, + r.Kclient, + r.Scheme, + Log, + ) + if err != nil { + Log.Error(err, "unable to create helper") + return ctrl.Result{}, err + } + + // Always patch the instance status when exiting this function so we can persist any changes. + defer func() { + // update the Ready condition based on the sub conditions + if instance.Status.Conditions.AllSubConditionIsTrue() { + instance.Status.Conditions.MarkTrue( + condition.ReadyCondition, condition.ReadyMessage) + } else { + // something is not ready so reset the Ready condition + instance.Status.Conditions.MarkUnknown( + condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage) + // and recalculate it based on the state of the rest of the conditions + instance.Status.Conditions.Set( + instance.Status.Conditions.Mirror(condition.ReadyCondition)) + } + + err := versionHelper.PatchInstance(ctx, instance) + if err != nil { + _err = err + return + } + }() + + // greenfield deployment + cl := condition.CreateList( + condition.UnknownCondition(corev1beta1.OpenStackVersionInitialized, condition.InitReason, string(corev1beta1.OpenStackVersionInitializedInitMessage)), + ) + // no minor update conditions unless we have a deployed version + if instance.Status.DeployedVersion != nil && instance.Spec.TargetVersion != *instance.Status.DeployedVersion { + cl = append(cl, *condition.UnknownCondition(corev1beta1.OpenStackVersionMinorUpdateOVNControlplane, condition.InitReason, string(corev1beta1.OpenStackVersionMinorUpdateInitMessage)), + *condition.UnknownCondition(corev1beta1.OpenStackVersionMinorUpdateControlplane, condition.InitReason, string(corev1beta1.OpenStackVersionMinorUpdateInitMessage))) + // fixme add dataplane conditions here + //condition.UnknownCondition(corev1beta1.OpenStackVersionMinorUpdateOVNDataplane, condition.InitReason, string(corev1beta1.OpenStackVersionMinorUpdateInitMessage)), + //condition.UnknownCondition(corev1beta1.OpenStackVersionMinorUpdateDataplane, condition.InitReason, string(corev1beta1.OpenStackVersionMinorUpdateInitMessage))) + } + instance.Status.Conditions.Init(&cl) + if isNewInstance { + // Register overall status immediately to have an early feedback e.g. in the cli + return ctrl.Result{}, nil + } + + instance.Status.Conditions.Set(condition.FalseCondition( + corev1beta1.OpenStackVersionInitialized, + condition.RequestedReason, + condition.SeverityInfo, + corev1beta1.OpenStackVersionInitializedReadyRunningMessage)) - // TODO(user): your logic here + instance.Status.AvailableVersion = &envAvailableVersion + defaults := openstack.InitializeOpenStackVersionImageDefaults(ctx, envContainerImages) + // store the defaults for the currently available version + if instance.Status.ContainerImageVersionDefaults == nil { + instance.Status.ContainerImageVersionDefaults = make(map[string]*corev1beta1.ContainerDefaults) + } + instance.Status.ContainerImageVersionDefaults[envAvailableVersion] = defaults + + // calculate the container images for the target version + val, ok := instance.Status.ContainerImageVersionDefaults[instance.Spec.TargetVersion] + if !ok { + Log.Info("Target version not found in defaults", "targetVersion", instance.Spec.TargetVersion) + return ctrl.Result{}, nil + } + instance.Status.ContainerImages = openstack.GetContainerImages(ctx, val, *instance) + + instance.Status.Conditions.MarkTrue( + corev1beta1.OpenStackVersionInitialized, + corev1beta1.OpenStackVersionInitializedReadyMessage) + Log.Info("OpenStackVersion Initialized") + + // lookup the current Controlplane object + controlPlane := &corev1beta1.OpenStackControlPlane{} + err = r.Client.Get(ctx, client.ObjectKey{ + Namespace: instance.Namespace, + Name: instance.Name, + }, controlPlane) + if err != nil { + // we ignore not found + if k8s_errors.IsNotFound(err) { + Log.Info("No controlplane found.") + return ctrl.Result{}, nil + } else { + return ctrl.Result{}, err + } + } + + // greenfield deployment //FIXME check dataplane here too + if controlPlane.Status.DeployedVersion == nil { + Log.Info("No controlplane or controlplane is not deployed") + return ctrl.Result{}, nil + } + + // TODO minor update for OVN Dataplane in progress + + // minor update for OVN Controlplane in progress + if instance.Status.DeployedVersion != nil && instance.Spec.TargetVersion != *instance.Status.DeployedVersion { + if !compareStringPointers(controlPlane.Status.ContainerImages.OvnControllerImage, instance.Status.ContainerImages.OvnControllerImage) || + !controlPlane.Status.Conditions.IsTrue(corev1beta1.OpenStackControlPlaneOVNReadyCondition) { + instance.Status.Conditions.Set(condition.FalseCondition( + corev1beta1.OpenStackVersionMinorUpdateOVNControlplane, + condition.RequestedReason, + condition.SeverityInfo, + corev1beta1.OpenStackVersionMinorUpdateReadyRunningMessage)) + Log.Info("Minor update for OVN Controlplane in progress") + return ctrl.Result{}, nil + } + instance.Status.Conditions.MarkTrue( + corev1beta1.OpenStackVersionMinorUpdateOVNControlplane, + corev1beta1.OpenStackVersionMinorUpdateReadyMessage) + + // minor update for Controlplane in progress + // we only check keystone here as it will only get updated during this phase + // FIXME: add checks to all images on the Controlplane here once conditions and observedGeneration work are finished + if !compareStringPointers(controlPlane.Status.ContainerImages.KeystoneAPIImage, instance.Status.ContainerImages.KeystoneAPIImage) || + !controlPlane.IsReady() { + instance.Status.Conditions.Set(condition.FalseCondition( + corev1beta1.OpenStackVersionMinorUpdateControlplane, + condition.RequestedReason, + condition.SeverityInfo, + corev1beta1.OpenStackVersionMinorUpdateReadyRunningMessage)) + Log.Info("Minor update for Controlplane in progress") + return ctrl.Result{}, nil + } + // TODO minor update for Dataplane in progress goes here + + instance.Status.Conditions.MarkTrue( + corev1beta1.OpenStackVersionMinorUpdateControlplane, + corev1beta1.OpenStackVersionMinorUpdateReadyMessage) + } + + if controlPlane.IsReady() { + Log.Info("Setting DeployedVersion") + instance.Status.DeployedVersion = &instance.Spec.TargetVersion + } return ctrl.Result{}, nil } // SetupWithManager sets up the controller with the Manager. func (r *OpenStackVersionReconciler) SetupWithManager(mgr ctrl.Manager) error { + + versionFunc := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) []reconcile.Request { + Log := r.GetLogger(ctx) + versionList := &corev1beta1.OpenStackVersionList{} + + result := []reconcile.Request{} + + listOpts := []client.ListOption{ + client.InNamespace(o.GetNamespace()), + } + if err := r.Client.List(ctx, versionList, listOpts...); err != nil { + Log.Error(err, "Unable to retrieve OpenStackVersion") + return nil + } + + for _, i := range versionList.Items { + name := client.ObjectKey{ + Namespace: o.GetNamespace(), + Name: i.Name, + } + result = append(result, reconcile.Request{NamespacedName: name}) + } + if len(result) > 0 { + Log.Info("Reconcile request for:", "result", result) + return result + } + return nil + }) + return ctrl.NewControllerManagedBy(mgr). + Watches(&corev1beta1.OpenStackControlPlane{}, versionFunc). For(&corev1beta1.OpenStackVersion{}). Complete(r) } diff --git a/go.mod b/go.mod index 10017a0dc..112fe754e 100644 --- a/go.mod +++ b/go.mod @@ -125,3 +125,6 @@ replace github.com/openstack-k8s-operators/openstack-operator/apis => ./apis // mschuppert: map to latest commit from release-4.13 tag // must consistent within modules and service operators replace github.com/openshift/api => github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7 //allow-merging + +// custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.6.0_patches_tag) +replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20240313124519-961a0ee8bf7f //allow-merging diff --git a/go.sum b/go.sum index a332c8fe7..0045994b6 100644 --- a/go.sum +++ b/go.sum @@ -144,6 +144,8 @@ github.com/openstack-k8s-operators/ovn-operator/api v0.3.1-0.20240403151939-f1ae github.com/openstack-k8s-operators/ovn-operator/api v0.3.1-0.20240403151939-f1aeebd1f2e0/go.mod h1:gouaaSPxUBLC1ifDBAdFsbl1njab50Uc2cBE8M6oKGc= github.com/openstack-k8s-operators/placement-operator/api v0.3.1-0.20240404140050-69252e99daaf h1:O7RzcKH3qRORucojkKZc1vIpQv5naYoWn34zhVzTs0E= github.com/openstack-k8s-operators/placement-operator/api v0.3.1-0.20240404140050-69252e99daaf/go.mod h1:NYOgk2HS4mSR+4WwsiexepNU1pjxeo7h2WTs8qtS9/0= +github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20240313124519-961a0ee8bf7f h1:wWaOCAkCym4t+NZWXYT/LErGhKujDdKgc7Qy/3vX4uU= +github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20240313124519-961a0ee8bf7f/go.mod h1:Zryxg5YgbPUFcLSCcKpf10il8kIRAK5HloNo6khhdis= github.com/openstack-k8s-operators/swift-operator/api v0.3.1-0.20240405150212-f8cecba5f227 h1:aX8lFcr9d7SzsP9MUvHzrki1jUPqYbAFlfdlu4OWxl0= github.com/openstack-k8s-operators/swift-operator/api v0.3.1-0.20240405150212-f8cecba5f227/go.mod h1:kl+TdEExQwr7OCZaOilotlGlz9rzGxC75rUBL0P35f8= github.com/openstack-k8s-operators/telemetry-operator/api v0.3.1-0.20240404090348-ab779da79e83 h1:/YiMXzTLTehsSlDHliiJiDr3n/j1krxRHlP0A2ca41k= @@ -162,8 +164,6 @@ github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqSc github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rabbitmq/cluster-operator/v2 v2.6.0 h1:pr42elurQgi4DVmLTI1cOh8VZRNkfFKZK9+FgQuM/8w= -github.com/rabbitmq/cluster-operator/v2 v2.6.0/go.mod h1:Zryxg5YgbPUFcLSCcKpf10il8kIRAK5HloNo6khhdis= github.com/rhobs/obo-prometheus-operator/pkg/apis/monitoring v0.69.0-rhobs1 h1:d6UamuHl8GaEXcQqM7VO8jMnnhzHmTA0f6h4dQTQsGk= github.com/rhobs/obo-prometheus-operator/pkg/apis/monitoring v0.69.0-rhobs1/go.mod h1:SDL0R6499oleOOVL5ovIxHpyLOh2sR2g0rvBuuqHyQM= github.com/rhobs/observability-operator v0.0.28 h1:FFMBkmI1LWJVWyJKJqelYbV5iUc4u/wJClqowRJZRoU= diff --git a/hack/export_related_images.sh b/hack/export_related_images.sh new file mode 100755 index 000000000..ad3774970 --- /dev/null +++ b/hack/export_related_images.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +export OPENSTACK_RELEASE_VERSION=0.0.1 +export RELATED_IMAGE_OPENSTACK_CLIENT_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-openstackclient:current-podified +export RELATED_IMAGE_RABBITMQ_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-rabbitmq:current-podified +export RELATED_IMAGE_KEYSTONE_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-keystone:current-podified +export RELATED_IMAGE_MARIADB_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-mariadb:current-podified +export RELATED_IMAGE_INFRA_MEMCACHED_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-memcached:current-podified +export RELATED_IMAGE_INFRA_REDIS_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-redis:current-podified +export RELATED_IMAGE_INFRA_DNSMASQ_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-neutron-server:current-podified +export RELATED_IMAGE_ANSIBLEEE_IMAGE_URL_DEFAULT=quay.io/openstack-k8s-operators/openstack-ansibleee-runner:current-podified +export RELATED_IMAGE_NOVA_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-nova-api:current-podified +export RELATED_IMAGE_NOVA_CONDUCTOR_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-nova-conductor:current-podified +export RELATED_IMAGE_NOVA_NOVNC_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-nova-novncproxy:current-podified +export RELATED_IMAGE_NOVA_SCHEDULER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-nova-scheduler:current-podified +export RELATED_IMAGE_NOVA_COMPUTE_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-nova-compute:current-podified +export RELATED_IMAGE_NEUTRON_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-neutron-server:current-podified +export RELATED_IMAGE_MANILA_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-manila-api:current-podified +export RELATED_IMAGE_MANILA_SCHEDULER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-manila-scheduler:current-podified +export RELATED_IMAGE_MANILA_SHARE_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-manila-share:current-podified +export RELATED_IMAGE_GLANCE_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-glance-api:current-podified +export RELATED_IMAGE_IRONIC_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ironic-api:current-podified +export RELATED_IMAGE_IRONIC_CONDUCTOR_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ironic-conductor:current-podified +export RELATED_IMAGE_IRONIC_INSPECTOR_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ironic-inspector:current-podified +export RELATED_IMAGE_IRONIC_PXE_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ironic-pxe:current-podified +export RELATED_IMAGE_IRONIC_NEUTRON_AGENT_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ironic-neutron-agent:current-podified +export RELATED_IMAGE_IRONIC_PYTHON_AGENT_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/ironic-python-agent:current-podified +export RELATED_IMAGE_OS_CONTAINER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/edpm-hardened-uefi:current-podified +export RELATED_IMAGE_AGENT_IMAGE_URL_DEFAULT=quay.io/openstack-k8s-operators/openstack-baremetal-operator-agent:current-podified +export RELATED_IMAGE_APACHE_IMAGE_URL_DEFAULT=registry.redhat.io/rhel8/httpd-24:current-podified +export OS_IMAGE_DEFAULT=edpm-hardened-uefi.qcow2 +export RELATED_IMAGE_PLACEMENT_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-placement-api:current-podified +export RELATED_IMAGE_CEILOMETER_CENTRAL_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ceilometer-central:current-podified +export RELATED_IMAGE_CEILOMETER_COMPUTE_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ceilometer-compute:current-podified +export RELATED_IMAGE_CEILOMETER_NOTIFICATION_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ceilometer-notification:current-podified +export RELATED_IMAGE_CEILOMETER_IPMI_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ceilometer-ipmi:current-podified +export RELATED_IMAGE_CEILOMETER_SGCORE_IMAGE_URL_DEFAULT=quay.io/infrawatch/sg-core:current-podified +export RELATED_IMAGE_AODH_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-aodh-api:current-podified +export RELATED_IMAGE_AODH_EVALUATOR_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-aodh-evaluator:current-podified +export RELATED_IMAGE_AODH_NOTIFIER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-aodh-notifier:current-podified +export RELATED_IMAGE_AODH_LISTENER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-aodh-listener:current-podified +export RELATED_IMAGE_OVN_NB_DBCLUSTER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ovn-nb-db-server:current-podified +export RELATED_IMAGE_OVN_SB_DBCLUSTER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ovn-sb-db-server:current-podified +export RELATED_IMAGE_OVN_NORTHD_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ovn-northd:current-podified +export RELATED_IMAGE_OVN_CONTROLLER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ovn-controller:current-podified +export RELATED_IMAGE_OVN_CONTROLLER_OVS_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-ovn-base:current-podified +export RELATED_IMAGE_CINDER_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-cinder-api:current-podified +export RELATED_IMAGE_CINDER_BACKUP_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-cinder-backup:current-podified +export RELATED_IMAGE_CINDER_SCHEDULER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-cinder-scheduler:current-podified +export RELATED_IMAGE_CINDER_VOLUME_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-cinder-volume:current-podified +export RELATED_IMAGE_HORIZON_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-horizon:current-podified +export RELATED_IMAGE_HEAT_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-heat-api:current-podified +export RELATED_IMAGE_HEAT_CFNAPI_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-heat-api-cfn:current-podified +export RELATED_IMAGE_HEAT_ENGINE_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-heat-engine:current-podified +export RELATED_IMAGE_SWIFT_PROXY_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-swift-proxy-server:current-podified +export RELATED_IMAGE_SWIFT_ACCOUNT_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-swift-account:current-podified +export RELATED_IMAGE_SWIFT_CONTAINER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-swift-container:current-podified +export RELATED_IMAGE_SWIFT_OBJECT_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-swift-object:current-podified +export RELATED_IMAGE_OCTAVIA_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-octavia-api:current-podified +export RELATED_IMAGE_OCTAVIA_HOUSEKEEPING_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-octavia-housekeeping:current-podified +export RELATED_IMAGE_OCTAVIA_HEALTHMANAGER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-octavia-health-manager:current-podified +export RELATED_IMAGE_OCTAVIA_WORKER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-octavia-worker:current-podified +export RELATED_IMAGE_DESIGNATE_API_IMAGE_URL_DEFAULT=quay.io/tripleowallabycentos9/openstack-designate-api:current-podified +export RELATED_IMAGE_DESIGNATE_CENTRAL_IMAGE_URL_DEFAULT=quay.io/tripleowallabycentos9/openstack-designate-central:current-podified +export RELATED_IMAGE_DESIGNATE_MDNS_IMAGE_URL_DEFAULT=quay.io/tripleowallabycentos9/openstack-designate-mdns:current-podified +export RELATED_IMAGE_DESIGNATE_PRODUCER_IMAGE_URL_DEFAULT=quay.io/tripleowallabycentos9/openstack-designate-producer:current-podified +export RELATED_IMAGE_DESIGNATE_WORKER_IMAGE_URL_DEFAULT=quay.io/tripleowallabycentos9/openstack-designate-worker:current-podified +export RELATED_IMAGE_DESIGNATE_BACKENDBIND9_IMAGE_URL_DEFAULT=quay.io/tripleowallabycentos9/openstack-designate-backend-bind9:current-podified +export RELATED_IMAGE_DESIGNATE_UNBOUND_IMAGE_URL_DEFAULT=quay.io/tripleowallabycentos9/openstack-unbound:current-podified +export RELATED_IMAGE_BARBICAN_API_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-barbican-api:current-podified +export RELATED_IMAGE_BARBICAN_WORKER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-barbican-worker:current-podified +export RELATED_IMAGE_BARBICAN_KEYSTONE_LISTENER_IMAGE_URL_DEFAULT=quay.io/podified-antelope-centos9/openstack-barbican-keystone-listener:current-podified +export RELATED_IMAGE_OPENSTACK_EDPM_FRR_DEFAULT_IMG=quay.io/podified-antelope-centos9/openstack-frr:current-podified +export RELATED_IMAGE_OPENSTACK_EDPM_ISCSID_DEFAULT_IMG=quay.io/podified-antelope-centos9/openstack-iscsid:current-podified +export RELATED_IMAGE_OPENSTACK_EDPM_LOGROTATE_CROND_DEFAULT_IMG=quay.io/podified-antelope-centos9/openstack-cron:current-podified +export RELATED_IMAGE_OPENSTACK_EDPM_NEUTRON_METADATA_AGENT_DEFAULT_IMG=quay.io/podified-antelope-centos9/openstack-neutron-metadata-agent-ovn:current-podified +export RELATED_IMAGE_OPENSTACK_EDPM_NEUTRON_SRIOV_AGENT_DEFAULT_IMG=quay.io/podified-antelope-centos9/openstack-neutron-sriov-agent:current-podified +export RELATED_IMAGE_OPENSTACK_EDPM_OVN_BGP_AGENT_IMAGE=quay.io/podified-antelope-centos9/openstack-ovn-bgp-agent:current-podified +export RELATED_IMAGE_OPENSTACK_EDPM_CEILOMETER_COMPUTE_IMAGE=quay.io/podified-antelope-centos9/openstack-ceilometer-compute:current-podified +export RELATED_IMAGE_OPENSTACK_EDPM_CEILOMETER_IPMI_IMAGE=quay.io/podified-antelope-centos9/openstack-ceilometer-ipmi:current-podified +#NOTE: RELATED_IMAGE_OPENSTACK_EDPM_NODE_EXPORTER_IMAGE is the same as below +export RELATED_IMAGE_TELEMETRY_NODE_EXPORTER_IMAGE_URL_DEFAULT=quay.io/prometheus/node-exporter:v1.5.0 diff --git a/hack/fake_minor_update.sh b/hack/fake_minor_update.sh new file mode 100644 index 000000000..d3d4a65d8 --- /dev/null +++ b/hack/fake_minor_update.sh @@ -0,0 +1,9 @@ +# A quick way to test a fake minor update. Run this script, and then once the +# openstackversion reconciles (the CSV will redeploy the controller-manager) +# you can set targetVersion == 0.0.2 for a quick test +oc get csv openstack-operator.v0.0.1 -o yaml -n openstack-operators > csv.yaml +# bump them to current-podified +sed -i csv.yaml -e "s|value: .*quay.io/podified-antelope-centos9/\(.*\)@.*|value: quay.io/podified-antelope-centos9/\1:current-podified|g" +# also bump the OPENSTACK_RELEASE_VERSION value (it is the only field set like this) +sed -i csv.yaml -e "s|value: 0.0.1|value: 0.0.2|" +oc apply -n openstack-operators -f csv.yaml diff --git a/main.go b/main.go index 566d19822..a84a78e9b 100644 --- a/main.go +++ b/main.go @@ -72,7 +72,7 @@ import ( clientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" corev1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" - corev1beta1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" + clientcontrollers "github.com/openstack-k8s-operators/openstack-operator/controllers/client" corecontrollers "github.com/openstack-k8s-operators/openstack-operator/controllers/core" "github.com/openstack-k8s-operators/openstack-operator/pkg/openstack" @@ -115,7 +115,6 @@ func init() { utilruntime.Must(routev1.AddToScheme(scheme)) utilruntime.Must(certmgrv1.AddToScheme(scheme)) utilruntime.Must(barbicanv1.AddToScheme(scheme)) - utilruntime.Must(corev1beta1.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } @@ -209,6 +208,16 @@ func main() { os.Exit(1) } + if err = (&corecontrollers.OpenStackVersionReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Kclient: kclient, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "OpenStackVersion") + os.Exit(1) + } + corecontrollers.SetupVersionDefaults() + // Defaults for service operators openstack.SetupServiceOperatorDefaults() @@ -217,6 +226,7 @@ func main() { // Defaults for anything else that was not covered by OpenStackClient nor service operator defaults corev1.SetupDefaults() + corev1.SetupVersionDefaults() // Webhooks checker := healthz.Ping @@ -230,18 +240,14 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "OpenStackClient") os.Exit(1) } + if err = (&corev1.OpenStackVersion{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "OpenStackVersion") + os.Exit(1) + } checker = mgr.GetWebhookServer().StartedChecker() } - if err = (&corecontrollers.OpenStackVersionReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "OpenStackVersion") - os.Exit(1) - } //+kubebuilder:scaffold:builder - if err := mgr.AddHealthzCheck("healthz", checker); err != nil { setupLog.Error(err, "unable to set up health check") os.Exit(1) diff --git a/pkg/openstack/barbican.go b/pkg/openstack/barbican.go index a41062dac..b1fc1a204 100644 --- a/pkg/openstack/barbican.go +++ b/pkg/openstack/barbican.go @@ -19,7 +19,7 @@ import ( ) // ReconcileBarbican - -func ReconcileBarbican(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileBarbican(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { barbican := &barbicanv1.Barbican{ ObjectMeta: metav1.ObjectMeta{ Name: "barbican", @@ -97,7 +97,14 @@ func ReconcileBarbican(ctx context.Context, instance *corev1beta1.OpenStackContr helper.GetLogger().Info("Reconciling Barbican", "Barbican.Namespace", instance.Namespace, "Barbican.Name", "barbican") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), barbican, func() error { - instance.Spec.Barbican.Template.DeepCopyInto(&barbican.Spec) + instance.Spec.Barbican.Template.BarbicanSpecBase.DeepCopyInto(&barbican.Spec.BarbicanSpecBase) + instance.Spec.Barbican.Template.BarbicanAPI.DeepCopyInto(&barbican.Spec.BarbicanAPI.BarbicanAPITemplateCore) + instance.Spec.Barbican.Template.BarbicanWorker.DeepCopyInto(&barbican.Spec.BarbicanWorker.BarbicanWorkerTemplateCore) + instance.Spec.Barbican.Template.BarbicanKeystoneListener.DeepCopyInto(&barbican.Spec.BarbicanKeystoneListener.BarbicanKeystoneListenerTemplateCore) + + barbican.Spec.BarbicanAPI.ContainerImage = *version.Status.ContainerImages.BarbicanAPIImage + barbican.Spec.BarbicanWorker.ContainerImage = *version.Status.ContainerImages.BarbicanWorkerImage + barbican.Spec.BarbicanKeystoneListener.ContainerImage = *version.Status.ContainerImages.BarbicanKeystoneListenerImage // FIXME: barbican webhooks are not setting this correctly yet if barbican.Spec.DatabaseAccount == "" { @@ -142,6 +149,9 @@ func ReconcileBarbican(ctx context.Context, instance *corev1beta1.OpenStackContr condition.SeverityInfo, corev1beta1.OpenStackControlPlaneBarbicanReadyRunningMessage)) } + instance.Status.ContainerImages.BarbicanAPIImage = version.Status.ContainerImages.BarbicanAPIImage + instance.Status.ContainerImages.BarbicanWorkerImage = version.Status.ContainerImages.BarbicanWorkerImage + instance.Status.ContainerImages.BarbicanKeystoneListenerImage = version.Status.ContainerImages.BarbicanKeystoneListenerImage return ctrl.Result{}, nil } diff --git a/pkg/openstack/cinder.go b/pkg/openstack/cinder.go index 077a02fcb..9b3ea2142 100644 --- a/pkg/openstack/cinder.go +++ b/pkg/openstack/cinder.go @@ -2,6 +2,7 @@ package openstack import ( "context" + "errors" "fmt" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" @@ -19,7 +20,7 @@ import ( ) // ReconcileCinder - -func ReconcileCinder(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileCinder(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { cinder := &cinderv1.Cinder{ ObjectMeta: metav1.ObjectMeta{ Name: "cinder", @@ -99,7 +100,34 @@ func ReconcileCinder(ctx context.Context, instance *corev1beta1.OpenStackControl Log.Info("Reconciling Cinder", "Cinder.Namespace", instance.Namespace, "Cinder.Name", "cinder") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), cinder, func() error { - instance.Spec.Cinder.Template.DeepCopyInto(&cinder.Spec) + instance.Spec.Cinder.Template.CinderSpecBase.DeepCopyInto(&cinder.Spec.CinderSpecBase) + instance.Spec.Cinder.Template.CinderAPI.DeepCopyInto(&cinder.Spec.CinderAPI.CinderAPITemplateCore) + instance.Spec.Cinder.Template.CinderScheduler.DeepCopyInto(&cinder.Spec.CinderScheduler.CinderSchedulerTemplateCore) + instance.Spec.Cinder.Template.CinderBackup.DeepCopyInto(&cinder.Spec.CinderBackup.CinderBackupTemplateCore) + + cinder.Spec.CinderAPI.ContainerImage = *version.Status.ContainerImages.CinderAPIImage + cinder.Spec.CinderScheduler.ContainerImage = *version.Status.ContainerImages.CinderSchedulerImage + cinder.Spec.CinderBackup.ContainerImage = *version.Status.ContainerImages.CinderBackupImage + + defaultVolumeImg := version.Status.ContainerImages.CinderVolumeImages["default"] + if defaultVolumeImg == nil { + return errors.New("default Cinder Volume images is unset") + } + + if cinder.Spec.CinderVolumes == nil { + cinder.Spec.CinderVolumes = make(map[string]cinderv1.CinderVolumeTemplate) + } + + for name, volume := range instance.Spec.Cinder.Template.CinderVolumes { + cinderCore := cinderv1.CinderVolumeTemplate{} + volume.DeepCopyInto(&cinderCore.CinderVolumeTemplateCore) + if volVal, ok := version.Status.ContainerImages.CinderVolumeImages[name]; ok { + cinderCore.ContainerImage = *volVal + } else { + cinderCore.ContainerImage = *defaultVolumeImg + } + cinder.Spec.CinderVolumes[name] = cinderCore + } if cinder.Spec.Secret == "" { cinder.Spec.Secret = instance.Spec.Secret @@ -125,7 +153,6 @@ func ReconcileCinder(ctx context.Context, instance *corev1beta1.OpenStackControl } return nil }) - if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( corev1beta1.OpenStackControlPlaneCinderReadyCondition, @@ -139,7 +166,11 @@ func ReconcileCinder(ctx context.Context, instance *corev1beta1.OpenStackControl Log.Info(fmt.Sprintf("Cinder %s - %s", cinder.Name, op)) } - if cinder.IsReady() { + if cinder.Status.ObservedGeneration == cinder.Generation && cinder.IsReady() { + instance.Status.ContainerImages.CinderAPIImage = version.Status.ContainerImages.CinderAPIImage + instance.Status.ContainerImages.CinderSchedulerImage = version.Status.ContainerImages.CinderSchedulerImage + instance.Status.ContainerImages.CinderBackupImage = version.Status.ContainerImages.CinderBackupImage + instance.Status.ContainerImages.CinderVolumeImages = version.Status.ContainerImages.DeepCopy().CinderVolumeImages instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneCinderReadyCondition, corev1beta1.OpenStackControlPlaneCinderReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/designate.go b/pkg/openstack/designate.go index 37b29fa12..13d4cecf2 100644 --- a/pkg/openstack/designate.go +++ b/pkg/openstack/designate.go @@ -20,7 +20,7 @@ import ( ) // ReconcileDesignate - -func ReconcileDesignate(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileDesignate(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { designate := &designatev1.Designate{ ObjectMeta: metav1.ObjectMeta{ Name: "designate", @@ -90,7 +90,34 @@ func ReconcileDesignate(ctx context.Context, instance *corev1beta1.OpenStackCont helper.GetLogger().Info("Reconciling Designate", "Designate.Namespace", instance.Namespace, "Designate.Name", "designate") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), designate, func() error { - instance.Spec.Designate.Template.DeepCopyInto(&designate.Spec) + // FIXME: the designate structs need some rework (images should be at the top level, not in the sub structs) + instance.Spec.Designate.Template.DesignateSpecBase.DeepCopyInto(&designate.Spec.DesignateSpecBase) + // API + instance.Spec.Designate.Template.DesignateAPI.DesignateAPISpecBase.DeepCopyInto(&designate.Spec.DesignateAPI.DesignateAPISpecBase) + instance.Spec.Designate.Template.DesignateAPI.DesignateServiceTemplateCore.DeepCopyInto(&designate.Spec.DesignateAPI.DesignateServiceTemplateCore) + // Central + instance.Spec.Designate.Template.DesignateCentral.DesignateCentralSpecBase.DeepCopyInto(&designate.Spec.DesignateCentral.DesignateCentralSpecBase) + instance.Spec.Designate.Template.DesignateCentral.DesignateServiceTemplateCore.DeepCopyInto(&designate.Spec.DesignateCentral.DesignateServiceTemplateCore) + // Worker + instance.Spec.Designate.Template.DesignateWorker.DesignateWorkerSpecBase.DeepCopyInto(&designate.Spec.DesignateWorker.DesignateWorkerSpecBase) + instance.Spec.Designate.Template.DesignateWorker.DesignateServiceTemplateCore.DeepCopyInto(&designate.Spec.DesignateWorker.DesignateServiceTemplateCore) + // Mdns + instance.Spec.Designate.Template.DesignateMdns.DesignateMdnsSpecBase.DeepCopyInto(&designate.Spec.DesignateMdns.DesignateMdnsSpecBase) + instance.Spec.Designate.Template.DesignateMdns.DesignateServiceTemplateCore.DeepCopyInto(&designate.Spec.DesignateMdns.DesignateServiceTemplateCore) + // Producer + instance.Spec.Designate.Template.DesignateProducer.DesignateProducerSpecBase.DeepCopyInto(&designate.Spec.DesignateProducer.DesignateProducerSpecBase) + instance.Spec.Designate.Template.DesignateProducer.DesignateServiceTemplateCore.DeepCopyInto(&designate.Spec.DesignateProducer.DesignateServiceTemplateCore) + // Bind9 + instance.Spec.Designate.Template.DesignateBackendbind9.DesignateBackendbind9SpecBase.DeepCopyInto(&designate.Spec.DesignateBackendbind9.DesignateBackendbind9SpecBase) + instance.Spec.Designate.Template.DesignateBackendbind9.DesignateServiceTemplateCore.DeepCopyInto(&designate.Spec.DesignateBackendbind9.DesignateServiceTemplateCore) + + designate.Spec.DesignateAPI.ContainerImage = *version.Status.ContainerImages.DesignateAPIImage + designate.Spec.DesignateCentral.ContainerImage = *version.Status.ContainerImages.DesignateCentralImage + designate.Spec.DesignateMdns.ContainerImage = *version.Status.ContainerImages.DesignateMdnsImage + designate.Spec.DesignateProducer.ContainerImage = *version.Status.ContainerImages.DesignateProducerImage + designate.Spec.DesignateWorker.ContainerImage = *version.Status.ContainerImages.DesignateWorkerImage + designate.Spec.DesignateBackendbind9.ContainerImage = *version.Status.ContainerImages.DesignateBackendbind9Image + designate.Spec.DesignateUnbound.ContainerImage = *version.Status.ContainerImages.DesignateUnboundImage if designate.Spec.Secret == "" { designate.Spec.Secret = instance.Spec.Secret @@ -122,7 +149,14 @@ func ReconcileDesignate(ctx context.Context, instance *corev1beta1.OpenStackCont helper.GetLogger().Info(fmt.Sprintf("Designate %s - %s", designate.Name, op)) } - if designate.IsReady() { + if designate.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.DesignateAPIImage = version.Status.ContainerImages.DesignateAPIImage + instance.Status.ContainerImages.DesignateCentralImage = version.Status.ContainerImages.DesignateCentralImage + instance.Status.ContainerImages.DesignateMdnsImage = version.Status.ContainerImages.DesignateMdnsImage + instance.Status.ContainerImages.DesignateProducerImage = version.Status.ContainerImages.DesignateProducerImage + instance.Status.ContainerImages.DesignateWorkerImage = version.Status.ContainerImages.DesignateWorkerImage + instance.Status.ContainerImages.DesignateBackendbind9Image = version.Status.ContainerImages.DesignateBackendbind9Image + instance.Status.ContainerImages.DesignateUnboundImage = version.Status.ContainerImages.DesignateUnboundImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneDesignateReadyCondition, corev1beta1.OpenStackControlPlaneDesignateReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/dnsmasq.go b/pkg/openstack/dnsmasq.go index 530bab62e..36c7d5d75 100644 --- a/pkg/openstack/dnsmasq.go +++ b/pkg/openstack/dnsmasq.go @@ -17,7 +17,7 @@ import ( ) // ReconcileDNSMasqs - -func ReconcileDNSMasqs(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileDNSMasqs(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { dnsmasq := &networkv1.DNSMasq{ ObjectMeta: metav1.ObjectMeta{ Name: "dns", @@ -38,6 +38,7 @@ func ReconcileDNSMasqs(ctx context.Context, instance *corev1beta1.OpenStackContr Log.Info("Reconciling DNSMasq", "DNSMasq.Namespace", instance.Namespace, "DNSMasq.Name", "dnsmasq") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), dnsmasq, func() error { instance.Spec.DNS.Template.DeepCopyInto(&dnsmasq.Spec) + dnsmasq.Spec.ContainerImage = *version.Status.ContainerImages.InfraDnsmasqImage if dnsmasq.Spec.NodeSelector == nil && instance.Spec.NodeSelector != nil { dnsmasq.Spec.NodeSelector = instance.Spec.NodeSelector } @@ -61,7 +62,8 @@ func ReconcileDNSMasqs(ctx context.Context, instance *corev1beta1.OpenStackContr Log.Info(fmt.Sprintf("dnsmasq %s - %s", dnsmasq.Name, op)) } - if dnsmasq.IsReady() { + if dnsmasq.IsReady() { // FIXME ObservedGeneration + instance.Status.ContainerImages.InfraDnsmasqImage = version.Status.ContainerImages.InfraDnsmasqImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneDNSReadyCondition, corev1beta1.OpenStackControlPlaneDNSReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/galera.go b/pkg/openstack/galera.go index ec6303c05..96efe924c 100644 --- a/pkg/openstack/galera.go +++ b/pkg/openstack/galera.go @@ -31,6 +31,7 @@ const ( func ReconcileGaleras( ctx context.Context, instance *corev1beta1.OpenStackControlPlane, + version *corev1beta1.OpenStackVersion, helper *helper.Helper, ) (ctrl.Result, error) { if !instance.Spec.Galera.Enabled { @@ -76,7 +77,7 @@ func ReconcileGaleras( spec.TLS.Ca.CaBundleSecretName = instance.Status.TLS.CaBundleSecretName spec.TLS.SecretName = ptr.To(certSecret.Name) - status, err := reconcileGalera(ctx, instance, helper, name, &spec) + status, err := reconcileGalera(ctx, instance, version, helper, name, &spec) switch status { case galeraFailed: @@ -85,7 +86,7 @@ func ReconcileGaleras( inprogress = append(inprogress, name) case galeraReady: default: - return ctrl.Result{}, fmt.Errorf("Invalid galeraStatus from reconcileGalera: %d for Galera %s", status, name) + return ctrl.Result{}, fmt.Errorf("invalid galeraStatus from reconcileGalera: %d for Galera %s", status, name) } } @@ -121,9 +122,10 @@ func ReconcileGaleras( func reconcileGalera( ctx context.Context, instance *corev1beta1.OpenStackControlPlane, + version *corev1beta1.OpenStackVersion, helper *helper.Helper, name string, - spec *mariadbv1.GaleraSpec, + spec *mariadbv1.GaleraSpecCore, ) (galeraStatus, error) { galera := &mariadbv1.Galera{ ObjectMeta: metav1.ObjectMeta{ @@ -143,8 +145,8 @@ func reconcileGalera( Log.Info("Reconciling Galera", "Galera.Namespace", instance.Namespace, "Galera.Name", name) op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), galera, func() error { - spec.DeepCopyInto(&galera.Spec) - + spec.DeepCopyInto(&galera.Spec.GaleraSpecCore) + galera.Spec.ContainerImage = *version.Status.ContainerImages.MariadbImage err := controllerutil.SetControllerReference(helper.GetBeforeObject(), galera, helper.GetScheme()) if err != nil { return err @@ -160,7 +162,8 @@ func reconcileGalera( Log.Info(fmt.Sprintf("Galera %s - %s", galera.Name, op)) } - if galera.IsReady() { + if galera.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.MariadbImage = version.Status.ContainerImages.MariadbImage return galeraReady, nil } diff --git a/pkg/openstack/glance.go b/pkg/openstack/glance.go index 6568ca5f3..16c76216c 100644 --- a/pkg/openstack/glance.go +++ b/pkg/openstack/glance.go @@ -27,7 +27,7 @@ const ( ) // ReconcileGlance - -func ReconcileGlance(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileGlance(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { glance := &glancev1.Glance{ ObjectMeta: metav1.ObjectMeta{ Name: "glance", @@ -140,7 +140,8 @@ func ReconcileGlance(ctx context.Context, instance *corev1beta1.OpenStackControl Log.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) + instance.Spec.Glance.Template.DeepCopyInto(&glance.Spec.GlanceSpecCore) + glance.Spec.ContainerImage = *version.Status.ContainerImages.GlanceAPIImage if glance.Spec.Secret == "" { glance.Spec.Secret = instance.Spec.Secret } @@ -179,7 +180,8 @@ func ReconcileGlance(ctx context.Context, instance *corev1beta1.OpenStackControl Log.Info(fmt.Sprintf("glance %s - %s", glance.Name, op)) } - if glance.IsReady() { + if glance.Status.ObservedGeneration == glance.Generation && glance.IsReady() { + instance.Status.ContainerImages.GlanceAPIImage = version.Status.ContainerImages.GlanceAPIImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneGlanceReadyCondition, corev1beta1.OpenStackControlPlaneGlanceReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/heat.go b/pkg/openstack/heat.go index e615a9cb4..c202141bd 100644 --- a/pkg/openstack/heat.go +++ b/pkg/openstack/heat.go @@ -23,7 +23,7 @@ const ( ) // ReconcileHeat - -func ReconcileHeat(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileHeat(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { heat := &heatv1.Heat{ ObjectMeta: metav1.ObjectMeta{ Name: heatName, @@ -149,7 +149,14 @@ func ReconcileHeat(ctx context.Context, instance *corev1beta1.OpenStackControlPl Log.Info("Reconcile heat", "heat.Namespace", instance.Namespace, "heat.Name", "heat") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), heat, func() error { - instance.Spec.Heat.Template.DeepCopyInto(&heat.Spec) + instance.Spec.Heat.Template.HeatSpecBase.DeepCopyInto(&heat.Spec.HeatSpecBase) + instance.Spec.Heat.Template.HeatAPI.DeepCopyInto(&heat.Spec.HeatAPI.HeatAPITemplateCore) + instance.Spec.Heat.Template.HeatCfnAPI.DeepCopyInto(&heat.Spec.HeatCfnAPI.HeatCfnAPITemplateCore) + instance.Spec.Heat.Template.HeatEngine.DeepCopyInto(&heat.Spec.HeatEngine.HeatEngineTemplateCore) + + heat.Spec.HeatAPI.ContainerImage = *version.Status.ContainerImages.HeatAPIImage + heat.Spec.HeatCfnAPI.ContainerImage = *version.Status.ContainerImages.HeatCfnapiImage + heat.Spec.HeatEngine.ContainerImage = *version.Status.ContainerImages.HeatEngineImage err := controllerutil.SetControllerReference(helper.GetBeforeObject(), heat, helper.GetScheme()) if err != nil { @@ -171,7 +178,10 @@ func ReconcileHeat(ctx context.Context, instance *corev1beta1.OpenStackControlPl Log.Info(fmt.Sprintf("heat %s - %s", heat.Name, op)) } - if heat.IsReady() { + if heat.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.HeatAPIImage = version.Status.ContainerImages.HeatAPIImage + instance.Status.ContainerImages.HeatCfnapiImage = version.Status.ContainerImages.HeatCfnapiImage + instance.Status.ContainerImages.HeatEngineImage = version.Status.ContainerImages.HeatEngineImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneHeatReadyCondition, corev1beta1.OpenStackControlPlaneHeatReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/horizon.go b/pkg/openstack/horizon.go index 6327dede5..b70c01ed1 100644 --- a/pkg/openstack/horizon.go +++ b/pkg/openstack/horizon.go @@ -21,7 +21,7 @@ import ( ) // ReconcileHorizon - -func ReconcileHorizon(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileHorizon(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { horizon := &horizonv1.Horizon{ ObjectMeta: metav1.ObjectMeta{ Name: "horizon", @@ -106,7 +106,9 @@ func ReconcileHorizon(ctx context.Context, instance *corev1beta1.OpenStackContro Log.Info("Reconcile Horizon", "horizon.Namespace", instance.Namespace, "horizon.Name", "horizon") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), horizon, func() error { - instance.Spec.Horizon.Template.DeepCopyInto(&horizon.Spec) + instance.Spec.Horizon.Template.DeepCopyInto(&horizon.Spec.HorizonSpecCore) + + horizon.Spec.ContainerImage = *version.Status.ContainerImages.HorizonImage horizon.Spec.Override.Service = ptr.To(serviceOverrides[service.EndpointPublic]) err := controllerutil.SetControllerReference(helper.GetBeforeObject(), horizon, helper.GetScheme()) @@ -129,7 +131,8 @@ func ReconcileHorizon(ctx context.Context, instance *corev1beta1.OpenStackContro Log.Info(fmt.Sprintf("Horizon %s - %s", horizon.Name, op)) } - if horizon.IsReady() { + if horizon.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.HorizonImage = version.Status.ContainerImages.HorizonImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneHorizonReadyCondition, corev1beta1.OpenStackControlPlaneHorizonReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/ironic.go b/pkg/openstack/ironic.go index 308b3e92f..5057c50d6 100644 --- a/pkg/openstack/ironic.go +++ b/pkg/openstack/ironic.go @@ -19,7 +19,7 @@ import ( ) // ReconcileIronic - -func ReconcileIronic(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileIronic(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { ironic := &ironicv1.Ironic{ ObjectMeta: metav1.ObjectMeta{ Name: "ironic", @@ -147,7 +147,15 @@ func ReconcileIronic(ctx context.Context, instance *corev1beta1.OpenStackControl Log.Info("Reconciling Ironic", "Ironic.Namespace", instance.Namespace, "Ironic.Name", "ironic") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), ironic, func() error { - instance.Spec.Ironic.Template.DeepCopyInto(&ironic.Spec) + instance.Spec.Ironic.Template.DeepCopyInto(&ironic.Spec.IronicSpecCore) + + ironic.Spec.Images.API = *version.Status.ContainerImages.IronicAPIImage + ironic.Spec.Images.Conductor = *version.Status.ContainerImages.IronicConductorImage + ironic.Spec.Images.Inspector = *version.Status.ContainerImages.IronicInspectorImage + ironic.Spec.Images.NeutronAgent = *version.Status.ContainerImages.IronicNeutronAgentImage + ironic.Spec.Images.Pxe = *version.Status.ContainerImages.IronicPxeImage + ironic.Spec.Images.IronicPythonAgent = *version.Status.ContainerImages.IronicPythonAgentImage + err := controllerutil.SetControllerReference(helper.GetBeforeObject(), ironic, helper.GetScheme()) if err != nil { return err @@ -168,7 +176,13 @@ func ReconcileIronic(ctx context.Context, instance *corev1beta1.OpenStackControl Log.Info(fmt.Sprintf("ironic %s - %s", ironic.Name, op)) } - if ironic.IsReady() { + if ironic.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.IronicAPIImage = version.Status.ContainerImages.IronicAPIImage + instance.Status.ContainerImages.IronicConductorImage = version.Status.ContainerImages.IronicConductorImage + instance.Status.ContainerImages.IronicInspectorImage = version.Status.ContainerImages.IronicInspectorImage + instance.Status.ContainerImages.IronicNeutronAgentImage = version.Status.ContainerImages.IronicNeutronAgentImage + instance.Status.ContainerImages.IronicPxeImage = version.Status.ContainerImages.IronicPxeImage + instance.Status.ContainerImages.IronicPythonAgentImage = version.Status.ContainerImages.IronicPythonAgentImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneIronicReadyCondition, corev1beta1.OpenStackControlPlaneIronicReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/keystone.go b/pkg/openstack/keystone.go index 4a47f04cc..f18db0288 100644 --- a/pkg/openstack/keystone.go +++ b/pkg/openstack/keystone.go @@ -19,7 +19,7 @@ import ( ) // ReconcileKeystoneAPI - -func ReconcileKeystoneAPI(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileKeystoneAPI(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { keystoneAPI := &keystonev1.KeystoneAPI{ ObjectMeta: metav1.ObjectMeta{ Name: "keystone", //FIXME (keystone doesn't seem to work unless named "keystone") @@ -100,8 +100,9 @@ func ReconcileKeystoneAPI(ctx context.Context, instance *corev1beta1.OpenStackCo Log.Info("Reconciling KeystoneAPI", "KeystoneAPI.Namespace", instance.Namespace, "KeystoneAPI.Name", "keystone") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), keystoneAPI, func() error { - instance.Spec.Keystone.Template.DeepCopyInto(&keystoneAPI.Spec) + instance.Spec.Keystone.Template.DeepCopyInto(&keystoneAPI.Spec.KeystoneAPISpecCore) + keystoneAPI.Spec.ContainerImage = *version.Status.ContainerImages.KeystoneAPIImage if keystoneAPI.Spec.Secret == "" { keystoneAPI.Spec.Secret = instance.Spec.Secret } @@ -133,7 +134,8 @@ func ReconcileKeystoneAPI(ctx context.Context, instance *corev1beta1.OpenStackCo Log.Info(fmt.Sprintf("KeystoneAPI %s - %s", keystoneAPI.Name, op)) } - if keystoneAPI.IsReady() { + if keystoneAPI.Status.ObservedGeneration == keystoneAPI.Generation && keystoneAPI.IsReady() { + instance.Status.ContainerImages.KeystoneAPIImage = version.Status.ContainerImages.KeystoneAPIImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneKeystoneAPIReadyCondition, corev1beta1.OpenStackControlPlaneKeystoneAPIReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/manila.go b/pkg/openstack/manila.go index 7b03a7eb6..f63f64dcb 100644 --- a/pkg/openstack/manila.go +++ b/pkg/openstack/manila.go @@ -2,6 +2,7 @@ package openstack import ( "context" + "errors" "fmt" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" @@ -19,7 +20,7 @@ import ( ) // ReconcileManila - -func ReconcileManila(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileManila(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { manila := &manilav1.Manila{ ObjectMeta: metav1.ObjectMeta{ Name: "manila", @@ -100,7 +101,32 @@ func ReconcileManila(ctx context.Context, instance *corev1beta1.OpenStackControl Log.Info("Reconciling Manila", "Manila.Namespace", instance.Namespace, "Manila.Name", "manila") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), manila, func() error { - instance.Spec.Manila.Template.DeepCopyInto(&manila.Spec) + instance.Spec.Manila.Template.ManilaSpecBase.DeepCopyInto(&manila.Spec.ManilaSpecBase) + instance.Spec.Manila.Template.ManilaAPI.DeepCopyInto(&manila.Spec.ManilaAPI.ManilaAPITemplateCore) + instance.Spec.Manila.Template.ManilaScheduler.DeepCopyInto(&manila.Spec.ManilaScheduler.ManilaSchedulerTemplateCore) + + manila.Spec.ManilaAPI.ContainerImage = *version.Status.ContainerImages.ManilaAPIImage + manila.Spec.ManilaScheduler.ContainerImage = *version.Status.ContainerImages.ManilaSchedulerImage + + defaultShareImg := version.Status.ContainerImages.ManilaShareImages["default"] + if defaultShareImg == nil { + return errors.New("default Manila Share images is unset") + } + + if manila.Spec.ManilaShares == nil { + manila.Spec.ManilaShares = make(map[string]manilav1.ManilaShareTemplate) + } + + for name, share := range instance.Spec.Manila.Template.ManilaShares { + manilaCore := manilav1.ManilaShareTemplate{} + share.DeepCopyInto(&manilaCore.ManilaShareTemplateCore) + if volVal, ok := version.Status.ContainerImages.ManilaShareImages[name]; ok { + manilaCore.ContainerImage = *volVal + } else { + manilaCore.ContainerImage = *defaultShareImg + } + manila.Spec.ManilaShares[name] = manilaCore + } if manila.Spec.Secret == "" { manila.Spec.Secret = instance.Spec.Secret @@ -140,7 +166,10 @@ func ReconcileManila(ctx context.Context, instance *corev1beta1.OpenStackControl Log.Info(fmt.Sprintf("Manila %s - %s", manila.Name, op)) } - if manila.IsReady() { + if manila.Status.ObservedGeneration == manila.Generation && manila.IsReady() { + instance.Status.ContainerImages.ManilaAPIImage = version.Status.ContainerImages.ManilaAPIImage + instance.Status.ContainerImages.ManilaSchedulerImage = version.Status.ContainerImages.ManilaSchedulerImage + instance.Status.ContainerImages.ManilaShareImages = version.Status.ContainerImages.ManilaShareImages instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneManilaReadyCondition, corev1beta1.OpenStackControlPlaneManilaReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/memcached.go b/pkg/openstack/memcached.go index 3509b629f..2b17d4a35 100644 --- a/pkg/openstack/memcached.go +++ b/pkg/openstack/memcached.go @@ -32,6 +32,7 @@ const ( func ReconcileMemcacheds( ctx context.Context, instance *corev1beta1.OpenStackControlPlane, + version *corev1beta1.OpenStackVersion, helper *helper.Helper, ) (ctrl.Result, error) { var failures []string = []string{} @@ -88,7 +89,7 @@ func ReconcileMemcacheds( var err error var status memcachedStatus for name, spec := range instance.Spec.Memcached.Templates { - status, ctrlResult, err = reconcileMemcached(ctx, instance, helper, name, &spec) + status, ctrlResult, err = reconcileMemcached(ctx, instance, version, helper, name, &spec) switch status { case memcachedFailed: @@ -133,9 +134,10 @@ func ReconcileMemcacheds( func reconcileMemcached( ctx context.Context, instance *corev1beta1.OpenStackControlPlane, + version *corev1beta1.OpenStackVersion, helper *helper.Helper, name string, - spec *memcachedv1.MemcachedSpec, + spec *memcachedv1.MemcachedSpecCore, ) (memcachedStatus, ctrl.Result, error) { memcached := &memcachedv1.Memcached{ ObjectMeta: metav1.ObjectMeta{ @@ -187,13 +189,13 @@ func reconcileMemcached( } op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), memcached, func() error { - spec.DeepCopyInto(&memcached.Spec) + spec.DeepCopyInto(&memcached.Spec.MemcachedSpecCore) if tlsCert != "" { memcached.Spec.TLS.SecretName = ptr.To(tlsCert) } memcached.Spec.TLS.CaBundleSecretName = tls.CABundleSecret - + memcached.Spec.ContainerImage = *version.Status.ContainerImages.InfraMemcachedImage err := controllerutil.SetControllerReference(helper.GetBeforeObject(), memcached, helper.GetScheme()) if err != nil { return err @@ -209,7 +211,8 @@ func reconcileMemcached( Log.Info(fmt.Sprintf("Memcached %s - %s", memcached.Name, op)) } - if memcached.IsReady() { + if memcached.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.InfraMemcachedImage = version.Status.ContainerImages.InfraMemcachedImage return memcachedReady, ctrl.Result{}, nil } diff --git a/pkg/openstack/neutron.go b/pkg/openstack/neutron.go index 2e7d9a27f..7e363158a 100644 --- a/pkg/openstack/neutron.go +++ b/pkg/openstack/neutron.go @@ -22,7 +22,7 @@ import ( ) // ReconcileNeutron - -func ReconcileNeutron(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileNeutron(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { neutronAPI := &neutronv1.NeutronAPI{ ObjectMeta: metav1.ObjectMeta{ Name: "neutron", @@ -132,8 +132,8 @@ func ReconcileNeutron(ctx context.Context, instance *corev1beta1.OpenStackContro Log.Info("Reconciling NeutronAPI", "NeutronAPI.Namespace", instance.Namespace, "NeutronAPI.Name", "neutron") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), neutronAPI, func() error { - instance.Spec.Neutron.Template.DeepCopyInto(&neutronAPI.Spec) - + instance.Spec.Neutron.Template.DeepCopyInto(&neutronAPI.Spec.NeutronAPISpecCore) + neutronAPI.Spec.ContainerImage = *version.Status.ContainerImages.NeutronAPIImage if neutronAPI.Spec.Secret == "" { neutronAPI.Spec.Secret = instance.Spec.Secret } @@ -172,7 +172,8 @@ func ReconcileNeutron(ctx context.Context, instance *corev1beta1.OpenStackContro Log.Info(fmt.Sprintf("neutronAPI %s - %s", neutronAPI.Name, op)) } - if neutronAPI.IsReady() { + if neutronAPI.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.NeutronAPIImage = version.Status.ContainerImages.NeutronAPIImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneNeutronReadyCondition, corev1beta1.OpenStackControlPlaneNeutronReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/nova.go b/pkg/openstack/nova.go index 5b493bba0..1efff7441 100644 --- a/pkg/openstack/nova.go +++ b/pkg/openstack/nova.go @@ -39,7 +39,7 @@ import ( ) // ReconcileNova - -func ReconcileNova(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileNova(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { nova := &novav1.Nova{ ObjectMeta: metav1.ObjectMeta{ Name: "nova", @@ -282,6 +282,13 @@ func ReconcileNova(ctx context.Context, instance *corev1beta1.OpenStackControlPl // RabbitMQCluster per nova cell. instance.Spec.Nova.Template.DeepCopyInto(&nova.Spec) + nova.Spec.NovaImages.APIContainerImageURL = *version.Status.ContainerImages.NovaAPIImage + nova.Spec.NovaImages.NovaComputeContainerImageURL = *version.Status.ContainerImages.NovaComputeImage + nova.Spec.NovaImages.ConductorContainerImageURL = *version.Status.ContainerImages.NovaConductorImage + nova.Spec.NovaImages.MetadataContainerImageURL = *version.Status.ContainerImages.NovaAPIImage //metadata uses novaAPI image + nova.Spec.NovaImages.SchedulerContainerImageURL = *version.Status.ContainerImages.NovaSchedulerImage + nova.Spec.NovaImages.NoVNCContainerImageURL = *version.Status.ContainerImages.NovaNovncImage + err := controllerutil.SetControllerReference(helper.GetBeforeObject(), nova, helper.GetScheme()) if err != nil { return err @@ -302,7 +309,12 @@ func ReconcileNova(ctx context.Context, instance *corev1beta1.OpenStackControlPl Log.Info(fmt.Sprintf("Nova %s - %s", nova.Name, op)) } - if nova.IsReady() { + if nova.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.NovaAPIImage = version.Status.ContainerImages.NovaAPIImage + instance.Status.ContainerImages.NovaComputeImage = version.Status.ContainerImages.NovaComputeImage + instance.Status.ContainerImages.NovaConductorImage = version.Status.ContainerImages.NovaConductorImage + instance.Status.ContainerImages.NovaNovncImage = version.Status.ContainerImages.NovaNovncImage + instance.Status.ContainerImages.NovaSchedulerImage = version.Status.ContainerImages.NovaSchedulerImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneNovaReadyCondition, corev1beta1.OpenStackControlPlaneNovaReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/octavia.go b/pkg/openstack/octavia.go index 073f9101d..89866a18e 100644 --- a/pkg/openstack/octavia.go +++ b/pkg/openstack/octavia.go @@ -36,7 +36,7 @@ import ( ) // ReconcileOctavia - -func ReconcileOctavia(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileOctavia(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { octavia := &octaviav1.Octavia{ ObjectMeta: metav1.ObjectMeta{ Name: "octavia", @@ -116,7 +116,17 @@ func ReconcileOctavia(ctx context.Context, instance *corev1beta1.OpenStackContro helper.GetLogger().Info("Reconciling Octavia", "Octavia.Namespace", instance.Namespace, "Octavia.Name", octavia.Name) op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), octavia, func() error { - instance.Spec.Octavia.Template.DeepCopyInto(&octavia.Spec) + instance.Spec.Octavia.Template.OctaviaSpecBase.DeepCopyInto(&octavia.Spec.OctaviaSpecBase) + instance.Spec.Octavia.Template.OctaviaAPI.DeepCopyInto(&octavia.Spec.OctaviaAPI.OctaviaAPISpecCore) + instance.Spec.Octavia.Template.OctaviaHousekeeping.DeepCopyInto(&octavia.Spec.OctaviaHousekeeping.OctaviaAmphoraControllerSpecCore) + instance.Spec.Octavia.Template.OctaviaHealthManager.DeepCopyInto(&octavia.Spec.OctaviaHealthManager.OctaviaAmphoraControllerSpecCore) + instance.Spec.Octavia.Template.OctaviaWorker.DeepCopyInto(&octavia.Spec.OctaviaWorker.OctaviaAmphoraControllerSpecCore) + + octavia.Spec.OctaviaAPI.ContainerImage = *version.Status.ContainerImages.OctaviaAPIImage + octavia.Spec.OctaviaWorker.ContainerImage = *version.Status.ContainerImages.OctaviaWorkerImage + octavia.Spec.OctaviaHealthManager.ContainerImage = *version.Status.ContainerImages.OctaviaHealthmanagerImage + octavia.Spec.OctaviaHousekeeping.ContainerImage = *version.Status.ContainerImages.OctaviaHousekeepingImage + err := controllerutil.SetControllerReference(helper.GetBeforeObject(), octavia, helper.GetScheme()) if err != nil { return err @@ -137,7 +147,11 @@ func ReconcileOctavia(ctx context.Context, instance *corev1beta1.OpenStackContro helper.GetLogger().Info(fmt.Sprintf("Octavia %s - %s", octavia.Name, op)) } - if octavia.IsReady() { + if octavia.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.OctaviaAPIImage = version.Status.ContainerImages.OctaviaAPIImage + instance.Status.ContainerImages.OctaviaWorkerImage = version.Status.ContainerImages.OctaviaWorkerImage + instance.Status.ContainerImages.OctaviaHealthmanagerImage = version.Status.ContainerImages.OctaviaHealthmanagerImage + instance.Status.ContainerImages.OctaviaHousekeepingImage = version.Status.ContainerImages.OctaviaHousekeepingImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneOctaviaReadyCondition, corev1beta1.OpenStackControlPlaneOctaviaReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/openstackclient.go b/pkg/openstack/openstackclient.go index 06f115b9d..80d0f7f42 100644 --- a/pkg/openstack/openstackclient.go +++ b/pkg/openstack/openstackclient.go @@ -33,7 +33,7 @@ const ( ) // ReconcileOpenStackClient - -func ReconcileOpenStackClient(ctx context.Context, instance *corev1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileOpenStackClient(ctx context.Context, instance *corev1.OpenStackControlPlane, version *corev1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { openstackclient := &clientv1.OpenStackClient{ ObjectMeta: metav1.ObjectMeta{ @@ -47,6 +47,8 @@ func ReconcileOpenStackClient(ctx context.Context, instance *corev1.OpenStackCon op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), openstackclient, func() error { instance.Spec.OpenStackClient.Template.DeepCopyInto(&openstackclient.Spec) + openstackclient.Spec.ContainerImage = *version.Status.ContainerImages.OpenstackClientImage + if instance.Spec.TLS.Ingress.Enabled || instance.Spec.TLS.PodLevel.Enabled { openstackclient.Spec.Ca.CaBundleSecretName = tls.CABundleSecret } @@ -71,8 +73,9 @@ func ReconcileOpenStackClient(ctx context.Context, instance *corev1.OpenStackCon Log.Info(fmt.Sprintf("OpenStackClient %s - %s", openstackclient.Name, op)) } - if openstackclient.Status.Conditions.IsTrue(clientv1.OpenStackClientReadyCondition) { + if openstackclient.Status.Conditions.IsTrue(clientv1.OpenStackClientReadyCondition) { //FIXME ObservedGeneration Log.Info("OpenStackClient ready condition is true") + instance.Status.ContainerImages.OpenstackClientImage = version.Status.ContainerImages.OpenstackClientImage instance.Status.Conditions.MarkTrue(corev1.OpenStackControlPlaneClientReadyCondition, corev1.OpenStackControlPlaneClientReadyMessage) } else { Log.Info("OpenStackClient ready condition is false") diff --git a/pkg/openstack/ovn.go b/pkg/openstack/ovn.go index 5d1efbd66..f8e8ba2ea 100644 --- a/pkg/openstack/ovn.go +++ b/pkg/openstack/ovn.go @@ -20,8 +20,8 @@ import ( ) // ReconcileOVN - -func ReconcileOVN(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { - +func ReconcileOVN(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { + Log := GetLogger(ctx) setOVNReadyError := func(instance *corev1beta1.OpenStackControlPlane, err error) { instance.Status.Conditions.Set(condition.FalseCondition( corev1beta1.OpenStackControlPlaneOVNReadyCondition, @@ -31,21 +31,26 @@ func ReconcileOVN(ctx context.Context, instance *corev1beta1.OpenStackControlPla err.Error())) } - OVNDBClustersReady, err := ReconcileOVNDbClusters(ctx, instance, helper) + OVNDBClustersReady, err := ReconcileOVNDbClusters(ctx, instance, version, helper) if err != nil { + Log.Error(err, "Failed to reconcile OVNDBClusters") setOVNReadyError(instance, err) } - OVNNorthdReady, err := ReconcileOVNNorthd(ctx, instance, helper) + OVNNorthdReady, err := ReconcileOVNNorthd(ctx, instance, version, helper) if err != nil { + Log.Error(err, "Failed to reconcile OVNNorthd") setOVNReadyError(instance, err) } - OVNControllerReady, err := ReconcileOVNController(ctx, instance, helper) + OVNControllerReady, err := ReconcileOVNController(ctx, instance, version, helper) if err != nil { + Log.Error(err, "Failed to reconcile OVNController") setOVNReadyError(instance, err) } + Log.Info("Reconciling OVN", "OVNDBClustersReady", OVNDBClustersReady, "OVNNorthdReady", OVNNorthdReady, "OVNControllerReady", OVNControllerReady) + // Expect all services (dbclusters, northd, ovn-controller) ready if OVNDBClustersReady && OVNNorthdReady && OVNControllerReady { instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneOVNReadyCondition, corev1beta1.OpenStackControlPlaneOVNReadyMessage) @@ -61,7 +66,7 @@ func ReconcileOVN(ctx context.Context, instance *corev1beta1.OpenStackControlPla return ctrl.Result{}, nil } -func ReconcileOVNDbClusters(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (bool, error) { +func ReconcileOVNDbClusters(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (bool, error) { Log := GetLogger(ctx) OVNDBClustersReady := len(instance.Spec.Ovn.Template.OVNDBCluster) != 0 @@ -129,7 +134,14 @@ func ReconcileOVNDbClusters(ctx context.Context, instance *corev1beta1.OpenStack Log.Info("Reconciling OVNDBCluster", "OVNDBCluster.Namespace", instance.Namespace, "OVNDBCluster.Name", name) op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), OVNDBCluster, func() error { - dbcluster.DeepCopyInto(&OVNDBCluster.Spec) + dbcluster.DeepCopyInto(&OVNDBCluster.Spec.OVNDBClusterSpecCore) + + // we always set these to match OpenStackVersion + if dbcluster.DBType == ovnv1.NBDBType { + OVNDBCluster.Spec.ContainerImage = *version.Status.ContainerImages.OvnNbDbclusterImage + } else if dbcluster.DBType == ovnv1.SBDBType { + OVNDBCluster.Spec.ContainerImage = *version.Status.ContainerImages.OvnSbDbclusterImage + } if OVNDBCluster.Spec.NodeSelector == nil && instance.Spec.NodeSelector != nil { OVNDBCluster.Spec.NodeSelector = instance.Spec.NodeSelector @@ -146,17 +158,26 @@ func ReconcileOVNDbClusters(ctx context.Context, instance *corev1beta1.OpenStack }) if err != nil { + Log.Error(err, "Failed to reconcile OVNDBCluster") return false, err } if op != controllerutil.OperationResultNone { Log.Info(fmt.Sprintf("OVNDBCluster %s - %s", OVNDBCluster.Name, op)) } - OVNDBClustersReady = OVNDBClustersReady && OVNDBCluster.IsReady() + + OVNDBClustersReady = OVNDBClustersReady && (OVNDBCluster.Status.ObservedGeneration == OVNDBCluster.Generation) && OVNDBCluster.IsReady() + + } + if OVNDBClustersReady { + instance.Status.ContainerImages.OvnNbDbclusterImage = version.Status.ContainerImages.OvnNbDbclusterImage + instance.Status.ContainerImages.OvnSbDbclusterImage = version.Status.ContainerImages.OvnSbDbclusterImage } + return OVNDBClustersReady, nil + } -func ReconcileOVNNorthd(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (bool, error) { +func ReconcileOVNNorthd(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (bool, error) { Log := GetLogger(ctx) OVNNorthd := &ovnv1.OVNNorthd{ @@ -220,7 +241,9 @@ func ReconcileOVNNorthd(ctx context.Context, instance *corev1beta1.OpenStackCont Log.Info("Reconciling OVNNorthd", "OVNNorthd.Namespace", instance.Namespace, "OVNNorthd.Name", "ovnnorthd") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), OVNNorthd, func() error { - instance.Spec.Ovn.Template.OVNNorthd.DeepCopyInto(&OVNNorthd.Spec) + instance.Spec.Ovn.Template.OVNNorthd.DeepCopyInto(&OVNNorthd.Spec.OVNNorthdSpecCore) + + OVNNorthd.Spec.ContainerImage = *version.Status.ContainerImages.OvnNorthdImage if OVNNorthd.Spec.NodeSelector == nil && instance.Spec.NodeSelector != nil { OVNNorthd.Spec.NodeSelector = instance.Spec.NodeSelector @@ -240,15 +263,23 @@ func ReconcileOVNNorthd(ctx context.Context, instance *corev1beta1.OpenStackCont condition.SeverityWarning, corev1beta1.OpenStackControlPlaneOVNReadyErrorMessage, err.Error())) + Log.Error(err, "Failed to reconcile OVNNorthd") return false, err } if op != controllerutil.OperationResultNone { Log.Info(fmt.Sprintf("OVNNorthd %s - %s", OVNNorthd.Name, op)) } - return OVNNorthd.IsReady(), nil + + if OVNNorthd.Status.ObservedGeneration == OVNNorthd.Generation && OVNNorthd.IsReady() { + instance.Status.ContainerImages.OvnNorthdImage = version.Status.ContainerImages.OvnNorthdImage + return true, nil + } else { + return false, nil + } + } -func ReconcileOVNController(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (bool, error) { +func ReconcileOVNController(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (bool, error) { Log := GetLogger(ctx) OVNController := &ovnv1.OVNController{ @@ -312,7 +343,10 @@ func ReconcileOVNController(ctx context.Context, instance *corev1beta1.OpenStack Log.Info("Reconciling OVNController", "OVNController.Namespace", instance.Namespace, "OVNController.Name", "ovncontroller") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), OVNController, func() error { - instance.Spec.Ovn.Template.OVNController.DeepCopyInto(&OVNController.Spec) + instance.Spec.Ovn.Template.OVNController.DeepCopyInto(&OVNController.Spec.OVNControllerSpecCore) + + OVNController.Spec.OvnContainerImage = *version.Status.ContainerImages.OvnControllerImage + OVNController.Spec.OvsContainerImage = *version.Status.ContainerImages.OvnControllerOvsImage if OVNController.Spec.NodeSelector == nil && instance.Spec.NodeSelector != nil { OVNController.Spec.NodeSelector = instance.Spec.NodeSelector @@ -332,11 +366,18 @@ func ReconcileOVNController(ctx context.Context, instance *corev1beta1.OpenStack condition.SeverityWarning, corev1beta1.OpenStackControlPlaneOVNReadyErrorMessage, err.Error())) + Log.Error(err, "Failed to reconcile OVNController") return false, err } if op != controllerutil.OperationResultNone { Log.Info(fmt.Sprintf("OVNController %s - %s", OVNController.Name, op)) } - return OVNController.IsReady(), nil + if OVNController.Status.ObservedGeneration == OVNController.Generation && OVNController.IsReady() { + instance.Status.ContainerImages.OvnControllerImage = version.Status.ContainerImages.OvnControllerImage + instance.Status.ContainerImages.OvnControllerOvsImage = version.Status.ContainerImages.OvnControllerOvsImage + return true, nil + } else { + return false, nil + } } diff --git a/pkg/openstack/placement.go b/pkg/openstack/placement.go index f295f9bc1..1e67022a1 100644 --- a/pkg/openstack/placement.go +++ b/pkg/openstack/placement.go @@ -19,7 +19,7 @@ import ( ) // ReconcilePlacementAPI - -func ReconcilePlacementAPI(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcilePlacementAPI(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { placementAPI := &placementv1.PlacementAPI{ ObjectMeta: metav1.ObjectMeta{ Name: "placement", @@ -98,8 +98,9 @@ func ReconcilePlacementAPI(ctx context.Context, instance *corev1beta1.OpenStackC Log.Info("Reconciling PlacementAPI", "PlacementAPI.Namespace", instance.Namespace, "PlacementAPI.Name", "placement") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), placementAPI, func() error { - instance.Spec.Placement.Template.DeepCopyInto(&placementAPI.Spec) + instance.Spec.Placement.Template.DeepCopyInto(&placementAPI.Spec.PlacementAPISpecCore) + placementAPI.Spec.ContainerImage = *version.Status.ContainerImages.PlacementAPIImage if placementAPI.Spec.Secret == "" { placementAPI.Spec.Secret = instance.Spec.Secret } @@ -130,6 +131,7 @@ func ReconcilePlacementAPI(ctx context.Context, instance *corev1beta1.OpenStackC } if placementAPI.IsReady() { + instance.Status.ContainerImages.PlacementAPIImage = version.Status.ContainerImages.PlacementAPIImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlanePlacementAPIReadyCondition, corev1beta1.OpenStackControlPlanePlacementAPIReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/rabbitmq.go b/pkg/openstack/rabbitmq.go index 48cb2a292..afeba00e7 100644 --- a/pkg/openstack/rabbitmq.go +++ b/pkg/openstack/rabbitmq.go @@ -38,6 +38,7 @@ const ( func ReconcileRabbitMQs( ctx context.Context, instance *corev1beta1.OpenStackControlPlane, + version *corev1beta1.OpenStackVersion, helper *helper.Helper, ) (ctrl.Result, error) { var failures []string = []string{} @@ -47,7 +48,7 @@ func ReconcileRabbitMQs( var status mqStatus for name, spec := range instance.Spec.Rabbitmq.Templates { - status, ctrlResult, err = reconcileRabbitMQ(ctx, instance, helper, name, spec) + status, ctrlResult, err = reconcileRabbitMQ(ctx, instance, version, helper, name, spec) switch status { case mqFailed: @@ -91,6 +92,7 @@ func ReconcileRabbitMQs( func reconcileRabbitMQ( ctx context.Context, instance *corev1beta1.OpenStackControlPlane, + version *corev1beta1.OpenStackVersion, helper *helper.Helper, name string, spec corev1beta1.RabbitmqTemplate, @@ -176,7 +178,7 @@ func reconcileRabbitMQ( Name: "rabbitmq", // NOTE(gibi): without this the second RabbitMqCluster // will fail as the Pod will have no image. - Image: spec.Image, + Image: *version.Status.ContainerImages.RabbitmqImage, Env: envVars, Args: []string{ // OSP17 runs kolla_start here, instead just run rabbitmq-server directly @@ -228,13 +230,23 @@ func reconcileRabbitMQ( op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), rabbitmq, func() error { - spec.RabbitmqClusterSpec.DeepCopyInto(&rabbitmq.Spec) - - //FIXME: We shouldn't have to set this here but not setting it causes the rabbitmq - // operator to continuously mutate the CR when setting it: - // https://github.com/rabbitmq/cluster-operator/blob/main/controllers/reconcile_operator_defaults.go#L19 - if rabbitmq.Spec.Image == "" { - rabbitmq.Spec.Image = "registry.redhat.io/rhosp-rhel9/openstack-rabbitmq:17.0" + rabbitmq.Spec.Image = *version.Status.ContainerImages.RabbitmqImage + rabbitmq.Spec.Replicas = spec.Replicas + rabbitmq.Spec.Tolerations = spec.Tolerations + rabbitmq.Spec.SkipPostDeploySteps = spec.SkipPostDeploySteps + rabbitmq.Spec.TerminationGracePeriodSeconds = spec.TerminationGracePeriodSeconds + rabbitmq.Spec.DelayStartSeconds = spec.DelayStartSeconds + spec.Service.DeepCopyInto(&rabbitmq.Spec.Service) + spec.Persistence.DeepCopyInto(&rabbitmq.Spec.Persistence) + spec.Override.DeepCopyInto(&rabbitmq.Spec.Override) + spec.SecretBackend.DeepCopyInto(&rabbitmq.Spec.SecretBackend) + if spec.Resources != nil { + rabbitmq.Spec.Resources = spec.Resources + //spec.Resources.DeepCopyInto(rabbitmq.Spec.Resources) + } + if spec.Affinity != nil { + rabbitmq.Spec.Affinity = spec.Affinity + //spec.Affinity.DeepCopyInto(rabbitmq.Spec.Affinity) } if rabbitmq.Spec.Persistence.StorageClassName == nil { @@ -284,11 +296,14 @@ func reconcileRabbitMQ( Log.Info(fmt.Sprintf("RabbitMQ %s - %s", rabbitmq.Name, op)) } - for _, oldCond := range rabbitmq.Status.Conditions { - // Forced to hardcode "ClusterAvailable" here because linter will not allow - // us to import "github.com/rabbitmq/cluster-operator/internal/status" - if string(oldCond.Type) == "ClusterAvailable" && oldCond.Status == corev1.ConditionTrue { - return mqReady, ctrl.Result{}, nil + if rabbitmq.Status.ObservedGeneration == rabbitmq.Generation { + for _, oldCond := range rabbitmq.Status.Conditions { + // Forced to hardcode "ClusterAvailable" here because linter will not allow + // us to import "github.com/rabbitmq/cluster-operator/internal/status" + if string(oldCond.Type) == "ClusterAvailable" && oldCond.Status == corev1.ConditionTrue { + instance.Status.ContainerImages.RabbitmqImage = version.Status.ContainerImages.RabbitmqImage + return mqReady, ctrl.Result{}, nil + } } } diff --git a/pkg/openstack/redis.go b/pkg/openstack/redis.go index c7bf23d55..1e1d6d408 100644 --- a/pkg/openstack/redis.go +++ b/pkg/openstack/redis.go @@ -32,6 +32,7 @@ const ( func ReconcileRedis( ctx context.Context, instance *corev1beta1.OpenStackControlPlane, + version *corev1beta1.OpenStackVersion, helper *helper.Helper, ) (ctrl.Result, error) { var failures []string = []string{} @@ -104,7 +105,7 @@ func ReconcileRedis( var status redisStatus for name, spec := range instance.Spec.Redis.Templates { - status, ctrlResult, err = reconcileRedis(ctx, instance, helper, name, &spec) + status, ctrlResult, err = reconcileRedis(ctx, instance, version, helper, name, &spec) switch status { case redisFailed: @@ -151,9 +152,10 @@ func ReconcileRedis( func reconcileRedis( ctx context.Context, instance *corev1beta1.OpenStackControlPlane, + version *corev1beta1.OpenStackVersion, helper *helper.Helper, name string, - spec *redisv1.RedisSpec, + spec *redisv1.RedisSpecCore, ) (redisStatus, ctrl.Result, error) { redis := &redisv1.Redis{ ObjectMeta: metav1.ObjectMeta{ @@ -202,13 +204,14 @@ func reconcileRedis( } op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), redis, func() error { - spec.DeepCopyInto(&redis.Spec) + spec.DeepCopyInto(&redis.Spec.RedisSpecCore) if tlsCert != "" { redis.Spec.TLS.SecretName = ptr.To(tlsCert) } redis.Spec.TLS.CaBundleSecretName = tls.CABundleSecret + redis.Spec.ContainerImage = *version.Status.ContainerImages.InfraRedisImage err := controllerutil.SetControllerReference(helper.GetBeforeObject(), redis, helper.GetScheme()) if err != nil { return err @@ -224,7 +227,8 @@ func reconcileRedis( helper.GetLogger().Info(fmt.Sprintf("Redis %s - %s", redis.Name, op)) } - if redis.IsReady() { + if redis.IsReady() { //FIXME ObserverdGeneration + instance.Status.ContainerImages.InfraRedisImage = version.Status.ContainerImages.InfraRedisImage return redisReady, ctrl.Result{}, nil } diff --git a/pkg/openstack/swift.go b/pkg/openstack/swift.go index a522d0871..4b1dcdc64 100644 --- a/pkg/openstack/swift.go +++ b/pkg/openstack/swift.go @@ -19,7 +19,7 @@ import ( ) // ReconcileSwift - -func ReconcileSwift(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileSwift(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { swift := &swiftv1.Swift{ ObjectMeta: metav1.ObjectMeta{ Name: "swift", @@ -100,7 +100,17 @@ func ReconcileSwift(ctx context.Context, instance *corev1beta1.OpenStackControlP Log.Info("Reconciling Swift", "Swift.Namespace", instance.Namespace, "Swift.Name", "swift") op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), swift, func() error { - instance.Spec.Swift.Template.DeepCopyInto(&swift.Spec) + instance.Spec.Swift.Template.SwiftSpecBase.DeepCopyInto(&swift.Spec.SwiftSpecBase) + instance.Spec.Swift.Template.SwiftProxy.DeepCopyInto(&swift.Spec.SwiftProxy.SwiftProxySpecCore) + instance.Spec.Swift.Template.SwiftStorage.DeepCopyInto(&swift.Spec.SwiftStorage.SwiftStorageSpecCore) + instance.Spec.Swift.Template.SwiftRing.DeepCopyInto(&swift.Spec.SwiftRing.SwiftRingSpecCore) + + swift.Spec.SwiftRing.ContainerImage = *version.Status.ContainerImages.SwiftProxyImage + swift.Spec.SwiftStorage.ContainerImageAccount = *version.Status.ContainerImages.SwiftAccountImage + swift.Spec.SwiftStorage.ContainerImageContainer = *version.Status.ContainerImages.SwiftContainerImage + swift.Spec.SwiftStorage.ContainerImageObject = *version.Status.ContainerImages.SwiftObjectImage + swift.Spec.SwiftStorage.ContainerImageProxy = *version.Status.ContainerImages.SwiftProxyImage + swift.Spec.SwiftProxy.ContainerImageProxy = *version.Status.ContainerImages.SwiftProxyImage err := controllerutil.SetControllerReference(helper.GetBeforeObject(), swift, helper.GetScheme()) if err != nil { @@ -122,7 +132,11 @@ func ReconcileSwift(ctx context.Context, instance *corev1beta1.OpenStackControlP Log.Info(fmt.Sprintf("Swift %s - %s", swift.Name, op)) } - if swift.IsReady() { + if swift.Status.ObservedGeneration == swift.GetGeneration() && swift.IsReady() { + instance.Status.ContainerImages.SwiftAccountImage = version.Status.ContainerImages.SwiftAccountImage + instance.Status.ContainerImages.SwiftContainerImage = version.Status.ContainerImages.SwiftContainerImage + instance.Status.ContainerImages.SwiftObjectImage = version.Status.ContainerImages.SwiftObjectImage + instance.Status.ContainerImages.SwiftProxyImage = version.Status.ContainerImages.SwiftProxyImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneSwiftReadyCondition, corev1beta1.OpenStackControlPlaneSwiftReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/telemetry.go b/pkg/openstack/telemetry.go index d09642960..5233fe93e 100644 --- a/pkg/openstack/telemetry.go +++ b/pkg/openstack/telemetry.go @@ -27,7 +27,7 @@ const ( ) // ReconcileTelemetry puts telemetry resources to required state -func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, error) { +func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { telemetry := &telemetryv1.Telemetry{ ObjectMeta: metav1.ObjectMeta{ Name: telemetryName, @@ -220,7 +220,27 @@ func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackCont helper.GetLogger().Info("Reconciling Telemetry", telemetryNamespaceLabel, instance.Namespace, telemetryNameLabel, telemetryName) op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), telemetry, func() error { - instance.Spec.Telemetry.Template.DeepCopyInto(&telemetry.Spec) + instance.Spec.Telemetry.Template.TelemetrySpecBase.DeepCopyInto(&telemetry.Spec.TelemetrySpecBase) + instance.Spec.Telemetry.Template.Autoscaling.AutoscalingSpecBase.DeepCopyInto(&telemetry.Spec.Autoscaling.AutoscalingSpecBase) + instance.Spec.Telemetry.Template.Ceilometer.CeilometerSpecCore.DeepCopyInto(&telemetry.Spec.Ceilometer.CeilometerSpecCore) + instance.Spec.Telemetry.Template.Logging.DeepCopyInto(&telemetry.Spec.Logging) + instance.Spec.Telemetry.Template.MetricStorage.DeepCopyInto(&telemetry.Spec.MetricStorage) + + // FIXME: need to switch telemetry operator enabled defaults to bool pointers to get around webhook defaulting issues + telemetry.Spec.Ceilometer.Enabled = instance.Spec.Telemetry.Template.Ceilometer.Enabled + telemetry.Spec.Autoscaling.Enabled = instance.Spec.Telemetry.Template.Autoscaling.Enabled + telemetry.Spec.Logging.Enabled = instance.Spec.Telemetry.Template.Logging.Enabled + telemetry.Spec.MetricStorage.Enabled = instance.Spec.Telemetry.Template.MetricStorage.Enabled + + telemetry.Spec.Ceilometer.CentralImage = *version.Status.ContainerImages.CeilometerCentralImage + telemetry.Spec.Ceilometer.ComputeImage = *version.Status.ContainerImages.CeilometerComputeImage + telemetry.Spec.Ceilometer.IpmiImage = *version.Status.ContainerImages.CeilometerIpmiImage + telemetry.Spec.Ceilometer.NotificationImage = *version.Status.ContainerImages.CeilometerNotificationImage + telemetry.Spec.Ceilometer.SgCoreImage = *version.Status.ContainerImages.CeilometerSgcoreImage + telemetry.Spec.Autoscaling.AutoscalingSpec.Aodh.APIImage = *version.Status.ContainerImages.AodhAPIImage + telemetry.Spec.Autoscaling.AutoscalingSpec.Aodh.EvaluatorImage = *version.Status.ContainerImages.AodhEvaluatorImage + telemetry.Spec.Autoscaling.AutoscalingSpec.Aodh.NotifierImage = *version.Status.ContainerImages.AodhNotifierImage + telemetry.Spec.Autoscaling.AutoscalingSpec.Aodh.ListenerImage = *version.Status.ContainerImages.AodhListenerImage if telemetry.Spec.Ceilometer.Secret == "" { telemetry.Spec.Ceilometer.Secret = instance.Spec.Secret @@ -257,7 +277,16 @@ func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackCont helper.GetLogger().Info(fmt.Sprintf("%s %s - %s", telemetryName, telemetry.Name, op)) } - if telemetry.IsReady() { + if telemetry.IsReady() { //FIXME ObservedGeneration + instance.Status.ContainerImages.CeilometerCentralImage = version.Status.ContainerImages.CeilometerCentralImage + instance.Status.ContainerImages.CeilometerComputeImage = version.Status.ContainerImages.CeilometerComputeImage + instance.Status.ContainerImages.CeilometerIpmiImage = version.Status.ContainerImages.CeilometerIpmiImage + instance.Status.ContainerImages.CeilometerNotificationImage = version.Status.ContainerImages.CeilometerNotificationImage + instance.Status.ContainerImages.CeilometerSgcoreImage = version.Status.ContainerImages.CeilometerSgcoreImage + instance.Status.ContainerImages.AodhAPIImage = version.Status.ContainerImages.AodhAPIImage + instance.Status.ContainerImages.AodhEvaluatorImage = version.Status.ContainerImages.AodhEvaluatorImage + instance.Status.ContainerImages.AodhNotifierImage = version.Status.ContainerImages.AodhNotifierImage + instance.Status.ContainerImages.AodhListenerImage = version.Status.ContainerImages.AodhListenerImage instance.Status.Conditions.MarkTrue(corev1beta1.OpenStackControlPlaneTelemetryReadyCondition, corev1beta1.OpenStackControlPlaneTelemetryReadyMessage) } else { instance.Status.Conditions.Set(condition.FalseCondition( diff --git a/pkg/openstack/version.go b/pkg/openstack/version.go new file mode 100644 index 000000000..f5bc42814 --- /dev/null +++ b/pkg/openstack/version.go @@ -0,0 +1,212 @@ +package openstack + +import ( + "context" + "fmt" + "reflect" + "regexp" + "strings" + + "github.com/openstack-k8s-operators/lib-common/modules/common/helper" + corev1beta1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// InitializeOpenStackVersionImageDefaults - initializes OpenStackVersion CR with default container images +func InitializeOpenStackVersionImageDefaults(ctx context.Context, envImages map[string]*string) *corev1beta1.ContainerDefaults { + Log := GetLogger(ctx) + + defaults := &corev1beta1.ContainerDefaults{} + + d := reflect.ValueOf(defaults).Elem() + for key, val := range envImages { + Log.Info(fmt.Sprintf("Initialize OpenStackVersion Image Defaults: %s", key)) + + r := regexp.MustCompile(`[A-Za-z0-9]+`) + matches := r.FindAllString(key, -1) + fieldName := "" + // only match related image strings + if matches[0] == "RELATED" && matches[1] == "IMAGE" { + // exclude prefix and suffix fields (2 and 2 each respectively) + // first 2 fields are "RELATED" and "IMAGE" + // last 2 fields are "URL" and "DEFAULT" + for i := 2; i < len(matches)-2; i++ { + fieldName += strings.ToUpper(matches[i])[0:1] + fieldName += strings.ToLower(matches[i])[1:] + } + // format API so we adhere to go linting standards + fieldName = strings.Replace(fieldName, "Api", "API", -1) + // EDPM variables have OPENSTACK prefixes we drop + if strings.Contains(fieldName, "Edpm") { + fieldName = strings.Replace(fieldName, "Openstack", "", -1) + fieldName += "Image" + } + // FIXME: RELATED_IMAGE_OPENSTACK_EDPM_OVN_BGP_AGENT_IMAGE is inconsistent with other EDPM image names + if fieldName == "EdpmOvnBgpImage" { + fieldName = "EdpmOvnBgpAgentImage" + } + } + Log.Info(fmt.Sprintf("Initialize Field name: %s", fieldName)) + field := d.FieldByName(fieldName) + if field.IsValid() && field.CanSet() { + field.Set(reflect.ValueOf(val)) + } else { + Log.Info(fmt.Sprintf("Field not found: %s", fieldName)) + } + } + Log.Info("Initialize OpenStackVersion Cinder/Manila:") + if envImages["RELATED_IMAGE_CINDER_VOLUME_IMAGE_URL_DEFAULT"] != nil { + defaults.CinderVolumeImage = envImages["RELATED_IMAGE_CINDER_VOLUME_IMAGE_URL_DEFAULT"] + } + if envImages["RELATED_IMAGE_MANILA_SHARE_IMAGE_URL_DEFAULT"] != nil { + defaults.ManilaShareImage = envImages["RELATED_IMAGE_MANILA_SHARE_IMAGE_URL_DEFAULT"] + } + Log.Info("Initialize OpenStackVersion return defaults") + return defaults + +} + +// getImg return val1 if set, otherwise return val2 +func getImg(val1 *string, val2 *string) *string { + if val1 != nil { + return val1 + } + return val2 + +} + +// GetContainerImages - initializes OpenStackVersion CR with default container images +func GetContainerImages(ctx context.Context, defaults *corev1beta1.ContainerDefaults, instance corev1beta1.OpenStackVersion) corev1beta1.ContainerImages { + + containerImages := corev1beta1.ContainerImages{ + CinderVolumeImages: instance.Spec.CustomContainerImages.CinderVolumeImages, + ManilaShareImages: instance.Spec.CustomContainerImages.ManilaShareImages, + ContainerTemplate: corev1beta1.ContainerTemplate{ + AgentImage: getImg(instance.Spec.CustomContainerImages.AgentImage, defaults.AgentImage), + AnsibleeeImage: getImg(instance.Spec.CustomContainerImages.AnsibleeeImage, defaults.AnsibleeeImage), + AodhAPIImage: getImg(instance.Spec.CustomContainerImages.AodhAPIImage, defaults.AodhAPIImage), + AodhEvaluatorImage: getImg(instance.Spec.CustomContainerImages.AodhEvaluatorImage, defaults.AodhEvaluatorImage), + AodhListenerImage: getImg(instance.Spec.CustomContainerImages.AodhListenerImage, defaults.AodhListenerImage), + AodhNotifierImage: getImg(instance.Spec.CustomContainerImages.AodhNotifierImage, defaults.AodhNotifierImage), + ApacheImage: getImg(instance.Spec.CustomContainerImages.ApacheImage, defaults.ApacheImage), + BarbicanAPIImage: getImg(instance.Spec.CustomContainerImages.BarbicanAPIImage, defaults.BarbicanAPIImage), + BarbicanKeystoneListenerImage: getImg(instance.Spec.CustomContainerImages.BarbicanKeystoneListenerImage, defaults.BarbicanKeystoneListenerImage), + BarbicanWorkerImage: getImg(instance.Spec.CustomContainerImages.BarbicanWorkerImage, defaults.BarbicanWorkerImage), + CeilometerCentralImage: getImg(instance.Spec.CustomContainerImages.CeilometerCentralImage, defaults.CeilometerCentralImage), + CeilometerComputeImage: getImg(instance.Spec.CustomContainerImages.CeilometerComputeImage, defaults.CeilometerComputeImage), + CeilometerIpmiImage: getImg(instance.Spec.CustomContainerImages.CeilometerIpmiImage, defaults.CeilometerIpmiImage), + CeilometerNotificationImage: getImg(instance.Spec.CustomContainerImages.CeilometerNotificationImage, defaults.CeilometerNotificationImage), + CeilometerSgcoreImage: getImg(instance.Spec.CustomContainerImages.CeilometerSgcoreImage, defaults.CeilometerSgcoreImage), + CinderAPIImage: getImg(instance.Spec.CustomContainerImages.CinderAPIImage, defaults.CinderAPIImage), + CinderBackupImage: getImg(instance.Spec.CustomContainerImages.CinderBackupImage, defaults.CinderBackupImage), + CinderSchedulerImage: getImg(instance.Spec.CustomContainerImages.CinderSchedulerImage, defaults.CinderSchedulerImage), + DesignateAPIImage: getImg(instance.Spec.CustomContainerImages.DesignateAPIImage, defaults.DesignateAPIImage), + DesignateBackendbind9Image: getImg(instance.Spec.CustomContainerImages.DesignateBackendbind9Image, defaults.DesignateBackendbind9Image), + DesignateCentralImage: getImg(instance.Spec.CustomContainerImages.DesignateCentralImage, defaults.DesignateCentralImage), + DesignateMdnsImage: getImg(instance.Spec.CustomContainerImages.DesignateMdnsImage, defaults.DesignateMdnsImage), + DesignateProducerImage: getImg(instance.Spec.CustomContainerImages.DesignateProducerImage, defaults.DesignateProducerImage), + DesignateUnboundImage: getImg(instance.Spec.CustomContainerImages.DesignateUnboundImage, defaults.DesignateUnboundImage), + DesignateWorkerImage: getImg(instance.Spec.CustomContainerImages.DesignateWorkerImage, defaults.DesignateWorkerImage), + EdpmFrrImage: getImg(instance.Spec.CustomContainerImages.EdpmFrrImage, defaults.EdpmFrrImage), + EdpmIscsidImage: getImg(instance.Spec.CustomContainerImages.EdpmIscsidImage, defaults.EdpmIscsidImage), + EdpmLogrotateCrondImage: getImg(instance.Spec.CustomContainerImages.EdpmLogrotateCrondImage, defaults.EdpmLogrotateCrondImage), + EdpmNeutronMetadataAgentImage: getImg(instance.Spec.CustomContainerImages.EdpmNeutronMetadataAgentImage, defaults.EdpmNeutronMetadataAgentImage), + EdpmNeutronSriovAgentImage: getImg(instance.Spec.CustomContainerImages.EdpmNeutronSriovAgentImage, defaults.EdpmNeutronSriovAgentImage), + EdpmOvnBgpAgentImage: getImg(instance.Spec.CustomContainerImages.EdpmOvnBgpAgentImage, defaults.EdpmOvnBgpAgentImage), + EdpmNodeExporterImage: getImg(instance.Spec.CustomContainerImages.EdpmNodeExporterImage, defaults.EdpmNodeExporterImage), + GlanceAPIImage: getImg(instance.Spec.CustomContainerImages.GlanceAPIImage, defaults.GlanceAPIImage), + HeatAPIImage: getImg(instance.Spec.CustomContainerImages.HeatAPIImage, defaults.HeatAPIImage), + HeatCfnapiImage: getImg(instance.Spec.CustomContainerImages.HeatCfnapiImage, defaults.HeatCfnapiImage), + HeatEngineImage: getImg(instance.Spec.CustomContainerImages.HeatEngineImage, defaults.HeatEngineImage), + HorizonImage: getImg(instance.Spec.CustomContainerImages.HorizonImage, defaults.HorizonImage), + InfraDnsmasqImage: getImg(instance.Spec.CustomContainerImages.InfraDnsmasqImage, defaults.InfraDnsmasqImage), + InfraMemcachedImage: getImg(instance.Spec.CustomContainerImages.InfraMemcachedImage, defaults.InfraMemcachedImage), + InfraRedisImage: getImg(instance.Spec.CustomContainerImages.InfraRedisImage, defaults.InfraRedisImage), + IronicAPIImage: getImg(instance.Spec.CustomContainerImages.IronicAPIImage, defaults.IronicAPIImage), + IronicConductorImage: getImg(instance.Spec.CustomContainerImages.IronicConductorImage, defaults.IronicConductorImage), + IronicInspectorImage: getImg(instance.Spec.CustomContainerImages.IronicInspectorImage, defaults.IronicInspectorImage), + IronicNeutronAgentImage: getImg(instance.Spec.CustomContainerImages.IronicNeutronAgentImage, defaults.IronicNeutronAgentImage), + IronicPxeImage: getImg(instance.Spec.CustomContainerImages.IronicPxeImage, defaults.IronicPxeImage), + IronicPythonAgentImage: getImg(instance.Spec.CustomContainerImages.IronicPythonAgentImage, defaults.IronicPythonAgentImage), + KeystoneAPIImage: getImg(instance.Spec.CustomContainerImages.KeystoneAPIImage, defaults.KeystoneAPIImage), + ManilaAPIImage: getImg(instance.Spec.CustomContainerImages.ManilaAPIImage, defaults.ManilaAPIImage), + ManilaSchedulerImage: getImg(instance.Spec.CustomContainerImages.ManilaSchedulerImage, defaults.ManilaSchedulerImage), + MariadbImage: getImg(instance.Spec.CustomContainerImages.MariadbImage, defaults.MariadbImage), + NeutronAPIImage: getImg(instance.Spec.CustomContainerImages.NeutronAPIImage, defaults.NeutronAPIImage), + NovaAPIImage: getImg(instance.Spec.CustomContainerImages.NovaAPIImage, defaults.NovaAPIImage), + NovaComputeImage: getImg(instance.Spec.CustomContainerImages.NovaComputeImage, defaults.NovaComputeImage), + NovaConductorImage: getImg(instance.Spec.CustomContainerImages.NovaConductorImage, defaults.NovaConductorImage), + NovaNovncImage: getImg(instance.Spec.CustomContainerImages.NovaNovncImage, defaults.NovaNovncImage), + NovaSchedulerImage: getImg(instance.Spec.CustomContainerImages.NovaSchedulerImage, defaults.NovaSchedulerImage), + OctaviaAPIImage: getImg(instance.Spec.CustomContainerImages.OctaviaAPIImage, defaults.OctaviaAPIImage), + OctaviaHealthmanagerImage: getImg(instance.Spec.CustomContainerImages.OctaviaHealthmanagerImage, defaults.OctaviaHealthmanagerImage), + OctaviaHousekeepingImage: getImg(instance.Spec.CustomContainerImages.OctaviaHousekeepingImage, defaults.OctaviaHousekeepingImage), + OctaviaWorkerImage: getImg(instance.Spec.CustomContainerImages.OctaviaWorkerImage, defaults.OctaviaWorkerImage), + OpenstackClientImage: getImg(instance.Spec.CustomContainerImages.OpenstackClientImage, defaults.OpenstackClientImage), + OsContainerImage: getImg(instance.Spec.CustomContainerImages.OsContainerImage, defaults.OsContainerImage), + OvnControllerImage: getImg(instance.Spec.CustomContainerImages.OvnControllerImage, defaults.OvnControllerImage), + OvnControllerOvsImage: getImg(instance.Spec.CustomContainerImages.OvnControllerOvsImage, defaults.OvnControllerOvsImage), + OvnNbDbclusterImage: getImg(instance.Spec.CustomContainerImages.OvnNbDbclusterImage, defaults.OvnNbDbclusterImage), + OvnNorthdImage: getImg(instance.Spec.CustomContainerImages.OvnNorthdImage, defaults.OvnNorthdImage), + OvnSbDbclusterImage: getImg(instance.Spec.CustomContainerImages.OvnSbDbclusterImage, defaults.OvnSbDbclusterImage), + PlacementAPIImage: getImg(instance.Spec.CustomContainerImages.PlacementAPIImage, defaults.PlacementAPIImage), + RabbitmqImage: getImg(instance.Spec.CustomContainerImages.RabbitmqImage, defaults.RabbitmqImage), + SwiftAccountImage: getImg(instance.Spec.CustomContainerImages.SwiftAccountImage, defaults.SwiftAccountImage), + SwiftContainerImage: getImg(instance.Spec.CustomContainerImages.SwiftContainerImage, defaults.SwiftContainerImage), + SwiftObjectImage: getImg(instance.Spec.CustomContainerImages.SwiftObjectImage, defaults.SwiftObjectImage), + SwiftProxyImage: getImg(instance.Spec.CustomContainerImages.SwiftProxyImage, defaults.SwiftProxyImage), + TelemetryNodeExporterImage: getImg(instance.Spec.CustomContainerImages.TelemetryNodeExporterImage, defaults.TelemetryNodeExporterImage), + }} + if containerImages.CinderVolumeImages == nil { + containerImages.CinderVolumeImages = make(map[string]*string) + } + if containerImages.ManilaShareImages == nil { + containerImages.ManilaShareImages = make(map[string]*string) + } + containerImages.CinderVolumeImages["default"] = defaults.CinderVolumeImage + containerImages.ManilaShareImages["default"] = defaults.ManilaShareImage + return containerImages +} + +// ReconcileVersion - reconciles OpenStackVersion CR +func ReconcileVersion(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (ctrl.Result, *corev1beta1.OpenStackVersion, error) { + version := &corev1beta1.OpenStackVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: instance.Name, + Namespace: instance.Namespace, + }, + } + + Log := GetLogger(ctx) + + // return if OpenStackVersion CR already exists + if err := helper.GetClient().Get(ctx, types.NamespacedName{ + Name: instance.Name, + Namespace: instance.Namespace, + }, + version); err == nil { + Log.Info(fmt.Sprintf("OpenStackVersion found. Name: %s", version.Name)) + } else { + Log.Info(fmt.Sprintf("OpenStackVersion does not exist. Creating: %s", version.Name)) + } + + op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), version, func() error { + err := controllerutil.SetControllerReference(helper.GetBeforeObject(), version, helper.GetScheme()) + if err != nil { + return err + } + return nil + }) + + if err != nil { + return ctrl.Result{}, nil, err + } + if op != controllerutil.OperationResultNone { + Log.Info(fmt.Sprintf("OpenStackVersion %s - %s", version.Name, op)) + } + + return ctrl.Result{}, version, nil +} diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go index d67654ee2..6cb3484c7 100644 --- a/tests/functional/base_test.go +++ b/tests/functional/base_test.go @@ -33,8 +33,11 @@ import ( type Names struct { Namespace string OpenStackControlplaneName types.NamespacedName + OpenStackVersionName types.NamespacedName KeystoneAPIName types.NamespacedName MemcachedName types.NamespacedName + CinderName types.NamespacedName + ManilaName types.NamespacedName DBName types.NamespacedName DBCertName types.NamespacedName DBCell1Name types.NamespacedName @@ -60,6 +63,10 @@ func CreateNames(openstackControlplaneName types.NamespacedName) Names { return Names{ Namespace: openstackControlplaneName.Namespace, OpenStackControlplaneName: openstackControlplaneName, + OpenStackVersionName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: openstackControlplaneName.Name, // same name as controlplane + }, RootCAPublicName: types.NamespacedName{ Namespace: openstackControlplaneName.Namespace, Name: "rootca-public"}, @@ -92,6 +99,14 @@ func CreateNames(openstackControlplaneName types.NamespacedName) Names { Namespace: openstackControlplaneName.Namespace, Name: "memcached", }, + CinderName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "cinder", + }, + ManilaName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "manila", + }, DBName: types.NamespacedName{ Namespace: openstackControlplaneName.Namespace, Name: "openstack", @@ -170,6 +185,37 @@ func OpenStackClientConditionGetter(name types.NamespacedName) condition.Conditi return instance.Status.Conditions } +func CreateOpenStackVersion(name types.NamespacedName, spec map[string]interface{}) client.Object { + + raw := map[string]interface{}{ + "apiVersion": "core.openstack.org/v1beta1", + "kind": "OpenStackVersion", + "metadata": map[string]interface{}{ + "name": name.Name, + "namespace": name.Namespace, + }, + "spec": spec, + } + return th.CreateUnstructured(raw) +} + +func GetDefaultOpenStackVersionSpec() map[string]interface{} { + return map[string]interface{}{} +} + +func GetOpenStackVersion(name types.NamespacedName) *corev1.OpenStackVersion { + instance := &corev1.OpenStackVersion{} + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, name, instance)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + return instance +} + +func OpenStackVersionConditionGetter(name types.NamespacedName) condition.Conditions { + instance := GetOpenStackVersion(name) + return instance.Status.Conditions +} + func CreateOpenStackControlPlane(name types.NamespacedName, spec map[string]interface{}) client.Object { raw := map[string]interface{}{ diff --git a/tests/functional/openstackoperator_controller_test.go b/tests/functional/openstackoperator_controller_test.go index c9e8ff934..22d19c453 100644 --- a/tests/functional/openstackoperator_controller_test.go +++ b/tests/functional/openstackoperator_controller_test.go @@ -29,8 +29,10 @@ import ( "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + cinderv1 "github.com/openstack-k8s-operators/cinder-operator/api/v1beta1" . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" "github.com/openstack-k8s-operators/lib-common/modules/common/tls" + manilav1 "github.com/openstack-k8s-operators/manila-operator/api/v1beta1" clientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" corev1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" ovnv1 "github.com/openstack-k8s-operators/ovn-operator/api/v1beta1" @@ -181,6 +183,19 @@ var _ = Describe("OpenStackOperator controller", func() { // make keystoneAPI ready and create secrets usually created by keystone-controller keystone.SimulateKeystoneAPIReady(names.KeystoneAPIName) + // openstackversion exists + Eventually(func(g Gomega) { + osversion := GetOpenStackVersion(names.OpenStackControlplaneName) + g.Expect(osversion).Should(Not(BeNil())) + + th.ExpectCondition( + names.OpenStackControlplaneName, + ConditionGetterFunc(OpenStackVersionConditionGetter), + corev1.OpenStackVersionInitialized, + k8s_corev1.ConditionTrue, + ) + }, timeout, interval).Should(Succeed()) + th.CreateSecret(types.NamespacedName{Name: "openstack-config-secret", Namespace: namespace}, map[string][]byte{"secure.yaml": []byte("foo")}) th.CreateConfigMap(types.NamespacedName{Name: "openstack-config", Namespace: namespace}, map[string]interface{}{"clouds.yaml": string("foo"), "OS_CLOUD": "default"}) @@ -222,6 +237,224 @@ var _ = Describe("OpenStackOperator controller", func() { }, timeout, interval).Should(Succeed()) }) }) + + When("A Manila OpenStackControlplane instance is created", func() { + BeforeEach(func() { + spec := GetDefaultOpenStackControlPlaneSpec() + spec["manila"] = map[string]interface{}{ + "enabled": true, + "template": map[string]interface{}{ + "manilaAPI": map[string]interface{}{ + "replicas": 1, + }, + "manilaScheduler": map[string]interface{}{ + "replicas": 1, + }, + "manilaShares": map[string]interface{}{ + "share1": map[string]interface{}{ + "replicas": 1, + }, + }, + }, + } + DeferCleanup( + th.DeleteInstance, + CreateOpenStackControlPlane(names.OpenStackControlplaneName, spec), + ) + }) + + It("should have Manila enabled", func() { + OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName) + Expect(OSCtlplane.Spec.Manila.Enabled).Should(BeTrue()) + + // manila exists + Eventually(func(g Gomega) { + manila := &manilav1.Manila{} + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, names.ManilaName, manila)).Should(Succeed()) + g.Expect(manila).ShouldNot(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + + // FIXME add helpers to manila-operator to simulate ready state + Eventually(func(g Gomega) { + manila := &manilav1.Manila{} + g.Expect(th.K8sClient.Get(th.Ctx, names.ManilaName, manila)).Should(Succeed()) + manila.Status.ObservedGeneration = manila.Generation + manila.Status.Conditions.MarkTrue(manilav1.ManilaAPIReadyCondition, "Ready") + manila.Status.Conditions.MarkTrue(manilav1.ManilaSchedulerReadyCondition, "Ready") + manila.Status.Conditions.MarkTrue(manilav1.ManilaShareReadyCondition, "Ready") + g.Expect(th.K8sClient.Status().Update(th.Ctx, manila)).To(Succeed()) + + th.Logger.Info("Simulated Manila ready", "on", names.ManilaName) + }, timeout, interval).Should(Succeed()) + + // expect the ready status to propagate to control plane object + Eventually(func(g Gomega) { + th.ExpectCondition( + names.OpenStackControlplaneName, + ConditionGetterFunc(OpenStackControlPlaneConditionGetter), + corev1.OpenStackControlPlaneManilaReadyCondition, + k8s_corev1.ConditionTrue, + ) + }, timeout, interval).Should(Succeed()) + }) + + It("should have Manila Shares configured", func() { + OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName) + Expect(OSCtlplane.Spec.Manila.Enabled).Should(BeTrue()) + + // manila exists + Eventually(func(g Gomega) { + manila := &manilav1.Manila{} + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, names.ManilaName, manila)).Should(Succeed()) + g.Expect(manila).ShouldNot(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + + // FIXME add helpers to manila-operator to simulate ready state + Eventually(func(g Gomega) { + manila := &manilav1.Manila{} + g.Expect(th.K8sClient.Get(th.Ctx, names.ManilaName, manila)).Should(Succeed()) + manila.Status.ObservedGeneration = manila.Generation + manila.Status.Conditions.MarkTrue(manilav1.ManilaAPIReadyCondition, "Ready") + manila.Status.Conditions.MarkTrue(manilav1.ManilaSchedulerReadyCondition, "Ready") + manila.Status.Conditions.MarkTrue(manilav1.ManilaShareReadyCondition, "Ready") + g.Expect(th.K8sClient.Status().Update(th.Ctx, manila)).To(Succeed()) + + g.Expect(manila.Spec.ManilaShares).Should(HaveLen(1)) + g.Expect(manila.Spec.ManilaShares["share1"]).ShouldNot(BeNil()) + replicas := int32(1) + g.Expect(manila.Spec.ManilaShares["share1"].Replicas).Should(Equal(&replicas)) + + th.Logger.Info("Simulated Manila ready", "on", names.ManilaName) + }, timeout, interval).Should(Succeed()) + + // expect the ready status to propagate to control plane object + Eventually(func(g Gomega) { + th.ExpectCondition( + names.OpenStackControlplaneName, + ConditionGetterFunc(OpenStackControlPlaneConditionGetter), + corev1.OpenStackControlPlaneManilaReadyCondition, + k8s_corev1.ConditionTrue, + ) + }, timeout, interval).Should(Succeed()) + }) + + }) + + When("A Cinder OpenStackControlplane instance is created", func() { + BeforeEach(func() { + spec := GetDefaultOpenStackControlPlaneSpec() + spec["cinder"] = map[string]interface{}{ + "enabled": true, + "template": map[string]interface{}{ + "cinderAPI": map[string]interface{}{ + "replicas": 1, + }, + "cinderBackup": map[string]interface{}{ + "replicas": 1, + }, + "cinderScheduler": map[string]interface{}{ + "replicas": 1, + }, + "cinderVolumes": map[string]interface{}{ + "volume1": map[string]interface{}{ + "replicas": 1, + }, + }, + }, + } + DeferCleanup( + th.DeleteInstance, + CreateOpenStackControlPlane(names.OpenStackControlplaneName, spec), + ) + }) + + It("should have Cinder enabled", func() { + OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName) + Expect(OSCtlplane.Spec.Cinder.Enabled).Should(BeTrue()) + + // cinder exists + Eventually(func(g Gomega) { + cinder := &cinderv1.Cinder{} + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, names.CinderName, cinder)).Should(Succeed()) + g.Expect(cinder).ShouldNot(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + + // FIXME add helpers to cinder-operator to simulate ready state + Eventually(func(g Gomega) { + cinder := &cinderv1.Cinder{} + g.Expect(th.K8sClient.Get(th.Ctx, names.CinderName, cinder)).Should(Succeed()) + cinder.Status.ObservedGeneration = cinder.Generation + cinder.Status.Conditions.MarkTrue(cinderv1.CinderAPIReadyCondition, "Ready") + cinder.Status.Conditions.MarkTrue(cinderv1.CinderBackupReadyCondition, "Ready") + cinder.Status.Conditions.MarkTrue(cinderv1.CinderSchedulerReadyCondition, "Ready") + cinder.Status.Conditions.MarkTrue(cinderv1.CinderVolumeReadyCondition, "Ready") + g.Expect(th.K8sClient.Status().Update(th.Ctx, cinder)).To(Succeed()) + + th.Logger.Info("Simulated Cinder ready", "on", names.CinderName) + }, timeout, interval).Should(Succeed()) + + // expect the ready status to propagate to control plane object + Eventually(func(g Gomega) { + th.ExpectCondition( + names.OpenStackControlplaneName, + ConditionGetterFunc(OpenStackControlPlaneConditionGetter), + corev1.OpenStackControlPlaneCinderReadyCondition, + k8s_corev1.ConditionTrue, + ) + }, timeout, interval).Should(Succeed()) + }) + + It("should have Cinder Volume configured", func() { + OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName) + Expect(OSCtlplane.Spec.Cinder.Enabled).Should(BeTrue()) + + // cinder exists + Eventually(func(g Gomega) { + cinder := &cinderv1.Cinder{} + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, names.CinderName, cinder)).Should(Succeed()) + g.Expect(cinder).ShouldNot(BeNil()) + }, timeout, interval).Should(Succeed()) + }) + + // FIXME add helpers to cinder-operator to simulate ready state + Eventually(func(g Gomega) { + cinder := &cinderv1.Cinder{} + g.Expect(th.K8sClient.Get(th.Ctx, names.CinderName, cinder)).Should(Succeed()) + cinder.Status.ObservedGeneration = cinder.Generation + cinder.Status.Conditions.MarkTrue(cinderv1.CinderAPIReadyCondition, "Ready") + cinder.Status.Conditions.MarkTrue(cinderv1.CinderBackupReadyCondition, "Ready") + cinder.Status.Conditions.MarkTrue(cinderv1.CinderSchedulerReadyCondition, "Ready") + cinder.Status.Conditions.MarkTrue(cinderv1.CinderVolumeReadyCondition, "Ready") + g.Expect(th.K8sClient.Status().Update(th.Ctx, cinder)).To(Succeed()) + + g.Expect(cinder.Spec.CinderVolumes).Should(HaveLen(1)) + g.Expect(cinder.Spec.CinderVolumes["volume1"]).ShouldNot(BeNil()) + replicas := int32(1) + g.Expect(cinder.Spec.CinderVolumes["volume1"].Replicas).Should(Equal(&replicas)) + + th.Logger.Info("Simulated Cinder ready", "on", names.CinderName) + }, timeout, interval).Should(Succeed()) + + // expect the ready status to propagate to control plane object + Eventually(func(g Gomega) { + th.ExpectCondition( + names.OpenStackControlplaneName, + ConditionGetterFunc(OpenStackControlPlaneConditionGetter), + corev1.OpenStackControlPlaneCinderReadyCondition, + k8s_corev1.ConditionTrue, + ) + }, timeout, interval).Should(Succeed()) + }) + + }) + When("A OVN OpenStackControlplane instance is created", func() { BeforeEach(func() { spec := GetDefaultOpenStackControlPlaneSpec() diff --git a/tests/functional/openstackversion_controller_test.go b/tests/functional/openstackversion_controller_test.go new file mode 100644 index 000000000..05201b118 --- /dev/null +++ b/tests/functional/openstackversion_controller_test.go @@ -0,0 +1,141 @@ +/* +Copyright 2024. + +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 functional_test + +import ( + "os" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + k8s_corev1 "k8s.io/api/core/v1" + + . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" + corev1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" +) + +var _ = Describe("OpenStackOperator controller", func() { + BeforeEach(func() { + // lib-common uses OPERATOR_TEMPLATES env var to locate the "templates" + // directory of the operator. We need to set them othervise lib-common + // will fail to generate the ConfigMap as it does not find common.sh + err := os.Setenv("OPERATOR_TEMPLATES", "../../templates") + Expect(err).NotTo(HaveOccurred()) + + }) + + When("A default OpenStackVersion instance is created", func() { + BeforeEach(func() { + DeferCleanup( + th.DeleteInstance, + CreateOpenStackVersion(names.OpenStackVersionName, GetDefaultOpenStackVersionSpec()), + ) + }) + It("should initialize container images", func() { + Eventually(func(g Gomega) { + + th.ExpectCondition( + names.OpenStackVersionName, + ConditionGetterFunc(OpenStackVersionConditionGetter), + corev1.OpenStackVersionInitialized, + k8s_corev1.ConditionTrue, + ) + + version := GetOpenStackVersion(names.OpenStackVersionName) + g.Expect(version).Should(Not(BeNil())) + + g.Expect(*version.Status.AvailableVersion).Should(Equal("0.0.1")) + g.Expect(version.Spec.TargetVersion).Should(Equal("0.0.1")) + + g.Expect(version.Status.ContainerImages.AgentImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.AnsibleeeImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.AodhAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.AodhEvaluatorImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.AodhListenerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.AodhNotifierImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.ApacheImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.BarbicanAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.BarbicanKeystoneListenerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.BarbicanWorkerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.CeilometerCentralImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.CeilometerComputeImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.CeilometerNotificationImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.CeilometerSgcoreImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.CinderAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.CinderBackupImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.CinderSchedulerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.DesignateAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.DesignateBackendbind9Image).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.DesignateCentralImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.DesignateMdnsImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.DesignateProducerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.DesignateUnboundImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.DesignateWorkerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.EdpmFrrImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.EdpmIscsidImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.EdpmLogrotateCrondImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.EdpmNeutronMetadataAgentImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.EdpmOvnBgpAgentImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.GlanceAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.HeatAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.HeatCfnapiImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.HeatEngineImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.InfraDnsmasqImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.InfraMemcachedImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.InfraRedisImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.IronicAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.IronicConductorImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.IronicInspectorImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.IronicNeutronAgentImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.IronicPxeImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.IronicPythonAgentImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.KeystoneAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.ManilaAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.ManilaSchedulerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.MariadbImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.NeutronAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.NovaAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.NovaComputeImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.NovaConductorImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.NovaNovncImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.NovaSchedulerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OctaviaAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OctaviaHealthmanagerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OctaviaHousekeepingImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OctaviaWorkerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OpenstackClientImage).ShouldNot(BeNil()) + //fixme wire this one in + //g.Expect(version.Status.ContainerImages.OsContainerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OvnControllerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OvnControllerOvsImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OvnNbDbclusterImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OvnNorthdImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.OvnSbDbclusterImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.PlacementAPIImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.RabbitmqImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.SwiftAccountImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.SwiftContainerImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.SwiftObjectImage).ShouldNot(BeNil()) + g.Expect(version.Status.ContainerImages.SwiftProxyImage).ShouldNot(BeNil()) + // same a RELATED_IMAGE_OPENSTACK_EDPM_NODE_EXPORTER_IMAGE + g.Expect(version.Status.ContainerImages.TelemetryNodeExporterImage).ShouldNot(BeNil()) + + }, timeout, interval).Should(Succeed()) + }) + + }) + +}) diff --git a/tests/functional/suite_test.go b/tests/functional/suite_test.go index 522637713..70ffdfb39 100644 --- a/tests/functional/suite_test.go +++ b/tests/functional/suite_test.go @@ -306,12 +306,16 @@ var _ = BeforeSuite(func() { err = (&openstackclientv1.OpenStackClient{}).SetupWebhookWithManager(k8sManager) Expect(err).NotTo(HaveOccurred()) + err = (&corev1.OpenStackVersion{}).SetupWebhookWithManager(k8sManager) + Expect(err).NotTo(HaveOccurred()) err = (&corev1.OpenStackControlPlane{}).SetupWebhookWithManager(k8sManager) Expect(err).NotTo(HaveOccurred()) + core_ctrl.SetupVersionDefaults() openstack.SetupServiceOperatorDefaults() openstackclientv1.SetupDefaults() corev1.SetupDefaults() + corev1.SetupVersionDefaults() err = (&client_ctrl.OpenStackClientReconciler{ Client: k8sManager.GetClient(), @@ -320,6 +324,13 @@ var _ = BeforeSuite(func() { }).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) + err = (&core_ctrl.OpenStackVersionReconciler{ + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + Kclient: kclient, + }).SetupWithManager(k8sManager) + Expect(err).ToNot(HaveOccurred()) + err = (&core_ctrl.OpenStackControlPlaneReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(),