diff --git a/apis/bases/client.openstack.org_openstackclients.yaml b/apis/bases/client.openstack.org_openstackclients.yaml index fb0d6a218..80ec744a8 100644 --- a/apis/bases/client.openstack.org_openstackclients.yaml +++ b/apis/bases/client.openstack.org_openstackclients.yaml @@ -36,7 +36,7 @@ spec: type: object spec: properties: - caSecretName: + caBundleSecretName: type: string containerImage: type: string diff --git a/apis/bases/core.openstack.org_openstackcontrolplanes.yaml b/apis/bases/core.openstack.org_openstackcontrolplanes.yaml index 34c0a28ae..fe458f92b 100644 --- a/apis/bases/core.openstack.org_openstackcontrolplanes.yaml +++ b/apis/bases/core.openstack.org_openstackcontrolplanes.yaml @@ -6479,6 +6479,33 @@ spec: type: object secret: type: string + tls: + properties: + api: + properties: + disabled: + type: boolean + endpoint: + additionalProperties: + properties: + secretName: + type: string + type: object + type: object + type: object + caBundleSecretName: + type: string + db: + properties: + disabled: + type: boolean + type: object + messaging: + properties: + disabled: + type: boolean + type: object + type: object trustFlushArgs: default: "" type: string @@ -10339,7 +10366,7 @@ spec: properties: template: properties: - caSecretName: + caBundleSecretName: type: string containerImage: type: string @@ -15186,7 +15213,7 @@ spec: public: enabled: true properties: - caSecretName: + caBundleSecretName: type: string endpoint: additionalProperties: diff --git a/apis/go.mod b/apis/go.mod index d7546308d..4de8f310d 100644 --- a/apis/go.mod +++ b/apis/go.mod @@ -113,3 +113,5 @@ replace github.com/openshift/api => github.com/openshift/api v0.0.0-202304141430 // Bump golang.org/x/net to avoid Rapid Reset CVE replace golang.org/x/net => golang.org/x/net v0.18.0 //allow-merging + +replace github.com/openstack-k8s-operators/lib-common/modules/common => github.com/Deydra71/lib-common/modules/common v0.0.0-20231204140814-3719cbd23dc5 diff --git a/apis/go.sum b/apis/go.sum index 48e6d8103..819c4fe33 100644 --- a/apis/go.sum +++ b/apis/go.sum @@ -1,6 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Deydra71/lib-common/modules/common v0.0.0-20231204140814-3719cbd23dc5 h1:5+xXZONbkUa2QBbqtyvABRuUazwRs9e5UgJgK3vQ6Oc= +github.com/Deydra71/lib-common/modules/common v0.0.0-20231204140814-3719cbd23dc5/go.mod h1:ImxqioQ1ID+d7fMMD4lK8CxJqNTB5tsQ+lGKcN/xx5M= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -148,8 +150,6 @@ github.com/openstack-k8s-operators/ironic-operator/api v0.3.1-0.20231127105109-2 github.com/openstack-k8s-operators/ironic-operator/api v0.3.1-0.20231127105109-2a854ad66b54/go.mod h1:H6BuZ52u+Dq/vWJgpGIJLttRTnPPH3xdVeqhI99QE/k= github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231128185906-0b4579c3dadf h1:Omn04tJTZlNOXIszGurB8XfpbsGf+6LIn86BaN9XRDs= github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231128185906-0b4579c3dadf/go.mod h1:kDtQ2LCkf28F7xgK8GBFAMPDhXnL6iRb8NztHhrYaO0= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231128145648-956f4d361a63 h1:iA/8vt+o2bMxYvvenNB7VArBvM8UyDLw3G7S/teMLc0= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231128145648-956f4d361a63/go.mod h1:OYad2L+OD4j5CR49di7gu3Q1UkLBmpYwvtdoGlnasL4= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20231128145648-956f4d361a63 h1:Bl+kXtdCux8H/iXixa+g/fdtPKCJc7oCyPsfZo70thE= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20231128145648-956f4d361a63/go.mod h1:IUYIDD1uazTWDPYTmAojTBFQDZ7lATPWTfynx2QlPjU= github.com/openstack-k8s-operators/lib-common/modules/storage v0.3.1-0.20231128145648-956f4d361a63 h1:ok420+r0QGypb4ORk2Zi4k9i0pgXjMZHQ1w/6zgxyrE= diff --git a/config/crd/bases/client.openstack.org_openstackclients.yaml b/config/crd/bases/client.openstack.org_openstackclients.yaml index fb0d6a218..80ec744a8 100644 --- a/config/crd/bases/client.openstack.org_openstackclients.yaml +++ b/config/crd/bases/client.openstack.org_openstackclients.yaml @@ -36,7 +36,7 @@ spec: type: object spec: properties: - caSecretName: + caBundleSecretName: type: string containerImage: type: string diff --git a/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml b/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml index 34c0a28ae..fe458f92b 100644 --- a/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml +++ b/config/crd/bases/core.openstack.org_openstackcontrolplanes.yaml @@ -6479,6 +6479,33 @@ spec: type: object secret: type: string + tls: + properties: + api: + properties: + disabled: + type: boolean + endpoint: + additionalProperties: + properties: + secretName: + type: string + type: object + type: object + type: object + caBundleSecretName: + type: string + db: + properties: + disabled: + type: boolean + type: object + messaging: + properties: + disabled: + type: boolean + type: object + type: object trustFlushArgs: default: "" type: string @@ -10339,7 +10366,7 @@ spec: properties: template: properties: - caSecretName: + caBundleSecretName: type: string containerImage: type: string @@ -15186,7 +15213,7 @@ spec: public: enabled: true properties: - caSecretName: + caBundleSecretName: type: string endpoint: additionalProperties: diff --git a/controllers/client/openstackclient_controller.go b/controllers/client/openstackclient_controller.go index 8ed0ce32e..a7552b243 100644 --- a/controllers/client/openstackclient_controller.go +++ b/controllers/client/openstackclient_controller.go @@ -26,14 +26,21 @@ import ( rbacv1 "k8s.io/api/rbac/v1" k8s_errors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" "github.com/openstack-k8s-operators/lib-common/modules/common" @@ -42,6 +49,7 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/env" helper "github.com/openstack-k8s-operators/lib-common/modules/common/helper" common_rbac "github.com/openstack-k8s-operators/lib-common/modules/common/rbac" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" "github.com/openstack-k8s-operators/lib-common/modules/common/secret" "github.com/openstack-k8s-operators/lib-common/modules/common/util" @@ -232,8 +240,15 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ } configVars[*instance.Spec.OpenStackConfigSecret] = env.SetValue(secretHash) - if instance.Spec.CaSecretName != "" { - _, secretHash, err := secret.GetSecret(ctx, helper, instance.Spec.CaSecretName, instance.Namespace) + if instance.Spec.CaBundleSecretName != "" { + secretHash, ctrlResult, err := tls.ValidateCACertSecret( + ctx, + helper.GetClient(), + types.NamespacedName{ + Name: instance.Spec.CaBundleSecretName, + Namespace: instance.Namespace, + }, + ) if err != nil { if k8s_errors.IsNotFound(err) { instance.Status.Conditions.Set(condition.FalseCondition( @@ -250,8 +265,16 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ clientv1.OpenStackClientReadyErrorMessage, err.Error())) return ctrl.Result{}, err + } else if (ctrlResult != ctrl.Result{}) { + instance.Status.Conditions.Set(condition.FalseCondition( + clientv1.OpenStackClientReadyCondition, + condition.RequestedReason, + condition.SeverityInfo, + clientv1.OpenStackClientSecretWaitingMessage)) + return ctrlResult, nil } - configVars[instance.Spec.CaSecretName] = env.SetValue(secretHash) + + configVars[instance.Spec.CaBundleSecretName] = env.SetValue(secretHash) } configVarsHash, err := util.HashOfInputHashes(configVars) @@ -269,12 +292,7 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ op, err := controllerutil.CreateOrPatch(ctx, r.Client, osclient, func() error { isPodUpdate := !osclient.ObjectMeta.CreationTimestamp.IsZero() if !isPodUpdate { - spec, err := openstackclient.ClientPodSpec(ctx, instance, helper, clientLabels, configVarsHash) - if err != nil { - return err - } - - osclient.Spec = *spec + osclient.Spec = openstackclient.ClientPodSpec(ctx, instance, helper, clientLabels, configVarsHash) } else { hashupdate := false @@ -367,14 +385,113 @@ func (r *OpenStackClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ } +// fields to index to reconcile when change +const ( + caBundleSecretNameField = ".spec.caBundleSecretName" + openStackConfigMapField = ".spec.openStackConfigMap" + openStackConfigSecretField = ".spec.openStackConfigSecret" +) + +var ( + allWatchFields = []string{ + caBundleSecretNameField, + openStackConfigMapField, + openStackConfigSecretField, + } +) + // SetupWithManager sets up the controller with the Manager. func (r *OpenStackClientReconciler) SetupWithManager(mgr ctrl.Manager) error { + // index caBundleSecretNameField + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &clientv1.OpenStackClient{}, caBundleSecretNameField, func(rawObj client.Object) []string { + // Extract the secret name from the spec, if one is provided + cr := rawObj.(*clientv1.OpenStackClient) + if cr.Spec.CaBundleSecretName == "" { + return nil + } + return []string{cr.Spec.CaBundleSecretName} + }); err != nil { + return err + } + // index openStackConfigMap + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &clientv1.OpenStackClient{}, openStackConfigMapField, func(rawObj client.Object) []string { + // Extract the configmap name from the spec, if one is provided + cr := rawObj.(*clientv1.OpenStackClient) + if cr.Spec.OpenStackConfigMap == nil { + return nil + } + if *cr.Spec.OpenStackConfigMap == "" { + return nil + } + return []string{*cr.Spec.OpenStackConfigMap} + }); err != nil { + return err + } + // index openStackConfigSecret + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &clientv1.OpenStackClient{}, openStackConfigSecretField, func(rawObj client.Object) []string { + // Extract the configmap name from the spec, if one is provided + cr := rawObj.(*clientv1.OpenStackClient) + if cr.Spec.OpenStackConfigSecret == nil { + return nil + } + if *cr.Spec.OpenStackConfigSecret == "" { + return nil + } + return []string{*cr.Spec.OpenStackConfigSecret} + }); err != nil { + return err + } + return ctrl.NewControllerManagedBy(mgr). For(&clientv1.OpenStackClient{}). Owns(&corev1.Pod{}). Owns(&corev1.ServiceAccount{}). Owns(&rbacv1.Role{}). Owns(&rbacv1.RoleBinding{}). + Watches( + &source.Kind{Type: &corev1.Secret{}}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). + Watches( + &source.Kind{Type: &corev1.ConfigMap{}}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). + Watches( + &source.Kind{Type: &corev1.Secret{}}, + handler.EnqueueRequestsFromMapFunc(r.findObjectsForSrc), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Complete(r) } + +func (r *OpenStackClientReconciler) findObjectsForSrc(src client.Object) []reconcile.Request { + requests := []reconcile.Request{} + + for _, field := range allWatchFields { + crList := &clientv1.OpenStackClientList{} + listOps := &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(field, src.GetName()), + Namespace: src.GetNamespace(), + } + err := r.List(context.TODO(), crList, listOps) + if err != nil { + return []reconcile.Request{} + } + + for _, item := range crList.Items { + requests = append(requests, + reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: item.GetName(), + Namespace: item.GetNamespace(), + }, + }, + ) + } + } + + return requests +} diff --git a/go.mod b/go.mod index 9972735db..73819a67d 100644 --- a/go.mod +++ b/go.mod @@ -131,3 +131,7 @@ 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 + +replace github.com/openstack-k8s-operators/lib-common/modules/common => github.com/Deydra71/lib-common/modules/common v0.0.0-20231204140814-3719cbd23dc5 + +replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/stuggi/keystone-operator/api v0.0.0-20231204163425-bd3998fc2d35 diff --git a/go.sum b/go.sum index 0f19faf44..1d6190333 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Deydra71/lib-common/modules/common v0.0.0-20231204140814-3719cbd23dc5 h1:5+xXZONbkUa2QBbqtyvABRuUazwRs9e5UgJgK3vQ6Oc= +github.com/Deydra71/lib-common/modules/common v0.0.0-20231204140814-3719cbd23dc5/go.mod h1:ImxqioQ1ID+d7fMMD4lK8CxJqNTB5tsQ+lGKcN/xx5M= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -159,12 +161,8 @@ github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20231122104142-3 github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20231122104142-3b449040167e/go.mod h1:FnKU6sravC43Uj0iq2bhZaPMjoPCBhkNlVdiVoGi5/E= github.com/openstack-k8s-operators/ironic-operator/api v0.3.1-0.20231127105109-2a854ad66b54 h1:feWz7K3XIqZOZenySzfei4rsCrdgpS30kInXokX06YA= github.com/openstack-k8s-operators/ironic-operator/api v0.3.1-0.20231127105109-2a854ad66b54/go.mod h1:H6BuZ52u+Dq/vWJgpGIJLttRTnPPH3xdVeqhI99QE/k= -github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231128185906-0b4579c3dadf h1:Omn04tJTZlNOXIszGurB8XfpbsGf+6LIn86BaN9XRDs= -github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231128185906-0b4579c3dadf/go.mod h1:kDtQ2LCkf28F7xgK8GBFAMPDhXnL6iRb8NztHhrYaO0= github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231128145648-956f4d361a63 h1:kVxfqAz0Il4mEGjU71k+NwS6773u7e9LzoVBAZJNFOM= github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231128145648-956f4d361a63/go.mod h1:+eEAq2Bfodi9xvh3S1OkEo4lJeTVGmhU/N7t5Hhpd6s= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231128145648-956f4d361a63 h1:iA/8vt+o2bMxYvvenNB7VArBvM8UyDLw3G7S/teMLc0= -github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231128145648-956f4d361a63/go.mod h1:OYad2L+OD4j5CR49di7gu3Q1UkLBmpYwvtdoGlnasL4= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20231128145648-956f4d361a63 h1:Bl+kXtdCux8H/iXixa+g/fdtPKCJc7oCyPsfZo70thE= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20231128145648-956f4d361a63/go.mod h1:IUYIDD1uazTWDPYTmAojTBFQDZ7lATPWTfynx2QlPjU= github.com/openstack-k8s-operators/lib-common/modules/storage v0.3.1-0.20231128145648-956f4d361a63 h1:ok420+r0QGypb4ORk2Zi4k9i0pgXjMZHQ1w/6zgxyrE= @@ -230,6 +228,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stuggi/keystone-operator/api v0.0.0-20231204163425-bd3998fc2d35 h1:L/DSGuZjo+FEt5HZ7KKJDhx1i/WLmMzFjUEwcO28pDs= +github.com/stuggi/keystone-operator/api v0.0.0-20231204163425-bd3998fc2d35/go.mod h1:vB6RW0rrO34maXX4pdbowQVxH7vEi1MLlmwelZxR33M= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/pkg/openstack/ca.go b/pkg/openstack/ca.go index 28729ff94..4f2cf6021 100644 --- a/pkg/openstack/ca.go +++ b/pkg/openstack/ca.go @@ -135,8 +135,8 @@ func ReconcileCAs(ctx context.Context, instance *corev1.OpenStackControlPlane, h instance.Status.Conditions.MarkTrue(corev1.OpenStackControlPlaneCAReadyCondition, corev1.OpenStackControlPlaneCAReadyMessage) // create/update combined CA secret - if instance.Spec.TLS.CaSecretName != "" { - caSecret, _, err := secret.GetSecret(ctx, helper, instance.Spec.TLS.CaSecretName, instance.Namespace) + if instance.Spec.TLS.CaBundleSecretName != "" { + caSecret, _, err := secret.GetSecret(ctx, helper, instance.Spec.TLS.CaBundleSecretName, instance.Namespace) if err != nil { instance.Status.Conditions.Set(condition.FalseCondition( corev1.OpenStackControlPlaneCAReadyCondition, @@ -144,7 +144,7 @@ func ReconcileCAs(ctx context.Context, instance *corev1.OpenStackControlPlane, h condition.SeverityWarning, corev1.OpenStackControlPlaneCAReadyErrorMessage, "secret", - instance.Spec.TLS.CaSecretName, + instance.Spec.TLS.CaBundleSecretName, err.Error())) return ctrlResult, err diff --git a/pkg/openstack/openstackclient.go b/pkg/openstack/openstackclient.go index a1b3ebb3b..c2cfe361a 100644 --- a/pkg/openstack/openstackclient.go +++ b/pkg/openstack/openstackclient.go @@ -48,7 +48,7 @@ func ReconcileOpenStackClient(ctx context.Context, instance *corev1.OpenStackCon for _, config := range instance.Spec.TLS.Endpoint { if config.Enabled { - openstackclient.Spec.Ca.CaSecretName = CombinedCASecret + openstackclient.Spec.Ca.CaBundleSecretName = CombinedCASecret break } } diff --git a/pkg/openstackclient/funcs.go b/pkg/openstackclient/funcs.go index 35abf7714..6d019b87d 100644 --- a/pkg/openstackclient/funcs.go +++ b/pkg/openstackclient/funcs.go @@ -17,7 +17,6 @@ import ( env "github.com/openstack-k8s-operators/lib-common/modules/common/env" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" - "github.com/openstack-k8s-operators/lib-common/modules/common/tls" clientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" corev1 "k8s.io/api/core/v1" @@ -31,54 +30,57 @@ func ClientPodSpec( helper *helper.Helper, labels map[string]string, configHash string, -) (*corev1.PodSpec, error) { +) corev1.PodSpec { envVars := map[string]env.Setter{} envVars["OS_CLOUD"] = env.SetValue("default") envVars["CONFIG_HASH"] = env.SetValue(configHash) - podSpec := &corev1.PodSpec{} + // create Volume and VolumeMounts + volumes := clientPodVolumes(instance) + volumeMounts := clientPodVolumeMounts() - podSpec.TerminationGracePeriodSeconds = ptr.To[int64](0) - podSpec.ServiceAccountName = instance.RbacResourceName() - clientContainer := corev1.Container{ - Name: "openstackclient", - Image: instance.Spec.ContainerImage, - Command: []string{"/bin/sleep"}, - Args: []string{"infinity"}, - SecurityContext: &corev1.SecurityContext{ - RunAsUser: ptr.To[int64](42401), - RunAsGroup: ptr.To[int64](42401), - RunAsNonRoot: ptr.To(true), - AllowPrivilegeEscalation: ptr.To(false), - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - "ALL", + // add CA cert if defined + if instance.Spec.CaBundleSecretName != "" { + volumes = append(volumes, instance.Spec.CreateVolume()) + volumeMounts = append(volumeMounts, instance.Spec.CreateVolumeMounts(nil)...) + } + + podSpec := corev1.PodSpec{ + TerminationGracePeriodSeconds: ptr.To[int64](0), + ServiceAccountName: instance.RbacResourceName(), + Volumes: volumes, + Containers: []corev1.Container{ + { + Name: "openstackclient", + Image: instance.Spec.ContainerImage, + Command: []string{"/bin/sleep"}, + Args: []string{"infinity"}, + SecurityContext: &corev1.SecurityContext{ + RunAsUser: ptr.To[int64](42401), + RunAsGroup: ptr.To[int64](42401), + RunAsNonRoot: ptr.To(true), + AllowPrivilegeEscalation: ptr.To(false), + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + "ALL", + }, + }, }, + Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), + VolumeMounts: volumeMounts, }, }, - Env: env.MergeEnvs([]corev1.EnvVar{}, envVars), - } - - tlsConfig, err := tls.NewTLS(ctx, helper, instance.Namespace, nil, &instance.Spec.Ca) - if err != nil { - return nil, err } - clientContainer.VolumeMounts = clientPodVolumeMounts(tlsConfig) - podSpec.Containers = []corev1.Container{clientContainer} - - podSpec.Volumes = clientPodVolumes(instance, tlsConfig) if instance.Spec.NodeSelector != nil && len(instance.Spec.NodeSelector) > 0 { podSpec.NodeSelector = instance.Spec.NodeSelector } - return podSpec, nil + return podSpec } -func clientPodVolumeMounts( - tlsConfig *tls.TLS, -) []corev1.VolumeMount { - volumeMounts := []corev1.VolumeMount{ +func clientPodVolumeMounts() []corev1.VolumeMount { + return []corev1.VolumeMount{ { Name: "openstack-config", MountPath: "/home/cloud-admin/.config/openstack/clouds.yaml", @@ -90,16 +92,13 @@ func clientPodVolumeMounts( SubPath: "secure.yaml", }, } - volumeMounts = append(volumeMounts, tlsConfig.CreateVolumeMounts()...) - - return volumeMounts } func clientPodVolumes( instance *clientv1.OpenStackClient, - tlsConfig *tls.TLS, ) []corev1.Volume { - volumes := []corev1.Volume{ + return []corev1.Volume{ + { Name: "openstack-config", VolumeSource: corev1.VolumeSource{ @@ -119,7 +118,4 @@ func clientPodVolumes( }, }, } - volumes = append(volumes, tlsConfig.CreateVolumes()...) - - return volumes } diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go index cc37adafc..3f380e2f6 100644 --- a/tests/functional/base_test.go +++ b/tests/functional/base_test.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/openstack-k8s-operators/lib-common/modules/common/condition" openstackclientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" corev1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" ) @@ -42,6 +43,7 @@ type Names struct { RootCAInternalName types.NamespacedName SelfSignedIssuerName types.NamespacedName CABundleName types.NamespacedName + OpenStackClientName types.NamespacedName } func CreateNames(openstackControlplaneName types.NamespacedName) Names { @@ -93,6 +95,10 @@ func CreateNames(openstackControlplaneName types.NamespacedName) Names { Namespace: openstackControlplaneName.Namespace, Name: "rabbitmq-cell1", }, + OpenStackClientName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "openstackclient", + }, } } @@ -122,6 +128,11 @@ func GetOpenStackClient(name types.NamespacedName) *openstackclientv1.OpenStackC return instance } +func OpenStackClientConditionGetter(name types.NamespacedName) condition.Conditions { + instance := GetOpenStackClient(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 c5201dda7..f2ae37c94 100644 --- a/tests/functional/openstackoperator_controller_test.go +++ b/tests/functional/openstackoperator_controller_test.go @@ -21,8 +21,13 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/openstack-k8s-operators/lib-common/modules/common/service" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" + + "github.com/openstack-k8s-operators/lib-common/modules/common/service" + . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" + clientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" ) var _ = Describe("OpenStackOperator controller", func() { @@ -127,5 +132,48 @@ var _ = Describe("OpenStackOperator controller", func() { g.Expect(caBundle.Data).Should(HaveLen(int(1))) }, timeout, interval).Should(Succeed()) }) + + It("should create an openstackclient", func() { + // keystone exists + Eventually(func(g Gomega) { + keystoneAPI := keystone.GetKeystoneAPI(names.KeystoneAPIName) + g.Expect(keystoneAPI).Should(Not(BeNil())) + }, timeout, interval).Should(Succeed()) + // make keystoneAPI ready and create secrets usually created by keystone-controller + keystone.SimulateKeystoneAPIReady(names.KeystoneAPIName) + 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"}) + + // openstackclient exists + Eventually(func(g Gomega) { + osclient := GetOpenStackClient(names.OpenStackClientName) + g.Expect(osclient).Should(Not(BeNil())) + + th.ExpectCondition( + names.OpenStackClientName, + ConditionGetterFunc(OpenStackClientConditionGetter), + clientv1.OpenStackClientReadyCondition, + corev1.ConditionTrue, + ) + + pod := &corev1.Pod{} + err := th.K8sClient.Get(ctx, names.OpenStackClientName, pod) + g.Expect(pod).Should(Not(BeNil())) + g.Expect(err).ToNot(HaveOccurred()) + vols := []string{} + for _, x := range pod.Spec.Volumes { + vols = append(vols, x.Name) + } + g.Expect(vols).To(ContainElements("combined-ca-bundle", "openstack-config", "openstack-config-secret")) + + volMounts := map[string]string{} + for _, x := range pod.Spec.Containers[0].VolumeMounts { + volMounts[x.Name] = x.MountPath + } + g.Expect(volMounts).To(HaveKeyWithValue("combined-ca-bundle", "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem")) + g.Expect(volMounts).To(HaveKeyWithValue("openstack-config", "/home/cloud-admin/.config/openstack/clouds.yaml")) + g.Expect(volMounts).To(HaveKeyWithValue("openstack-config-secret", "/home/cloud-admin/.config/openstack/secure.yaml")) + }, timeout, interval).Should(Succeed()) + }) }) })