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
35 changes: 35 additions & 0 deletions api/bases/watcher.openstack.org_watchers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -608,13 +608,46 @@ spec:
description: MemcachedInstance is the name of the Memcached CR that
all watcher service will use.
type: string
messagingBus:
description: MessagingBus configuration (username, vhost, and cluster)
properties:
cluster:
description: Name of the cluster
minLength: 1
type: string
user:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im not sure if this makes seense either.

the reaosin i say that is when i filed https://issues.redhat.com/browse/OSPRH-92 orgianly it was also covering rothation of the rabbit mq password

it was scoped down to only the db for GA but
the intent was to intoduce a messaging busss account CR following the mariadb CR patthern to allow password rotation while having 2 active password/users

to do that we would need to generate a new user/password password pair so that the old pass word can remain active after the contolplane has rotaited to allow time of for the edpm deployment.

inother words we cannot have the user be part of this struct unless rabbit supprot having 2 active password for the same user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback. The way credentials rotation can be achieved is by simply switching the user in the cr, so you could start from "user-old" and switch to "user-new". Both credentials will be valid until a human admin decides to manually remove the unused one. We did not implement auto cleanup as it would break edpm nodes, plus we want to allow rolling back to old credentials if required.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that seams messy vs the dedicated maria db account where the db is account is removed when the account CR is removed and we use a finalsize to prevent tis deletion until all usage of it is remvoed form all the crs that refence it.

are there plans to model the rabbit acocunts as CRDs in a similar way?
watcher does nto have any edpm compoents so its less relenvet for this PR but it a factor for nova

ideally we shoudl not have human operators direcly interacting with rabbit.

so my suggestion is to replace user with an account name which fence a rabbit account opbejct like the database account CRD.

the rotation woudl basically happen the way you suggest you create a new account obejct which will be reconsiled by the infra operator and update the value in the service template which will propagate to the service operator to reconisle.

during that reconsiliation they will remove there finaliser form the old account CR and add it to the new one.

once teh human has completed the edpm deploy ment they will delete the old account cr.
the infra operator would hten remove that user and password form rabit.

if they want to revert at any point before they do that delete they just need to revert the refence rabbit account object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's how it has been implemented already. Human operators only have to specify the username and a rabbitmquser crd is created for them, similarly to the db account. Finalizers are also moved to the new account and removed from the old one for rotation purposes. See openstack-k8s-operators/infra-operator@f4eab21 .

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the db account have to be created seperalty and then the name of the account passed in

so this is not workign the saem. unless this is the name of the rabbitmquer cr not the username.

if we have a rabbitmquser CRD then we shoudl be takign the name of the rabbitmquser CR here not the user name ot have this work the same as the db password.

can you make that change?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, according to the current implementation, services will keep creating a TransporURL object with optionally user and vhost parameters. The rabbitmq operator will create a CR RabbitmqUser and RabbitmqVhost under the hood, will create the watcher transportURL and will add a finalizer on the TransportURL to those two objects. When creating a new user by modifying the MessagingBus.user in Watcher object, the rabbitmq will create a new RabbitmqUser object, will update the TransportURL secret and object, remove the finalizer on the old user and will add the new one.

Then, the OpenStack operator should remove the old RabbitmqUser to delete the old account?

Is that the expected workflow?. IMO, it's an acceptable one, it's different than the one for MariaDB but I don't see an issue with it as soon as it's properly implemented. It's much more consistent and easy to implement that forcing the services to manage the RabbitmqUser creation, etc... which would require changing all the services operators. In this way the workflow is encapsulated in the RabbitMQ operator, which is good.

I have one doubt, what should happen when the user is not setting user and vhost? it will create a user name dynamically and an RabbitMQuser object for it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the ablity for the service operator to create the mariadbAccount CR
is the deprecated flow that was ment to be deleted

so i dont think that we shoudl eb creating the RabbitmqUser cr in the watcher operator based on jsut the username.

that specifcliy the part im objectign too.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for what its worht i kind of see the current propsoal to autocare the user (and password) just bsed on teh user name as a security problem that would prevent use merging this.

bsiclly it provde a very easy way to typo the name have a user created and then not notice this again since it wont show up in the controlplan CR

you would have to expclitly go looking for the RabbitmqUser crs to keep track fo them and manually corralate them.

description: User - RabbitMQ username
type: string
vhost:
description: Vhost - RabbitMQ vhost name
type: string
required:
- cluster
type: object
nodeSelector:
additionalProperties:
type: string
description: |-
NodeSelector to target subset of worker nodes running this component. Setting here overrides
any global NodeSelector settings within the Watcher CR.
type: object
notificationsBus:
description: NotificationsBus configuration (username, vhost, and
cluster) for notifications
properties:
cluster:
description: Name of the cluster
minLength: 1
type: string
user:
description: User - RabbitMQ username
type: string
vhost:
description: Vhost - RabbitMQ vhost name
type: string
required:
- cluster
type: object
notificationsBusInstance:
description: |-
NotificationsBusInstance is the name of the RabbitMqCluster CR to select
Expand All @@ -623,6 +656,7 @@ spec:
If undefined, the value will be inherited from OpenStackControlPlane.
An empty value "" leaves the notification drivers unconfigured and emitting no notifications at all.
Avoid colocating it with RabbitMqClusterName or other message bus instances used for RPC.
Deprecated: Use NotificationsBus.Cluster instead
type: string
passwordSelectors:
default:
Expand Down Expand Up @@ -650,6 +684,7 @@ spec:
description: |-
RabbitMQ instance name
Needed to request a transportURL that is created and used in Watcher
Deprecated: Use MessagingBus.Cluster instead
type: string
secret:
default: osp-secret
Expand Down
29 changes: 16 additions & 13 deletions api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.24.4
toolchain go1.24.6

require (
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251223124749-eedb97238c5f
github.com/openstack-k8s-operators/infra-operator/apis v0.6.1-0.20251217131115-0f117a938d4e
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 +18,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 @@ -45,16 +44,17 @@ require (
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/rabbitmq/cluster-operator/v2 v2.16.0 // indirect
github.com/spf13/pflag v1.0.7 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/term v0.35.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/term v0.34.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/time v0.12.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/protobuf v1.36.7 // indirect
Expand All @@ -70,22 +70,25 @@ require (
sigs.k8s.io/yaml v1.6.0 // indirect
)

// lmiccini: temporary replace for infra-operator fix
replace github.com/openstack-k8s-operators/infra-operator/apis => github.com/lmiccini/infra-operator/apis v0.0.0-20260112082729-52ecbe505d08

// pin these to avoid later versions pulled by rabbitmq
replace k8s.io/apimachinery => k8s.io/apimachinery v0.31.14 //allow-merging
replace k8s.io/apimachinery => k8s.io/apimachinery v0.31.13 //allow-merging

replace k8s.io/api => k8s.io/api v0.31.14 //allow-merging
replace k8s.io/api => k8s.io/api v0.31.13 //allow-merging

replace k8s.io/apiserver => k8s.io/apiserver v0.31.14 //allow-merging
replace k8s.io/apiserver => k8s.io/apiserver v0.31.13 //allow-merging

replace k8s.io/client-go => k8s.io/client-go v0.31.14 //allow-merging
replace k8s.io/client-go => k8s.io/client-go v0.31.13 //allow-merging

replace k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.31.14 //allow-merging
replace k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.31.13 //allow-merging

replace k8s.io/cli-runtime => k8s.io/cli-runtime v0.31.14 //allow-merging
replace k8s.io/cli-runtime => k8s.io/cli-runtime v0.31.13 //allow-merging

replace k8s.io/code-generator => k8s.io/code-generator v0.31.14 //allow-merging
replace k8s.io/code-generator => k8s.io/code-generator v0.31.13 //allow-merging

replace k8s.io/component-base => k8s.io/component-base v0.31.14 //allow-merging
replace k8s.io/component-base => k8s.io/component-base v0.31.13 //allow-merging

// custom RabbitmqClusterSpecCore for OpenStackControlplane (v2.16.0_patches)
replace github.com/rabbitmq/cluster-operator/v2 => github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec //allow-merging
Expand Down
39 changes: 21 additions & 18 deletions api/go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
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 @@ -64,6 +65,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lmiccini/infra-operator/apis v0.0.0-20260112082729-52ecbe505d08 h1:XgzBX9I6T4WJcPYjYcghvL1L1JF8iwmSS60eAi4iktk=
github.com/lmiccini/infra-operator/apis v0.0.0-20260112082729-52ecbe505d08/go.mod h1:ZXwFlspJCdZEUjMbmaf61t5AMB4u2vMyAMMoe/vJroE=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand All @@ -78,10 +81,10 @@ 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/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/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec h1:saovr368HPAKHN0aRPh8h8n9s9dn3d8Frmfua0UYRlc=
github.com/openstack-k8s-operators/rabbitmq-cluster-operator/v2 v2.6.1-0.20250929174222-a0d328fa4dec/go.mod h1:Nh2NEePLjovUQof2krTAg4JaAoLacqtPTZQXK6izNfg=
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 Expand Up @@ -137,19 +140,19 @@ golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKl
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand All @@ -175,14 +178,14 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.31.14 h1:xYn/S/WFJsksI7dk/5uBRd3Umm/D8W5g7sRnd4csotA=
k8s.io/api v0.31.14/go.mod h1:K8fvRey4z73RAuxBZCma7WtY8WFvkViYhfFLCMT4xgA=
k8s.io/apiextensions-apiserver v0.31.14 h1:1KupD0PyU7CgiT/PiZPSgZhTCL2KGwvXd1ejGcxjEfg=
k8s.io/apiextensions-apiserver v0.31.14/go.mod h1:Odk14fSl/zaciI8DRUSPMSH74UXtz4gfinw7zY7YHvE=
k8s.io/apimachinery v0.31.14 h1:/eMIwjv+GFm6A/sSGlB1NupBU6wTDPhEWsju0Fj69kY=
k8s.io/apimachinery v0.31.14/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/client-go v0.31.14 h1:d4/G0xfksNIbMWH7ghjzOwC5bTAwQ20gABTjZw7fLlQ=
k8s.io/client-go v0.31.14/go.mod h1:0uRpRB7r5QwtsbxEngZPkbcIVoNdAQAPIcopgiXjhQc=
k8s.io/api v0.31.13 h1:sco9Cq2pY4Ysv9qZiWzcR97MmA/35nwYQ/VCTzOcWmc=
k8s.io/api v0.31.13/go.mod h1:4D8Ry8RqqLDemNLwGYC6v5wOy51N7hitr4WQ6oSWfLY=
k8s.io/apiextensions-apiserver v0.31.13 h1:8xtWKVpV/YbYX0UX2k6w+cgxfxKhX0UNGuo/VXAdg8g=
k8s.io/apiextensions-apiserver v0.31.13/go.mod h1:zxpMLWXBxnJqKUIruJ+ulP+Xlfe5lPZPxq1z0cLwA2U=
k8s.io/apimachinery v0.31.13 h1:rkG0EiBkBkEzURo/8dKGx/oBF202Z2LqHuSD8Cm3bG4=
k8s.io/apimachinery v0.31.13/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/client-go v0.31.13 h1:Q0LG51uFbzNd9fzIj5ilA0Sm1wUholHvDaNwVKzqdCA=
k8s.io/client-go v0.31.13/go.mod h1:UB4yTzQeRAv+vULOKp2jdqA5LSwV55bvc3RQ5tM48LM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250627150254-e9823e99808e h1:UGI9rv1A2cV87NhXr4s+AUBxIuoo/SME/IyJ3b6KztE=
Expand Down
14 changes: 12 additions & 2 deletions api/v1beta1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ limitations under the License.
package v1beta1

import (
"github.com/openstack-k8s-operators/lib-common/modules/common/util"

rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1"
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
"github.com/openstack-k8s-operators/lib-common/modules/common/util"

corev1 "k8s.io/api/core/v1"
)
Expand Down Expand Up @@ -83,10 +83,19 @@ type WatcherSpecCore struct {
// Important: Run "make" to regenerate code after modifying this file
WatcherCommon `json:",inline"`

// +kubebuilder:validation:Optional
// MessagingBus configuration (username, vhost, and cluster)
MessagingBus rabbitmqv1.RabbitMqConfig `json:"messagingBus,omitempty"`

// +kubebuilder:validation:Optional
// NotificationsBus configuration (username, vhost, and cluster) for notifications
NotificationsBus *rabbitmqv1.RabbitMqConfig `json:"notificationsBus,omitempty"`

// +kubebuilder:validation:Required
// +kubebuilder:default=rabbitmq
// RabbitMQ instance name
// Needed to request a transportURL that is created and used in Watcher
// Deprecated: Use MessagingBus.Cluster instead
RabbitMqClusterName *string `json:"rabbitMqClusterName"`

// +kubebuilder:validation:Optional
Expand Down Expand Up @@ -136,6 +145,7 @@ type WatcherSpecCore struct {
// If undefined, the value will be inherited from OpenStackControlPlane.
// An empty value "" leaves the notification drivers unconfigured and emitting no notifications at all.
// Avoid colocating it with RabbitMqClusterName or other message bus instances used for RPC.
// Deprecated: Use NotificationsBus.Cluster instead
NotificationsBusInstance *string `json:"notificationsBusInstance,omitempty"`
}

Expand Down
55 changes: 48 additions & 7 deletions api/v1beta1/watcher_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package v1beta1
import (
"fmt"

rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1"
topologyv1 "github.com/openstack-k8s-operators/infra-operator/apis/topology/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -59,12 +60,34 @@ func (r *Watcher) Default() {

// Default - set defaults for this WatcherCore spec.
func (spec *WatcherSpec) Default() {
spec.WatcherSpecCore.Default()
spec.WatcherImages.Default(watcherDefaults)
}

// Default - set defaults for this WatcherSpecCore spec.
func (spec *WatcherSpecCore) Default() {
// no validations . Placeholder for defaulting webhook integrated in the OpenStackControlPlane
// Apply kubebuilder default for RabbitMqClusterName if not set
if spec.RabbitMqClusterName == nil {
spec.RabbitMqClusterName = ptr.To("rabbitmq")
}

// Default MessagingBus.Cluster from RabbitMqClusterName if not already set
if spec.MessagingBus.Cluster == "" {
rabbitmqv1.DefaultRabbitMqConfig(&spec.MessagingBus, *spec.RabbitMqClusterName)
}

// Default NotificationsBus if NotificationsBusInstance is specified
if spec.NotificationsBusInstance != nil && *spec.NotificationsBusInstance != "" {
if spec.NotificationsBus == nil {
// Initialize empty NotificationsBus - credentials will be created dynamically
// to ensure separation from MessagingBus (RPC and notifications should never share credentials)
spec.NotificationsBus = &rabbitmqv1.RabbitMqConfig{}
}
// Always default the Cluster field from NotificationsBusInstance if it's empty
if spec.NotificationsBus.Cluster == "" {
rabbitmqv1.DefaultRabbitMqConfig(spec.NotificationsBus, *spec.NotificationsBusInstance)
}
}
}

var _ webhook.Validator = &Watcher{}
Expand Down Expand Up @@ -95,19 +118,20 @@ func (spec *WatcherSpec) ValidateCreate(basePath *field.Path, namespace string)
func (spec *WatcherSpecCore) ValidateCreate(basePath *field.Path, namespace string) field.ErrorList {
var allErrs field.ErrorList

if *spec.DatabaseInstance == "" || spec.DatabaseInstance == nil {
if spec.DatabaseInstance == nil || *spec.DatabaseInstance == "" {
allErrs = append(
allErrs,
field.Invalid(
basePath.Child("databaseInstance"), "", "databaseInstance field should not be empty"),
)
}

if *spec.RabbitMqClusterName == "" || spec.RabbitMqClusterName == nil {
// Validate messagingBus.cluster instead of deprecated rabbitMqClusterName
if spec.MessagingBus.Cluster == "" {
allErrs = append(
allErrs,
field.Invalid(
basePath.Child("rabbitMqClusterName"), "", "rabbitMqClusterName field should not be empty"),
basePath.Child("messagingBus").Child("cluster"), "", "messagingBus.cluster field should not be empty"),
)
}

Expand Down Expand Up @@ -148,22 +172,39 @@ func (spec *WatcherSpec) ValidateUpdate(old WatcherSpec, basePath *field.Path, n
func (spec *WatcherSpecCore) ValidateUpdate(old WatcherSpecCore, basePath *field.Path, namespace string) field.ErrorList {
var allErrs field.ErrorList

if *spec.DatabaseInstance == "" || spec.DatabaseInstance == nil {
if spec.DatabaseInstance == nil || *spec.DatabaseInstance == "" {
allErrs = append(
allErrs,
field.Invalid(
basePath.Child("databaseInstance"), "", "databaseInstance field should not be empty"),
)
}

if *spec.RabbitMqClusterName == "" || spec.RabbitMqClusterName == nil {
// Validate messagingBus.cluster instead of deprecated rabbitMqClusterName
if spec.MessagingBus.Cluster == "" {
allErrs = append(
allErrs,
field.Invalid(
basePath.Child("rabbitMqClusterName"), "", "rabbitMqClusterName field should not be empty"),
basePath.Child("messagingBus").Child("cluster"), "", "messagingBus.cluster field should not be empty"),
)
}

// Reject changes to deprecated RabbitMqClusterName field
if spec.RabbitMqClusterName != nil && old.RabbitMqClusterName != nil &&
*spec.RabbitMqClusterName != *old.RabbitMqClusterName {
allErrs = append(allErrs, field.Forbidden(
basePath.Child("rabbitMqClusterName"),
"rabbitMqClusterName is deprecated and cannot be changed. Please use messagingBus.cluster instead"))
}

// Reject changes to deprecated NotificationsBusInstance field
if spec.NotificationsBusInstance != nil && old.NotificationsBusInstance != nil &&
*spec.NotificationsBusInstance != *old.NotificationsBusInstance {
allErrs = append(allErrs, field.Forbidden(
basePath.Child("notificationsBusInstance"),
"notificationsBusInstance is deprecated and cannot be changed. Please use notificationsBus.cluster instead"))
}

allErrs = append(allErrs, spec.ValidateWatcherTopology(basePath, namespace)...)

return allErrs
Expand Down
Loading