Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions modules/certmanager/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

certmgrv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
certmgrmetav1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
"github.com/openstack-k8s-operators/lib-common/modules/common/backup"
"github.com/openstack-k8s-operators/lib-common/modules/common/helper"
"github.com/openstack-k8s-operators/lib-common/modules/common/net"
"github.com/openstack-k8s-operators/lib-common/modules/common/secret"
Expand Down Expand Up @@ -270,14 +271,15 @@ func EnsureCert(
}

// EnsureCertForServicesWithSelector - creates certificate for k8s services identified
// by a label selector
// by a label selector. Optional extraLabels are merged into the certificate request labels.
func EnsureCertForServicesWithSelector(
ctx context.Context,
helper *helper.Helper,
namespace string,
selector map[string]string,
issuer string,
owner client.Object,
extraLabels ...map[string]string,
) (map[string]string, ctrl.Result, error) {
certs := map[string]string{}
svcs, err := service.GetServicesListWithLabel(
Expand All @@ -292,12 +294,23 @@ func EnsureCertForServicesWithSelector(

for _, svc := range svcs.Items {
hostname := fmt.Sprintf("%s.%s.svc", svc.Name, namespace)
certName := fmt.Sprintf("%s-svc", svc.Name)
// Merge service labels with extra labels, then apply cert secret
// backup annotation overrides so cert-manager's SecretTemplate
// propagates the correct labels.
labels, err := backup.GetCertSecretBackupLabels(
ctx, helper.GetClient(), certName, namespace,
util.MergeMaps(svc.Labels, extraLabels...),
)
if err != nil {
return nil, ctrl.Result{}, err
}
// create cert for the service
certRequest := CertificateRequest{
IssuerName: issuer,
CertName: fmt.Sprintf("%s-svc", svc.Name),
CertName: certName,
Hostnames: []string{hostname},
Labels: svc.Labels,
Labels: labels,
}
certSecret, ctrlResult, err := EnsureCert(
ctx,
Expand All @@ -317,7 +330,8 @@ func EnsureCertForServicesWithSelector(
}

// EnsureCertForServiceWithSelector - creates certificate for a k8s service identified
// by a label selector. The label selector must match a single service
// by a label selector. The label selector must match a single service.
// Optional extraLabels are merged into the certificate request labels.
// Note: Returns an NotFound error if <1 or >1 service found using the selector
func EnsureCertForServiceWithSelector(
ctx context.Context,
Expand All @@ -326,6 +340,7 @@ func EnsureCertForServiceWithSelector(
selector map[string]string,
issuer string,
owner client.Object,
extraLabels ...map[string]string,
) (string, ctrl.Result, error) {
var cert string
svcs, err := service.GetServicesListWithLabel(
Expand All @@ -346,7 +361,7 @@ func EnsureCertForServiceWithSelector(
}

certs, ctrlResult, err := EnsureCertForServicesWithSelector(
ctx, helper, namespace, selector, issuer, owner)
ctx, helper, namespace, selector, issuer, owner, extraLabels...)
if err != nil {
return cert, ctrlResult, err
} else if (ctrlResult != ctrl.Result{}) {
Expand Down
77 changes: 77 additions & 0 deletions modules/common/backup/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 2025 Red Hat

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 backup

import (
"context"

apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// Config holds backup/restore configuration for a CRD
type Config struct {
Enabled bool
RestoreOrder string
Category string
}

// CRDLabelCache maps CRD names to their backup configuration
type CRDLabelCache map[string]Config

// BuildCRDLabelCache reads all CRDs and caches their backup labels
func BuildCRDLabelCache(ctx context.Context, c client.Client) (CRDLabelCache, error) {
cache := make(CRDLabelCache)

crdList := &apiextensionsv1.CustomResourceDefinitionList{}
if err := c.List(ctx, crdList); err != nil {
return nil, err
}

for _, crd := range crdList.Items {
labels := crd.GetLabels()
if labels == nil {
continue
}

// Only cache CRDs that opt into backup/restore
if labels[BackupRestoreLabel] != "true" {
continue
}

config := Config{
Enabled: true,
RestoreOrder: labels[BackupRestoreOrderLabel],
Category: labels[BackupCategoryLabel],
}

// Cache by CRD name (e.g., "keystoneapis.keystone.openstack.org")
cache[crd.Name] = config
}

return cache, nil
}

// GetConfig looks up backup configuration by CRD name
// (e.g., "keystoneapis.keystone.openstack.org").
// Returns Config with Enabled=false if not found.
func (c CRDLabelCache) GetConfig(crdName string) Config {
if config, ok := c[crdName]; ok {
return config
}
return Config{Enabled: false}
}
Loading
Loading