From 837f77670f152634cdbda91aad7839a60bae5679 Mon Sep 17 00:00:00 2001 From: Martin Schuppert Date: Tue, 7 Nov 2023 15:55:02 +0100 Subject: [PATCH] [openstackclient] Update controller to watch named input resources Adds watches for name secret and configmap resources from the OpenStackClient CRD. This allows to watch the specific resources when they change. Also adds EnvTest for OpenstackClient being created by the OpenstackControlPlane controller. Depends-On: https://github.com/openstack-k8s-operators/lib-common/pull/384 --- ...client.openstack.org_openstackclients.yaml | 2 +- ....openstack.org_openstackcontrolplanes.yaml | 31 +++- apis/go.mod | 2 + apis/go.sum | 4 +- ...client.openstack.org_openstackclients.yaml | 2 +- ....openstack.org_openstackcontrolplanes.yaml | 31 +++- .../client/openstackclient_controller.go | 135 ++++++++++++++++-- go.mod | 4 + go.sum | 8 +- pkg/openstack/ca.go | 6 +- pkg/openstack/openstackclient.go | 2 +- pkg/openstackclient/funcs.go | 78 +++++----- tests/functional/base_test.go | 11 ++ .../openstackoperator_controller_test.go | 50 ++++++- 14 files changed, 299 insertions(+), 67 deletions(-) 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()) + }) }) })