Skip to content

Commit e55ccde

Browse files
lmicciniclaude
andcommitted
Add TLS certificate for InstanceHA metrics endpoint
Create a cert-manager Certificate for the InstanceHA metrics service when pod-level TLS is enabled. The certificate uses the internal issuer with wildcard hostnames for the namespace, following the same pattern as EnsureOVNMetricsCert. The resulting secret (cert-instanceha-metrics) is consumed by the infra-operator InstanceHA controller. Also add the cert-instanceha-metrics secret to functional tests so the reconciler does not block waiting for cert-manager in envtest. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent cdd350d commit e55ccde

14 files changed

Lines changed: 435 additions & 4 deletions

api/core/v1beta1/conditions.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ const (
150150
// OpenStackControlPlaneInstanceHaCMReadyCondition Status=True condition which indicates if InstanceHa CM is ready
151151
OpenStackControlPlaneInstanceHaCMReadyCondition condition.Type = "OpenStackControlPlaneInstanceHaCMReadyCondition"
152152

153+
// OpenStackControlPlaneInstanceHaTLSReadyCondition Status=True condition which indicates if InstanceHa TLS certificate is ready
154+
OpenStackControlPlaneInstanceHaTLSReadyCondition condition.Type = "OpenStackControlPlaneInstanceHaTLSReadyCondition"
155+
153156
// OpenStackControlPlaneCertCleanupReadyCondition Status=True condition which indicates global certification cleanup is Ready
154157
OpenStackControlPlaneCertCleanupReadyCondition condition.Type = "OpenStackControlPlaneCertCleanupReadyCondition"
155158

@@ -492,6 +495,12 @@ const (
492495
// OpenStackControlPlaneInstanceHaCMReadyMessage
493496
OpenStackControlPlaneInstanceHaCMReadyMessage = "OpenStackControlPlane InstanceHa CM is available"
494497

498+
// OpenStackControlPlaneInstanceHaTLSReadyErrorMessage
499+
OpenStackControlPlaneInstanceHaTLSReadyErrorMessage = "OpenStackControlPlane InstanceHa TLS cert error occured %s"
500+
501+
// OpenStackControlPlaneInstanceHaTLSReadyMessage
502+
OpenStackControlPlaneInstanceHaTLSReadyMessage = "OpenStackControlPlane InstanceHa TLS cert is available"
503+
495504
// OpenStackControlPlaneOpenStackVersionInitializationReadyInitMessage
496505
OpenStackControlPlaneOpenStackVersionInitializationReadyInitMessage = "OpenStackControlPlane OpenStackVersion initialization not started"
497506

internal/openstack/instanceha.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ package openstack
22

33
import (
44
"context"
5+
"fmt"
56

7+
certmgrv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
8+
"github.com/openstack-k8s-operators/lib-common/modules/certmanager"
9+
"github.com/openstack-k8s-operators/lib-common/modules/common/clusterdns"
610
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
711
"github.com/openstack-k8s-operators/lib-common/modules/common/configmap"
812
"github.com/openstack-k8s-operators/lib-common/modules/common/helper"
@@ -21,6 +25,26 @@ const (
2125

2226
// ReconcileInstanceHa reconciles the instance HA configuration for the OpenStack control plane
2327
func ReconcileInstanceHa(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) {
28+
Log := GetLogger(ctx)
29+
30+
if instance.Spec.TLS.PodLevel.Enabled {
31+
_, err := EnsureInstanceHAMetricsCert(ctx, instance, helper)
32+
if err != nil {
33+
Log.Error(err, "Failed to ensure InstanceHA metrics certificate")
34+
instance.Status.Conditions.Set(condition.FalseCondition(
35+
corev1beta1.OpenStackControlPlaneInstanceHaTLSReadyCondition,
36+
condition.ErrorReason,
37+
condition.SeverityWarning,
38+
corev1beta1.OpenStackControlPlaneInstanceHaTLSReadyErrorMessage,
39+
err.Error()))
40+
return ctrl.Result{}, err
41+
}
42+
instance.Status.Conditions.Set(condition.TrueCondition(
43+
corev1beta1.OpenStackControlPlaneInstanceHaTLSReadyCondition,
44+
corev1beta1.OpenStackControlPlaneInstanceHaTLSReadyMessage,
45+
))
46+
}
47+
2448
customData := map[string]string{
2549
InstanceHaImageKey: *getImg(version.Status.ContainerImages.OpenstackClientImage, &missingImageDefault),
2650
}
@@ -54,3 +78,48 @@ func ReconcileInstanceHa(ctx context.Context, instance *corev1beta1.OpenStackCon
5478

5579
return ctrl.Result{}, nil
5680
}
81+
82+
// EnsureInstanceHAMetricsCert creates a TLS certificate for InstanceHA metrics services
83+
func EnsureInstanceHAMetricsCert(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, helper *helper.Helper) (string, error) {
84+
Log := GetLogger(ctx)
85+
86+
dnsSuffix := clusterdns.GetDNSClusterDomain()
87+
88+
certRequest := certmanager.CertificateRequest{
89+
IssuerName: instance.GetInternalIssuer(),
90+
CertName: "instanceha-metrics",
91+
Hostnames: []string{
92+
fmt.Sprintf("*.%s.svc", instance.Namespace),
93+
fmt.Sprintf("*.%s.svc.%s", instance.Namespace, dnsSuffix),
94+
},
95+
Ips: nil,
96+
Usages: []certmgrv1.KeyUsage{
97+
certmgrv1.UsageKeyEncipherment,
98+
certmgrv1.UsageDigitalSignature,
99+
certmgrv1.UsageServerAuth,
100+
},
101+
Labels: map[string]string{ServiceCertSelector: ""},
102+
}
103+
104+
if instance.Spec.TLS.PodLevel.Internal.Cert.Duration != nil {
105+
certRequest.Duration = &instance.Spec.TLS.PodLevel.Internal.Cert.Duration.Duration
106+
}
107+
if instance.Spec.TLS.PodLevel.Internal.Cert.RenewBefore != nil {
108+
certRequest.RenewBefore = &instance.Spec.TLS.PodLevel.Internal.Cert.RenewBefore.Duration
109+
}
110+
111+
certSecret, ctrlResult, err := certmanager.EnsureCert(
112+
ctx,
113+
helper,
114+
certRequest,
115+
nil)
116+
if err != nil {
117+
return "", err
118+
} else if (ctrlResult != ctrl.Result{}) {
119+
Log.Info("InstanceHA metrics certificate creation in progress", "certificate", certRequest.CertName)
120+
return "", fmt.Errorf("InstanceHA metrics certificate creation in progress")
121+
}
122+
123+
Log.Info("InstanceHA metrics certificate ensured", "secret", certSecret.Name, "certificate", certRequest.CertName)
124+
return certSecret.Name, nil
125+
}

test/functional/ctlplane/base_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ type Names struct {
9999
OVNDbServerNBName types.NamespacedName
100100
OVNDbServerSBName types.NamespacedName
101101
OVNMetricsCertName types.NamespacedName
102+
InstanceHAMetricsCertName types.NamespacedName
102103
NeutronOVNCertName types.NamespacedName
103104
OpenStackTopology []types.NamespacedName
104105
WatcherCertPublicRouteName types.NamespacedName
@@ -291,6 +292,10 @@ func CreateNames(openstackControlplaneName types.NamespacedName) Names {
291292
Namespace: openstackControlplaneName.Namespace,
292293
Name: "cert-ovn-metrics",
293294
},
295+
InstanceHAMetricsCertName: types.NamespacedName{
296+
Namespace: openstackControlplaneName.Namespace,
297+
Name: "cert-instanceha-metrics",
298+
},
294299
NeutronOVNCertName: types.NamespacedName{
295300
Namespace: openstackControlplaneName.Namespace,
296301
Name: "cert-neutron-ovndbs",

test/functional/ctlplane/openstackoperator_controller_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,7 @@ var _ = Describe("OpenStackOperator controller", func() {
937937
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
938938
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
939939
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNMetricsCertName))
940+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InstanceHAMetricsCertName))
940941
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
941942
DeferCleanup(
942943
th.DeleteInstance,
@@ -1259,6 +1260,7 @@ var _ = Describe("OpenStackOperator controller", func() {
12591260
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
12601261
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
12611262
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNMetricsCertName))
1263+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InstanceHAMetricsCertName))
12621264
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
12631265
spec := GetDefaultOpenStackControlPlaneSpec()
12641266
spec["tls"] = GetTLSeCustomIssuerSpec()
@@ -1388,6 +1390,7 @@ var _ = Describe("OpenStackOperator controller", func() {
13881390
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
13891391
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
13901392
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNMetricsCertName))
1393+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InstanceHAMetricsCertName))
13911394
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
13921395

13931396
DeferCleanup(k8sClient.Delete, ctx,
@@ -2083,6 +2086,7 @@ var _ = Describe("OpenStackOperator controller", func() {
20832086
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
20842087
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
20852088
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNMetricsCertName))
2089+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InstanceHAMetricsCertName))
20862090
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
20872091

20882092
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.WatcherCertPublicRouteName))
@@ -2273,6 +2277,7 @@ var _ = Describe("OpenStackOperator controller", func() {
22732277
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
22742278
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
22752279
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNMetricsCertName))
2280+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InstanceHAMetricsCertName))
22762281
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
22772282
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.WatcherCertPublicRouteName))
22782283
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.WatcherCertPublicSvcName))
@@ -2750,6 +2755,7 @@ var _ = Describe("OpenStackOperator controller", func() {
27502755
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
27512756
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
27522757
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNMetricsCertName))
2758+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InstanceHAMetricsCertName))
27532759
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
27542760

27552761
DeferCleanup(
@@ -2991,6 +2997,7 @@ var _ = Describe("OpenStackOperator controller", func() {
29912997
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
29922998
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
29932999
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNMetricsCertName))
3000+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InstanceHAMetricsCertName))
29943001
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
29953002
// create cert secret for octavia ovn client
29963003
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(types.NamespacedName{Name: "cert-octavia-ovndbs", Namespace: names.Namespace}))
@@ -4049,6 +4056,7 @@ var _ = Describe("OpenStackOperator controller nova cell deletion", func() {
40494056
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNNorthdCertName))
40504057
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNControllerCertName))
40514058
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.OVNMetricsCertName))
4059+
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.InstanceHAMetricsCertName))
40524060
DeferCleanup(k8sClient.Delete, ctx, th.CreateCertSecret(names.NeutronOVNCertName))
40534061

40544062
// create cert secrets for memcached instance

0 commit comments

Comments
 (0)