diff --git a/api/bases/keystone.openstack.org_keystoneapis.yaml b/api/bases/keystone.openstack.org_keystoneapis.yaml index f460b115..b0f9436f 100644 --- a/api/bases/keystone.openstack.org_keystoneapis.yaml +++ b/api/bases/keystone.openstack.org_keystoneapis.yaml @@ -84,6 +84,10 @@ spec: files. Those get added to the service config dir in /etc/ . TODO: -> implement' type: object + enableFederation: + default: false + description: Enablement of Federation configuration + type: boolean enableSecureRBAC: default: true description: EnableSecureRBAC - Enable Consistent and Secure RBAC @@ -119,6 +123,76 @@ spec: description: NodeSelector to target subset of worker nodes running this service type: object + oidcFederation: + description: KeystoneFederationSpec to provide the configuration values + for OIDC Federation + properties: + keystoneFederationIdentityProviderName: + default: "" + description: KeystoneFederationIdentityProviderName + type: string + oidcCacheType: + default: memcache + description: OIDCCacheType + type: string + oidcClaimDelimiter: + default: ; + description: OIDCClaimDelimiter + type: string + oidcClaimPrefix: + default: OIDC- + description: OIDCClaimPrefix + type: string + oidcClientID: + default: "" + description: OIDCClientID + type: string + oidcIntrospectionEndpoint: + default: "" + description: OIDCIntrospectionEndpoint + type: string + oidcMemCacheServers: + description: OIDCMemCacheServers + type: string + oidcPassClaimsAs: + default: both + description: OIDCPassClaimsAs + type: string + oidcPassUserInfoAs: + default: claims + description: OIDCPassUserInfoAs + type: string + oidcProviderMetadataURL: + default: "" + description: OIDCProviderMetadataURL + type: string + oidcResponseType: + default: id_token + description: OIDCResponseType + type: string + oidcScope: + default: openid email profile + description: OIDCScope + type: string + remoteIDAttribute: + default: HTTP_OIDC_ISS + description: RemoteIDAttribute + type: string + required: + - keystoneFederationIdentityProviderName + - oidcCacheType + - oidcClaimDelimiter + - oidcClaimPrefix + - oidcClientID + - oidcIntrospectionEndpoint + - oidcMemCacheServers + - oidcPassClaimsAs + - oidcPassUserInfoAs + - oidcProviderMetadataURL + - oidcResponseType + - oidcScope + - remoteIDAttribute + type: object override: description: Override, provides the ability to override the generated manifest of several child resources. @@ -296,14 +370,27 @@ spec: passwordSelectors: default: admin: AdminPassword - description: PasswordSelectors - Selectors to identify the AdminUser - password from the Secret + keystoneOIDCClientSecret: KeystoneClientSecret + keystoneOIDCCryptoPassphrase: KeystoneCryptoPassphrase + description: PasswordSelectors - Selectors to identify the AdminUser, + KeystoneOIDCClient, and KeystoneOIDCCryptoPassphrase passwords from + the Secret properties: admin: default: AdminPassword description: Admin - Selector to get the keystone Admin password from the Secret type: string + keystoneOIDCClientSecret: + default: KeystoneClientSecret + description: OIDCClientSecret - Selector to get the IdP client + secret from the Secret + type: string + keystoneOIDCCryptoPassphrase: + default: KeystoneCryptoPassphrase + description: OIDCCryptoPassphrase - Selector to get the OIDC crypto + passphrase from the Secret + type: string type: object preserveJobs: default: false @@ -426,6 +513,7 @@ spec: required: - containerImage - databaseInstance + - enableFederation - memcachedInstance - rabbitMqClusterName - secret diff --git a/api/v1beta1/keystoneapi_types.go b/api/v1beta1/keystoneapi_types.go index a4c9b3cc..3653f85c 100644 --- a/api/v1beta1/keystoneapi_types.go +++ b/api/v1beta1/keystoneapi_types.go @@ -132,8 +132,8 @@ type KeystoneAPISpecCore struct { FernetMaxActiveKeys *int32 `json:"fernetMaxActiveKeys"` // +kubebuilder:validation:Optional - // +kubebuilder:default={admin: AdminPassword} - // PasswordSelectors - Selectors to identify the AdminUser password from the Secret + // +kubebuilder:default={admin: AdminPassword, keystoneOIDCClientSecret: KeystoneClientSecret, keystoneOIDCCryptoPassphrase: KeystoneCryptoPassphrase} + // PasswordSelectors - Selectors to identify the AdminUser, KeystoneOIDCClient, and KeystoneOIDCCryptoPassphrase passwords from the Secret PasswordSelectors PasswordSelector `json:"passwordSelectors"` // +kubebuilder:validation:Optional @@ -180,6 +180,15 @@ type KeystoneAPISpecCore struct { // +operator-sdk:csv:customresourcedefinitions:type=spec // TLS - Parameters related to the TLS TLS tls.API `json:"tls,omitempty"` + + // +kubebuilder:validation:Required + // +kubebuilder:default=false + // Enablement of Federation configuration + EnableFederation bool `json:"enableFederation"` + + // +kubebuilder:validation:Optional + // +OIDCFederation - parameters to configure keystone for OIDC federation + OIDCFederation KeystoneFederationSpec `json:"oidcFederation,omitempty"` } // APIOverrideSpec to override the generated manifest of several child resources. @@ -195,6 +204,83 @@ type PasswordSelector struct { // +kubebuilder:default="AdminPassword" // Admin - Selector to get the keystone Admin password from the Secret Admin string `json:"admin"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default="KeystoneClientSecret" + // OIDCClientSecret - Selector to get the IdP client secret from the Secret + KeystoneOIDCClientSecret string `json:"keystoneOIDCClientSecret"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default="KeystoneCryptoPassphrase" + // OIDCCryptoPassphrase - Selector to get the OIDC crypto passphrase from the Secret + KeystoneOIDCCryptoPassphrase string `json:"keystoneOIDCCryptoPassphrase"` +} + +// KeystoneFederationSpec to provide the configuration values for OIDC Federation +type KeystoneFederationSpec struct { + // +kubebuilder:validation:Required + // +kubebuilder:default="OIDC-" + // OIDCClaimPrefix + OIDCClaimPrefix string `json:"oidcClaimPrefix"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="id_token" + // OIDCResponseType + OIDCResponseType string `json:"oidcResponseType"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="openid email profile" + // OIDCScope + OIDCScope string `json:"oidcScope"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="" + // OIDCProviderMetadataURL + OIDCProviderMetadataURL string `json:"oidcProviderMetadataURL"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="" + // OIDCIntrospectionEndpoint + OIDCIntrospectionEndpoint string `json:"oidcIntrospectionEndpoint"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="" + // OIDCClientID + OIDCClientID string `json:"oidcClientID"` + + // +kubebuilder:validation:Required + // +kubebuilder:default=";" + // OIDCClaimDelimiter + OIDCClaimDelimiter string `json:"oidcClaimDelimiter"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="claims" + // OIDCPassUserInfoAs + OIDCPassUserInfoAs string `json:"oidcPassUserInfoAs"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="both" + // OIDCPassClaimsAs + OIDCPassClaimsAs string `json:"oidcPassClaimsAs"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="memcache" + // OIDCCacheType + OIDCCacheType string `json:"oidcCacheType"` + + // +kubebuilder:validaton:Required + // OIDCMemCacheServers + OIDCMemCacheServers string `json:"oidcMemCacheServers"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="HTTP_OIDC_ISS" + // RemoteIDAttribute + RemoteIDAttribute string `json:"remoteIDAttribute"` + + // +kubebuilder:validation:Required + // +kubebuilder:default="" + // KeystoneFederationIdentityProviderName + KeystoneFederationIdentityProviderName string `json:"keystoneFederationIdentityProviderName"` } // KeystoneAPIStatus defines the observed state of KeystoneAPI @@ -220,7 +306,7 @@ type KeystoneAPIStatus struct { // TransportURLSecret - Secret containing RabbitMQ transportURL TransportURLSecret string `json:"transportURLSecret,omitempty"` - //ObservedGeneration - the most recent generation observed for this service. If the observed generation is less than the spec generation, then the controller has not processed the latest changes. + // ObservedGeneration - the most recent generation observed for this service. If the observed generation is less than the spec generation, then the controller has not processed the latest changes. ObservedGeneration int64 `json:"observedGeneration,omitempty"` } diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 7ee47492..f242f1a8 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -180,6 +180,7 @@ func (in *KeystoneAPISpecCore) DeepCopyInto(out *KeystoneAPISpecCore) { } in.Override.DeepCopyInto(&out.Override) in.TLS.DeepCopyInto(&out.TLS) + out.OIDCFederation = in.OIDCFederation } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeystoneAPISpecCore. @@ -387,6 +388,21 @@ func (in *KeystoneEndpointStatus) DeepCopy() *KeystoneEndpointStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeystoneFederationSpec) DeepCopyInto(out *KeystoneFederationSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeystoneFederationSpec. +func (in *KeystoneFederationSpec) DeepCopy() *KeystoneFederationSpec { + if in == nil { + return nil + } + out := new(KeystoneFederationSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeystoneService) DeepCopyInto(out *KeystoneService) { *out = *in diff --git a/config/crd/bases/keystone.openstack.org_keystoneapis.yaml b/config/crd/bases/keystone.openstack.org_keystoneapis.yaml index f460b115..b0f9436f 100644 --- a/config/crd/bases/keystone.openstack.org_keystoneapis.yaml +++ b/config/crd/bases/keystone.openstack.org_keystoneapis.yaml @@ -84,6 +84,10 @@ spec: files. Those get added to the service config dir in /etc/ . TODO: -> implement' type: object + enableFederation: + default: false + description: Enablement of Federation configuration + type: boolean enableSecureRBAC: default: true description: EnableSecureRBAC - Enable Consistent and Secure RBAC @@ -119,6 +123,76 @@ spec: description: NodeSelector to target subset of worker nodes running this service type: object + oidcFederation: + description: KeystoneFederationSpec to provide the configuration values + for OIDC Federation + properties: + keystoneFederationIdentityProviderName: + default: "" + description: KeystoneFederationIdentityProviderName + type: string + oidcCacheType: + default: memcache + description: OIDCCacheType + type: string + oidcClaimDelimiter: + default: ; + description: OIDCClaimDelimiter + type: string + oidcClaimPrefix: + default: OIDC- + description: OIDCClaimPrefix + type: string + oidcClientID: + default: "" + description: OIDCClientID + type: string + oidcIntrospectionEndpoint: + default: "" + description: OIDCIntrospectionEndpoint + type: string + oidcMemCacheServers: + description: OIDCMemCacheServers + type: string + oidcPassClaimsAs: + default: both + description: OIDCPassClaimsAs + type: string + oidcPassUserInfoAs: + default: claims + description: OIDCPassUserInfoAs + type: string + oidcProviderMetadataURL: + default: "" + description: OIDCProviderMetadataURL + type: string + oidcResponseType: + default: id_token + description: OIDCResponseType + type: string + oidcScope: + default: openid email profile + description: OIDCScope + type: string + remoteIDAttribute: + default: HTTP_OIDC_ISS + description: RemoteIDAttribute + type: string + required: + - keystoneFederationIdentityProviderName + - oidcCacheType + - oidcClaimDelimiter + - oidcClaimPrefix + - oidcClientID + - oidcIntrospectionEndpoint + - oidcMemCacheServers + - oidcPassClaimsAs + - oidcPassUserInfoAs + - oidcProviderMetadataURL + - oidcResponseType + - oidcScope + - remoteIDAttribute + type: object override: description: Override, provides the ability to override the generated manifest of several child resources. @@ -296,14 +370,27 @@ spec: passwordSelectors: default: admin: AdminPassword - description: PasswordSelectors - Selectors to identify the AdminUser - password from the Secret + keystoneOIDCClientSecret: KeystoneClientSecret + keystoneOIDCCryptoPassphrase: KeystoneCryptoPassphrase + description: PasswordSelectors - Selectors to identify the AdminUser, + KeystoneOIDCClient, and KeystoneOIDCCryptoPassphrase passwords from + the Secret properties: admin: default: AdminPassword description: Admin - Selector to get the keystone Admin password from the Secret type: string + keystoneOIDCClientSecret: + default: KeystoneClientSecret + description: OIDCClientSecret - Selector to get the IdP client + secret from the Secret + type: string + keystoneOIDCCryptoPassphrase: + default: KeystoneCryptoPassphrase + description: OIDCCryptoPassphrase - Selector to get the OIDC crypto + passphrase from the Secret + type: string type: object preserveJobs: default: false @@ -426,6 +513,7 @@ spec: required: - containerImage - databaseInstance + - enableFederation - memcachedInstance - rabbitMqClusterName - secret diff --git a/controllers/keystoneapi_controller.go b/controllers/keystoneapi_controller.go index 1ce29856..2ad7c6a9 100644 --- a/controllers/keystoneapi_controller.go +++ b/controllers/keystoneapi_controller.go @@ -17,7 +17,9 @@ package controllers import ( "context" + "errors" "fmt" + "maps" "time" memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1" @@ -1190,6 +1192,16 @@ func (r *KeystoneAPIReconciler) generateServiceConfigMaps( keystone.DatabaseName, ), "enableSecureRBAC": instance.Spec.EnableSecureRBAC, + "enableFederation": instance.Spec.EnableFederation, + } + + if instance.Spec.EnableFederation { + federationParameters := map[string]interface{}{ + "federationTrustedDashboard": fmt.Sprintf("https://%s-%s.%s.svc/dashboard/auth/websso/", + instance.Name, service.EndpointPublic, instance.Namespace), + "federationRemoteIDAttribute": instance.Spec.OIDCFederation.RemoteIDAttribute, + } + maps.Copy(templateParameters, federationParameters) } // create httpd vhost template parameters @@ -1203,6 +1215,45 @@ func (r *KeystoneAPIReconciler) generateServiceConfigMaps( endptConfig["SSLCertificateFile"] = fmt.Sprintf("/etc/pki/tls/certs/%s.crt", endpt.String()) endptConfig["SSLCertificateKeyFile"] = fmt.Sprintf("/etc/pki/tls/private/%s.key", endpt.String()) } + + endptConfig["EnableFederation"] = false // default OIDCFederation to false, and set it below to true if enabled + if instance.Spec.EnableFederation { + ospSecret, _, err := oko_secret.GetSecret( + ctx, + h, + instance.Spec.Secret, + instance.Namespace) + if err != nil { + return err + } + + OIDCClientSecret := string(ospSecret.Data[instance.Spec.PasswordSelectors.KeystoneOIDCCryptoPassphrase]) + if OIDCClientSecret == "" { + return errors.New("OIDCClientSecret cannot be empty") + } + + OIDCCryptoPassphrase := string(ospSecret.Data[instance.Spec.PasswordSelectors.KeystoneOIDCCryptoPassphrase]) + if OIDCCryptoPassphrase == "" { + return errors.New("OIDCCryptoPassphrase cannot be empty") + } + + endptConfig["EnableFederation"] = true + endptConfig["OIDCClaimPrefix"] = instance.Spec.OIDCFederation.OIDCClaimPrefix + endptConfig["OIDCResponseType"] = instance.Spec.OIDCFederation.OIDCResponseType + endptConfig["OIDCScope"] = instance.Spec.OIDCFederation.OIDCScope + endptConfig["OIDCProviderMetadataURL"] = instance.Spec.OIDCFederation.OIDCProviderMetadataURL + endptConfig["OIDCIntrospectionEndpoint"] = instance.Spec.OIDCFederation.OIDCIntrospectionEndpoint + endptConfig["OIDCClientID"] = instance.Spec.OIDCFederation.OIDCClientID + endptConfig["OIDCClientSecret"] = OIDCClientSecret + endptConfig["OIDCCryptoPassphrase"] = OIDCCryptoPassphrase + endptConfig["OIDCPassUserInfoAs"] = instance.Spec.OIDCFederation.OIDCPassUserInfoAs + endptConfig["OIDCPassClaimsAs"] = instance.Spec.OIDCFederation.OIDCPassClaimsAs + endptConfig["OIDCClaimDelimiter"] = instance.Spec.OIDCFederation.OIDCClaimDelimiter + endptConfig["OIDCCacheType"] = instance.Spec.OIDCFederation.OIDCCacheType + endptConfig["OIDCMemCacheServers"] = mc.GetMemcachedServerListString() + endptConfig["KeystoneFederationIdentityProviderName"] = instance.Spec.OIDCFederation.KeystoneFederationIdentityProviderName + endptConfig["KeystoneEndpoint"], _ = instance.GetEndpoint(endpoint.EndpointPublic) + } httpdVhostConfig[endpt.String()] = endptConfig } templateParameters["VHosts"] = httpdVhostConfig @@ -1357,7 +1408,8 @@ func (r *KeystoneAPIReconciler) ensureFernetKeys( } annotations := map[string]string{ - fernetAnnotation: now.Format(time.RFC3339)} + fernetAnnotation: now.Format(time.RFC3339), + } tmpl := []util.Template{ { @@ -1502,7 +1554,6 @@ func (r *KeystoneAPIReconciler) ensureDB( h *helper.Helper, instance *keystonev1.KeystoneAPI, ) (*mariadbv1.Database, ctrl.Result, error) { - // ensure MariaDBAccount exists. This account record may be created by // openstack-operator or the cloud operator up front without a specific // MariaDBDatabase configured yet. Otherwise, a MariaDBAccount CR is @@ -1513,7 +1564,6 @@ func (r *KeystoneAPIReconciler) ensureDB( ctx, h, instance.Spec.DatabaseAccount, instance.Namespace, false, keystone.DatabaseUsernamePrefix, ) - if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( mariadbv1.MariaDBAccountReadyCondition, @@ -1541,7 +1591,6 @@ func (r *KeystoneAPIReconciler) ensureDB( // create or patch the DB ctrlResult, err := db.CreateOrPatchAll(ctx, h) - if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( condition.DBReadyCondition, diff --git a/templates/keystoneapi/config/httpd.conf b/templates/keystoneapi/config/httpd.conf index 2046181e..d5653d64 100644 --- a/templates/keystoneapi/config/httpd.conf +++ b/templates/keystoneapi/config/httpd.conf @@ -51,11 +51,56 @@ CustomLog /dev/stdout proxy env=forwarded SSLCertificateKeyFile "{{ $vhost.SSLCertificateKeyFile }}" {{- end }} - ## WSGI configuration + ## WSGI configuration WSGIApplicationGroup %{GLOBAL} WSGIDaemonProcess {{ $endpt }} display-name={{ $endpt }} group=keystone processes=3 threads=1 user=keystone WSGIProcessGroup {{ $endpt }} WSGIScriptAlias / "/usr/bin/keystone-wsgi-public" WSGIPassAuthorization On + + +{{- if $vhost.EnableFederation }} + # LoadModule auth_openidc_module modules/mod_auth_openidc.so + OIDCClaimPrefix "{{ $vhost.OIDCClaimPrefix }}" + OIDCResponseType "{{ $vhost.OIDCResponseType }}" + OIDCScope "{{ $vhost.OIDCScope }}" + OIDCProviderMetadataURL "{{ $vhost.OIDCProviderMetadataURL }}" + OIDCClientID "{{ $vhost.OIDCClientID }}" + OIDCClientSecret "{{ $vhost.OIDCClientSecret }}" + OIDCCryptoPassphrase "{{ $vhost.OIDCCryptoPassphrase }}" + OIDCClaimDelimiter "{{ $vhost.OIDCClaimDelimiter }}" + OIDCPassUserInfoAs "{{ $vhost.OIDCPassUserInfoAs }}" + OIDCPassClaimsAs "{{ $vhost.OIDCPassClaimsAs }}" + + OIDCCacheType "{{ $vhost.OIDCCacheType }}" + OIDCMemCacheServers "{{ $vhost.OIDCMemCacheServers }}" + + + # The following directives are necessary to support websso from Horizon + # (Per https://docs.openstack.org/keystone/pike/advanced-topics/federation/websso.html) + OIDCRedirectURI "{{ $vhost.KeystoneEndpoint }}/v3/auth/OS-FEDERATION/identity_providers/{{ $vhost.KeystoneFederationIdentityProviderName }}/protocols/openid/websso" + OIDCRedirectURI "{{ $vhost.KeystoneEndpoint }}/v3/auth/OS-FEDERATION/websso/openid" + + + AuthType "openid-connect" + Require valid-user + + + + AuthType "openid-connect" + Require valid-user + + + OIDCOAuthClientID "{{ $vhost.OIDCClientID }}" + OIDCOAuthClientSecret "{{ $vhost.OIDCClientSecret }}" + OIDCOAuthIntrospectionEndpoint "{{ $vhost.OIDCIntrospectionEndpoint }}" + + + AuthType oauth20 + Require valid-user + + +{{- end }} + {{ end }} diff --git a/templates/keystoneapi/config/keystone.conf b/templates/keystoneapi/config/keystone.conf index 6717aa26..270ffe6c 100644 --- a/templates/keystoneapi/config/keystone.conf +++ b/templates/keystoneapi/config/keystone.conf @@ -11,6 +11,17 @@ enabled=true memcache_servers={{ .memcachedServers }} tls_enabled={{ .memcachedTLS }} +{{if .enableFederation }} +[federation] +trusted_dashboard={{ .federationTrustedDashboard }} + +[openid] +remote_id_attribute={{ .federationRemoteIDAttribute }} + +[auth] +methods = password,token,oauth1,mapped,application_credential,openid +{{ end }} + [database] max_retries=-1 db_max_retries=-1 diff --git a/tests/functional/keystoneapi_controller_test.go b/tests/functional/keystoneapi_controller_test.go index 905b0341..26d89c41 100644 --- a/tests/functional/keystoneapi_controller_test.go +++ b/tests/functional/keystoneapi_controller_test.go @@ -39,7 +39,6 @@ import ( ) var _ = Describe("Keystone controller", func() { - var keystoneAPIName types.NamespacedName var keystoneAccountName types.NamespacedName var keystoneDatabaseName types.NamespacedName @@ -53,7 +52,6 @@ var _ = Describe("Keystone controller", func() { var memcachedSpec memcachedv1.MemcachedSpec BeforeEach(func() { - keystoneAPIName = types.NamespacedName{ Name: "keystone", Namespace: namespace, @@ -415,7 +413,6 @@ var _ = Describe("Keystone controller", func() { Namespace: namespace, }) }) - }) When("DB sync is completed", func() { @@ -958,7 +955,6 @@ var _ = Describe("Keystone controller", func() { configData = string(scrt.Data["my.cnf"]) Expect(configData).To( ContainSubstring("[client]\nssl-ca=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem\nssl=1")) - }) It("it creates deployment with CA and service certs mounted", func() { @@ -1185,7 +1181,6 @@ var _ = Describe("Keystone controller", func() { } } }, timeout, interval).Should(Succeed()) - }) }) @@ -1208,7 +1203,6 @@ var _ = Describe("Keystone controller", func() { // needs to make it all the way to the end where the mariadb finalizers // are removed from unused accounts since that's part of what we are testing SetupCR: func(accountName types.NamespacedName) { - spec := GetDefaultKeystoneAPISpec() spec["databaseAccount"] = accountName.Name @@ -1251,17 +1245,14 @@ var _ = Describe("Keystone controller", func() { condition.DeploymentReadyCondition, corev1.ConditionTrue, ) - }, // Change the account name in the service to a new name UpdateAccount: func(newAccountName types.NamespacedName) { - Eventually(func(g Gomega) { keystoneapi := GetKeystoneAPI(keystoneAPIName) keystoneapi.Spec.DatabaseAccount = newAccountName.Name g.Expect(th.K8sClient.Update(ctx, keystoneapi)).Should(Succeed()) }, timeout, interval).Should(Succeed()) - }, // delete the keystone instance to exercise finalizer removal DeleteCR: func() { @@ -1280,12 +1271,10 @@ var _ = Describe("Keystone controller", func() { ContainSubstring(fmt.Sprintf("connection=mysql+pymysql://%s:%s@hostname-for-openstack.%s.svc/keystone?read_default_file=/etc/my.cnf", username, password, namespace))) }, timeout, interval).Should(Succeed()) - }) mariadbSuite.RunConfigHashSuite(func() string { deployment := th.GetDeployment(deploymentName) return GetEnvVarValue(deployment.Spec.Template.Spec.Containers[0].Env, "CONFIG_HASH", "") }) - })