Skip to content
Open
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
17 changes: 17 additions & 0 deletions api/bases/watcher.openstack.org_watchers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ spec:
replicas: 1
description: APIServiceTemplate - define the watcher-api service
properties:
auth:
description: Auth - Parameters related to authentication
properties:
applicationCredentialSecret:
description: ApplicationCredentialSecret - Secret containing
Application Credential ID and Secret
type: string
type: object
customServiceConfig:
description: |-
CustomServiceConfig - customize the service config using this parameter to change service defaults,
Expand Down Expand Up @@ -460,6 +468,15 @@ spec:
type: string
type: object
type: object
auth:
description: Auth - Parameters related to authentication (shared by
all Watcher components)
properties:
applicationCredentialSecret:
description: ApplicationCredentialSecret - Secret containing Application
Credential ID and Secret
type: string
type: object
customServiceConfig:
description: |-
CustomServiceConfig - customize the service config using this parameter to change service defaults,
Expand Down
8 changes: 7 additions & 1 deletion api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ toolchain go1.24.6

require (
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251206133124-593df0a7a9e1
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35
k8s.io/api v0.31.14
k8s.io/apimachinery v0.31.14
Expand All @@ -18,7 +19,6 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
Expand All @@ -33,13 +33,17 @@ require (
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gophercloud/gophercloud/v2 v2.8.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openshift/api v3.9.0+incompatible // indirect
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251122131503-b76943960b6c // indirect
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20251122131503-b76943960b6c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
Expand Down Expand Up @@ -91,3 +95,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.13 //allow-merging
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging

replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging

replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81
10 changes: 10 additions & 0 deletions api/go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81 h1:plax+NFgJJL1SrERyXAnf3jOHRhLTtBlJ2oc7d84EoU=
github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81/go.mod h1:b98Jl8eyUw8V07l9YiuQnoMlnWC748oV8IhXH15NCC4=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down Expand Up @@ -48,6 +50,8 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gophercloud/gophercloud/v2 v2.8.0 h1:of2+8tT6+FbEYHfYC8GBu8TXJNsXYSNm9KuvpX7Neqo=
github.com/gophercloud/gophercloud/v2 v2.8.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
Expand Down Expand Up @@ -78,10 +82,16 @@ github.com/onsi/ginkgo/v2 v2.27.3 h1:ICsZJ8JoYafeXFFlFAG75a7CxMsJHwgKwtO+82SE9L8
github.com/onsi/ginkgo/v2 v2.27.3/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM=
github.com/onsi/gomega v1.38.3/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs=
github.com/openshift/api v3.9.0+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY=
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f h1:xcCGJ/g5vvbWhtEJCbv8UeBneI5yrMawm+CXRsJrJZo=
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f/go.mod h1:ex8ou6/3ms6ovR+CMXD6XhTlNakm1GhB6UZgagVRNW8=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35 h1:pF3mJ3nwq6r4qwom+rEWZNquZpcQW/iftHlJ1KPIDsk=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35/go.mod h1:kycZyoe7OZdW1HUghr2nI3N7wSJtNahXf6b/ypD14f4=
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251122131503-b76943960b6c h1:l7FO+XoQRnD4aT5p/JXVY2uezQLdC7D50KrwrTmzCfg=
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251122131503-b76943960b6c/go.mod h1:zOX7Y05keiSppIvLabuyh42QHBMhCcoskAtxFRbwXKo=
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20251122131503-b76943960b6c h1:dVIaDL5BeIdJjERGaN/XlcvZVplfkzh0uUfiVUHj/6Q=
github.com/openstack-k8s-operators/lib-common/modules/storage v0.6.1-0.20251122131503-b76943960b6c/go.mod h1:fy1lvz3uuzzh01DKKdgroXvmJgMpJBsvl2r9eTtAll0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
5 changes: 5 additions & 0 deletions api/v1beta1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ type WatcherSpecCore struct {
// APITimeout for Route and Apache
APITimeout *int `json:"apiTimeout"`

// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
// Auth - Parameters related to authentication (shared by all Watcher components)
Auth AuthSpec `json:"auth,omitempty"`

// +kubebuilder:validation:Optional
// NotificationsBusInstance is the name of the RabbitMqCluster CR to select
// the Message Bus Service instance used by the Watcher service to publish and consume notifications
Expand Down
6 changes: 6 additions & 0 deletions api/v1beta1/watcher_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"

topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -65,6 +66,11 @@ func (spec *WatcherSpec) Default() {
// Default - set defaults for this WatcherSpecCore spec.
func (spec *WatcherSpecCore) Default() {
// no validations . Placeholder for defaulting webhook integrated in the OpenStackControlPlane

// Default ApplicationCredentialSecret to standard AC secret name if not specified
if spec.Auth.ApplicationCredentialSecret == "" {
spec.Auth.ApplicationCredentialSecret = keystonev1.GetACSecretName("watcher")
}
}

var _ webhook.Validator = &Watcher{}
Expand Down
13 changes: 13 additions & 0 deletions api/v1beta1/watcherapi_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ type APIOverrideSpec struct {
Service map[service.Endpoint]service.RoutedOverrideSpec `json:"service,omitempty"`
}

// AuthSpec defines authentication parameters
type AuthSpec struct {
// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
// ApplicationCredentialSecret - Secret containing Application Credential ID and Secret
ApplicationCredentialSecret string `json:"applicationCredentialSecret,omitempty"`
}

// WatcherAPITemplate defines the input parameters specified by the user to
// create a WatcherAPI via higher level CRDs.
type WatcherAPITemplate struct {
Expand All @@ -112,6 +120,11 @@ type WatcherAPITemplate struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec
// TLS - Parameters related to the TLS
TLS tls.API `json:"tls,omitempty"`

// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec
// Auth - Parameters related to authentication
Auth AuthSpec `json:"auth,omitempty"`
}

//+kubebuilder:object:root=true
Expand Down
17 changes: 17 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions config/crd/bases/watcher.openstack.org_watchers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ spec:
replicas: 1
description: APIServiceTemplate - define the watcher-api service
properties:
auth:
description: Auth - Parameters related to authentication
properties:
applicationCredentialSecret:
description: ApplicationCredentialSecret - Secret containing
Application Credential ID and Secret
type: string
type: object
customServiceConfig:
description: |-
CustomServiceConfig - customize the service config using this parameter to change service defaults,
Expand Down Expand Up @@ -460,6 +468,15 @@ spec:
type: string
type: object
type: object
auth:
description: Auth - Parameters related to authentication (shared by
all Watcher components)
properties:
applicationCredentialSecret:
description: ApplicationCredentialSecret - Secret containing Application
Credential ID and Secret
type: string
type: object
customServiceConfig:
description: |-
CustomServiceConfig - customize the service config using this parameter to change service defaults,
Expand Down
15 changes: 15 additions & 0 deletions config/manifests/bases/watcher-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,24 @@ spec:
kind: Watcher
name: watchers.watcher.openstack.org
specDescriptors:
- description: Auth - Parameters related to authentication
displayName: Auth
path: apiServiceTemplate.auth
- description: ApplicationCredentialSecret - Secret containing Application Credential
ID and Secret
displayName: Application Credential Secret
path: apiServiceTemplate.auth.applicationCredentialSecret
- description: TLS - Parameters related to the TLS
displayName: TLS
path: apiServiceTemplate.tls
- description: Auth - Parameters related to authentication (shared by all Watcher
components)
displayName: Auth
path: auth
- description: ApplicationCredentialSecret - Secret containing Application Credential
ID and Secret
displayName: Application Credential Secret
path: auth.applicationCredentialSecret
version: v1beta1
description: The Watcher Operator project
displayName: Watcher Operator
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,5 @@ replace k8s.io/component-base => k8s.io/component-base v0.31.13 //allow-merging
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging

replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e //allow-merging

replace github.com/openstack-k8s-operators/keystone-operator/api => github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81 h1:plax+NFgJJL1SrERyXAnf3jOHRhLTtBlJ2oc7d84EoU=
github.com/Deydra71/keystone-operator/api v0.0.0-20251211085602-3e1a3e022c81/go.mod h1:b98Jl8eyUw8V07l9YiuQnoMlnWC748oV8IhXH15NCC4=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
Expand Down Expand Up @@ -120,8 +122,6 @@ github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e h1:E1OdwSpqWuDPCedyU
github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f h1:xcCGJ/g5vvbWhtEJCbv8UeBneI5yrMawm+CXRsJrJZo=
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f/go.mod h1:ex8ou6/3ms6ovR+CMXD6XhTlNakm1GhB6UZgagVRNW8=
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251206133124-593df0a7a9e1 h1:qcgbrF9c0axkaDcFGfIA2wGz8bkaxPuXHj3mdKAyz6M=
github.com/openstack-k8s-operators/keystone-operator/api v0.6.1-0.20251206133124-593df0a7a9e1/go.mod h1:0XsZ6Fc4hTV6a/BBP8+jiH8LR+IP5z9aStdPTDHALNk=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35 h1:pF3mJ3nwq6r4qwom+rEWZNquZpcQW/iftHlJ1KPIDsk=
github.com/openstack-k8s-operators/lib-common/modules/common v0.6.1-0.20251230215914-6ba873b49a35/go.mod h1:kycZyoe7OZdW1HUghr2nI3N7wSJtNahXf6b/ypD14f4=
github.com/openstack-k8s-operators/lib-common/modules/openstack v0.6.1-0.20251122131503-b76943960b6c h1:l7FO+XoQRnD4aT5p/JXVY2uezQLdC7D50KrwrTmzCfg=
Expand Down
2 changes: 2 additions & 0 deletions internal/controller/watcher_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
tlsAPIPublicField = ".spec.tls.api.public.secretName"
topologyField = ".spec.topologyRef.Name"
memcachedInstanceField = ".spec.memcachedInstance"
authAppCredSecretField = ".spec.auth.applicationCredentialSecret" //nolint:gosec // G101: Not actual credentials, just field path
// service label for cinder endpoint
endpointCinder = "cinder"
)
Expand All @@ -60,6 +61,7 @@ var (
watcherWatchFields = []string{
passwordSecretField,
prometheusSecretField,
authAppCredSecretField,
}
decisionEngineWatchFields = []string{
passwordSecretField,
Expand Down
51 changes: 51 additions & 0 deletions internal/controller/watcher_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,25 @@ func (r *WatcherReconciler) generateServiceConfigDBJobs(
"APIPublicPort": fmt.Sprintf("%d", watcher.WatcherPublicPort),
}

// Retrieve Application Credential data if configured
if instance.Spec.Auth.ApplicationCredentialSecret != "" {
secret := &corev1.Secret{}
key := types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Auth.ApplicationCredentialSecret}
if err := r.Client.Get(ctx, key, secret); err != nil {
if !k8s_errors.IsNotFound(err) {
Log.Error(err, "Failed to get ApplicationCredential secret", "secret", key)
}
} else {
acID, okID := secret.Data[keystonev1.ACIDSecretKey]
acSecret, okSecret := secret.Data[keystonev1.ACSecretSecretKey]
if okID && len(acID) > 0 && okSecret && len(acSecret) > 0 {
templateParameters["ACID"] = string(acID)
templateParameters["ACSecret"] = string(acSecret)
Log.Info("Using ApplicationCredentials auth", "secret", key)
}
}
}

return GenerateConfigsGeneric(ctx, helper, instance, envVars, templateParameters, customData, labels, true)
}

Expand Down Expand Up @@ -884,6 +903,26 @@ func (r *WatcherReconciler) createSubLevelSecret(
watcher.GlobalCustomConfigFileName: instance.Spec.CustomServiceConfig,
NotificationURLSelector: string(notificationURLSecret.Data[TransportURLSelector]),
}

// Add Application Credential data if configured
if instance.Spec.Auth.ApplicationCredentialSecret != "" {
acSecret := &corev1.Secret{}
key := types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.Auth.ApplicationCredentialSecret}
if err := r.Client.Get(ctx, key, acSecret); err != nil {
if !k8s_errors.IsNotFound(err) {
Log.Error(err, "Failed to get ApplicationCredential secret", "secret", key)
}
} else {
acID, okID := acSecret.Data[keystonev1.ACIDSecretKey]
acSecretData, okSecret := acSecret.Data[keystonev1.ACSecretSecretKey]
if okID && len(acID) > 0 && okSecret && len(acSecretData) > 0 {
data["ACID"] = string(acID)
data["ACSecret"] = string(acSecretData)
Log.Info("Using ApplicationCredentials auth (centralized from parent Watcher CR)", "secret", key)
}
}
}

secretName := instance.Name

labels := labels.GetLabels(instance, labels.GetGroupLabel(watcher.ServiceName), map[string]string{})
Expand Down Expand Up @@ -1266,6 +1305,18 @@ func (r *WatcherReconciler) SetupWithManager(mgr ctrl.Manager) error {
return err
}

// index authAppCredSecretField
if err := mgr.GetFieldIndexer().IndexField(context.Background(), &watcherv1beta1.Watcher{}, authAppCredSecretField, func(rawObj client.Object) []string {
// Extract the secret name from the spec, if one is provided
cr := rawObj.(*watcherv1beta1.Watcher)
if cr.Spec.Auth.ApplicationCredentialSecret == "" {
return nil
}
return []string{cr.Spec.Auth.ApplicationCredentialSecret}
}); err != nil {
return err
}

return ctrl.NewControllerManagedBy(mgr).
For(&watcherv1beta1.Watcher{}).
Owns(&watcherv1beta1.WatcherAPI{}).
Expand Down
10 changes: 10 additions & 0 deletions internal/controller/watcherapi_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,16 @@ func (r *WatcherAPIReconciler) generateServiceConfigs(
if string(secret.Data[NotificationURLSelector]) != "" {
templateParameters["NotificationURL"] = string(secret.Data[NotificationURLSelector])
}

// Application Credential data
if acID, ok := secret.Data["ACID"]; ok && len(acID) > 0 {
if acSecretData, ok := secret.Data["ACSecret"]; ok && len(acSecretData) > 0 {
templateParameters["ACID"] = string(acID)
templateParameters["ACSecret"] = string(acSecretData)
Log.Info("Using ApplicationCredentials auth")
}
}

// MTLS
if memcachedInstance.GetMemcachedMTLSSecret() != "" {
templateParameters["MemcachedAuthCert"] = fmt.Sprint(memcachedv1.CertMountPath())
Expand Down
Loading