[ISSUE #54 #50] Operator multiple mq cluster && start sequence - #56
[ISSUE #54 #50] Operator multiple mq cluster && start sequence#56linjiemiao wants to merge 2 commits into
Conversation
linjiemiao
commented
Sep 22, 2020
- ensure rocketmq-operator can operator more than one rocketmq cluster;
- make sure nameserver must ready before broker cluster.
2. make sure nameserver must ready before broker cluster.
| size: 1 | ||
| # nameServers is the [ip:port] list of name service | ||
| nameServers: "" | ||
| # rocketMQName is the rocketmq name, must equal to nameserver.spec.rocketMQName and topictransfer.spec.rocketMQName |
There was a problem hiding this comment.
We can not ensure users set insistent name correctly, is there a better way to do this?
There was a problem hiding this comment.
I did this because we don't have a rocketmq resource as the parent resource of the broker and nameserver. Without a common parent controller, we can only specify the connection of the child resource in the spec. So I hope to add a rocketmq api.
There was a problem hiding this comment.
In that case should we add rocketmq higher level api before this PR?
|
still need this |
|
This PR has conflicts with the base branch and cannot be merged. Please rebase or merge the base branch into your branch and resolve the conflicts: git fetch origin
git checkout issue-54-codereview
git rebase origin/main
# resolve conflicts, then:
git push --force-with-leaseThis is a one-time reminder. Feel free to @mention me for a re-review after conflicts are resolved. Automated notification by github-manager-bot |
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Summary
This PR modifies 19 file(s) with 702 lines of diff. No test changes detected — consider adding test coverage.
Automated review by github-manager-bot
Additional notes (not anchored to a changed line)
- [INFO]
README.md:1— Large diff (702 lines). Consider breaking into smaller, focused PRs for easier review. (line outside diff)
| @@ -27,7 +27,6 @@ import ( | |||
| "github.com/apache/rocketmq-operator/pkg/apis" | |||
There was a problem hiding this comment.
No test changes detected alongside source modifications. Consider adding tests to cover the changes.
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Summary
PR received and logged for review. This PR requires detailed code review by a maintainer.
Diff size: 702 lines
Author: linjiemiao (NONE)
Automated review by RockteMQ-AI
| } | ||
|
|
||
| func (sMap *ItemSyncMap) LoadOrStore(key string, value ShareItem) (actual ShareItem, loaded bool) { | ||
| a, loaded := sMap.m.LoadOrStore(key, value) |
There was a problem hiding this comment.
LoadOrStore will panic if the key exists and the stored value is nil, because a.(ShareItem) is an unconditional type assertion. Although ShareItem is a struct (not a pointer), any future refactor to a pointer type would cause a nil panic. More critically, if the underlying sync.Map somehow stores a non-ShareItem value (e.g., due to a bug), this will panic at runtime. Use a safe assertion: actual, _ = a.(ShareItem) to avoid panic.
| return reconcile.Result{}, err | ||
| } | ||
|
|
||
| actualKey := broker.Namespace + "-" + broker.Spec.RocketMQName |
There was a problem hiding this comment.
The broker reconcile loop spins in a tight busy-wait (for { if actual.IsNameServersStrInitialized { break } else { time.Sleep(...) } }) on the controller goroutine. This blocks the entire reconcile goroutine indefinitely, preventing any other reconcile requests from being processed for this controller. This should be replaced with a requeue-based approach (return reconcile.Result{Requeue: true, RequeueAfter: ...}) so the controller manager can continue handling other events.
| return reconcile.Result{}, err | ||
| } | ||
|
|
||
| actualKey := broker.Namespace + "-" + broker.Spec.RocketMQName |
There was a problem hiding this comment.
Race condition: actual is loaded from the sync map into a local variable at line ~134, then the busy-wait loop re-loads actual from the map inside the loop body, but the outer defer at line ~139 always stores the local actual variable back on function exit. If actual.IsNameServersStrInitialized becomes true during the wait loop (set by the nameservice controller), the defer will overwrite the map with the snapshot captured at loop-entry time, potentially clobbering fields like NameServersStr that the nameservice controller wrote.
| @@ -189,8 +201,8 @@ func (r *ReconcileBroker) Reconcile(request reconcile.Request) (reconcile.Result | |||
| // Check for name server scaling | |||
| if broker.Spec.AllowRestart { | |||
| // The following code will restart all brokers to update NAMESRV_ADDR env | |||
There was a problem hiding this comment.
Inconsistent indentation in the if actual.IsNameServersStrUpdated block: the inner for loop is indented with extra tabs compared to surrounding code. This is a minor formatting issue but indicates the code may not have been run through gofmt, which can cause CI lint failures.
| @@ -253,10 +265,17 @@ func (r *ReconcileBroker) Reconcile(request reconcile.Request) (reconcile.Result | |||
| podNames := getPodNames(podList.Items) | |||
There was a problem hiding this comment.
After the early return when len(podNames) == 0, the reconcile returns without storing the updated actual back to the sync map (the defer will still run, but actual.GroupNum and actual.BrokerClusterName will have been set just before this point). However, actual.NameServersStr may not be populated yet if nameServers is empty and the wait loop hasn't run. The defer stores a potentially incomplete actual, which could overwrite a valid previously-stored value if the nameservice controller already populated it.
| sourceCluster := topicTransfer.Spec.SourceCluster | ||
|
|
||
| nameServer := strings.Split(share.NameServersStr, ";")[0] | ||
| actualKey := topicTransfer.Namespace + "-" + topicTransfer.Spec.RocketMQName |
There was a problem hiding this comment.
strings.Split(actual.NameServersStr, ";")[0] will return an empty string (not panic) if actual.NameServersStr is empty, and the subsequent len(nameServer) < cons.MinIpListLength check handles that. However, if actual was just default-initialized by LoadOrStore (i.e., the nameservice for this rocketMQName has not yet reconciled), the TopicTransfer will silently terminate rather than requeue with an informative error. Consider returning a requeue result instead of terminating.
| SourceCluster string `json:"sourceCluster,omitempty"` | ||
| // The cluster where the topic will be transferred to | ||
| TargetCluster string `json:"targetCluster,omitempty"` | ||
| // // RocketMQ Name, the broker and nameserver in the same cluster must be filled with the same name |
There was a problem hiding this comment.
Double comment marker on line 40: // // RocketMQ Name, ... — there is a tab and an extra // before the actual comment text. This is a copy-paste artifact and should be // RocketMQ Name, ....
| @@ -93,6 +96,7 @@ spec: | |||
| - volumes | |||
There was a problem hiding this comment.
rocketMQName is now a required field in the CRD. This is a breaking change for any existing Broker CR that does not have this field set. Existing clusters that upgrade to this operator version will have their Broker CRs fail validation. A defaulting webhook or a non-required field with a documented migration path is needed for safe upgrades.
| @@ -73,6 +76,7 @@ spec: | |||
| - storageMode | |||
There was a problem hiding this comment.
Same breaking change as the Broker CRD: making rocketMQName required on NameService CRD will invalidate all existing NameService CRs on upgrade. Needs a migration strategy.
| @@ -100,7 +93,6 @@ func main() { | |||
|
|
|||
There was a problem hiding this comment.
Removing Namespace from manager.Options changes the operator from namespace-scoped to cluster-scoped watching. This is intentional (given the new ClusterRole), but it is a significant behavioral change: the operator will now watch all namespaces, increasing API server load and requiring the new ClusterRole/ClusterRoleBinding to be applied. This should be explicitly documented in the PR and migration notes, and the old namespace-scoped Role/RoleBinding files should be deprecated or removed to avoid confusion.
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Summary
The multi-cluster isolation approach via rocketMQName keyed sync.Map is a reasonable direction, but the implementation has a critical blocking infinite loop, a value-type race condition in the shared state, and backward-incompatible CRD changes that will break existing deployments.
Findings
- [CRITICAL]
pkg/controller/broker/broker_controller.go:147— Infinite blockingforloop withtime.Sleephas no timeout, context cancellation, or requeue. If the NameServer never becomes ready, this permanently blocks a controller worker goroutine, starving all other reconcile requests. Replace withreturn reconcile.Result{RequeueAfter: ...}, nilso the work is re-enqueued without blocking. - [CRITICAL]
pkg/share/share.go:23—ShareItemis a value type (struct), not a pointer.LoadOrStoreandLoadreturn a copy; mutations to fields likeactual.NameServersStrare local untilStoreis explicitly called. When broker and nameservice controllers reconcile concurrently for the same key, they each get independent copies, mutate them, and the lastStorewins — silently dropping the other's changes (e.g.,IsNameServersStrInitializedcould be overwritten back tofalse). Use*ShareItem(pointer) or a mutex-guarded struct to ensure atomic read-modify-write. - [CRITICAL]
deploy/crds/rocketmq_v1alpha1_broker_crd.yaml:99—rocketMQNameis added to therequiredlist. Any existing Broker CR that does not include this field will fail validation after CRD upgrade, breaking backward compatibility. Either provide a default value via an admission webhook / mutating webhook, remove it fromrequired, or use a conversion/migration step for existing resources. - [CRITICAL]
deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml:79— Same backward-compatibility break as the Broker CRD:rocketMQNameis added torequired, which will reject any existing NameService CR that lacks the field upon upgrade. - [WARNING]
deploy/clusterrole_binding.yaml:22— The ServiceAccount namespace is hardcoded todefault. If the operator is deployed to any other namespace, the binding will reference a non-existent ServiceAccount and RBAC will deny all API calls. Make this configurable (e.g., via Kustomize or Helm templating). - [WARNING]
pkg/controller/broker/broker_controller.go:204— Indentation regression: theforloop inside theif actual.IsNameServersStrUpdatedblock has an extra tab, misaligning it from the enclosingif. This is likely a merge artifact and should be corrected to maintain readability. - [WARNING]
pkg/controller/broker/broker_controller.go:478—getENVcallsLoadOrStore(actualKey, share.ShareItem{})which will insert an emptyShareItem(all zero values) if the key does not yet exist. If the broker reconciles before the nameservice controller has stored real values,NameServersStrwill be empty and broker pods will be created with an invalidNAMESRV_ADDR. Consider usingLoadinstead and returning an error / requeue when the key is absent. - [WARNING]
pkg/controller/nameservice/nameservice_controller.go:177— Early return whenlen(hostIps) != instance.Spec.Sizehappens before the deferredStore, so noShareItemis created for this key. This is correct behavior, but if the nameservice never reaches full size (e.g., a node shortage), brokers waiting onIsNameServersStrInitializedwill block indefinitely (see broker_controller.go infinite loop issue). Consider setting a partial-readiness indicator or adding a timeout. - [INFO]
pkg/apis/rocketmq/v1alpha1/topictransfer_types.go:40— Malformed comment:// // RocketMQ Name...contains a stray tab and duplicate//prefix, likely a copy-paste artifact. Clean up to// RocketMQ Name, the broker and nameserver in the same cluster must be filled with the same name. - [INFO]
deploy/cluster_role.yaml:66—pods/execis listed under therocketmq.apache.orgAPI group, which is incorrect —pods/execbelongs to the core ("") API group and is already listed there (line 30). The duplicate under the custom API group is meaningless and should be removed. - [WARNING]
pkg/controller/topictransfer/topictransfer_controller.go:130—LoadOrStorewith an emptyShareItemmeans if the TopicTransfer reconciles before any NameService has populated the map, an empty entry is persisted.strings.Split("", ";")[0]returns""which is caught by the length check, but the stale empty entry remains in the map. UseLoadand requeue if the key is not found. - [INFO]
pkg/controller/broker/broker_controller.go:298— The newlen(podNames) == 0guard returns early with a requeue, but the subsequent status update at line 302 adds alen(broker.Status.Nodes) != 0guard that prevents clearingStatus.Nodeswhen all pods are gone. This asymmetry means the status can never reflect a fully-scaled-down state; if that is intentional (safety), document it.
Automated review by github-manager-bot
| } else { | ||
| share.GroupNum = broker.Status.Size | ||
| groupNum = broker.Status.Size | ||
| } |
There was a problem hiding this comment.
Infinite blocking for loop with time.Sleep has no timeout, context cancellation, or requeue. If the NameServer never becomes ready, this permanently blocks a controller worker goroutine, starving all other reconcile requests. Replace with return reconcile.Result{RequeueAfter: ...}, nil so the work is re-enqueued without blocking.
|
|
||
| import "sync" | ||
|
|
||
| var ( |
There was a problem hiding this comment.
ShareItem is a value type (struct), not a pointer. LoadOrStore and Load return a copy; mutations to fields like actual.NameServersStr are local until Store is explicitly called. When broker and nameservice controllers reconcile concurrently for the same key, they each get independent copies, mutate them, and the last Store wins — silently dropping the other's changes (e.g., IsNameServersStrInitialized could be overwritten back to false). Use *ShareItem (pointer) or a mutex-guarded struct to ensure atomic read-modify-write.
| - volumes | ||
| - volumeClaimTemplates | ||
| - scalePodName | ||
| - rocketMQName |
There was a problem hiding this comment.
rocketMQName is added to the required list. Any existing Broker CR that does not include this field will fail validation after CRD upgrade, breaking backward compatibility. Either provide a default value via an admission webhook / mutating webhook, remove it from required, or use a conversion/migration step for existing resources.
| - storageMode | ||
| - hostPath | ||
| - volumeClaimTemplates | ||
| - rocketMQName |
There was a problem hiding this comment.
Same backward-compatibility break as the Broker CRD: rocketMQName is added to required, which will reject any existing NameService CR that lacks the field upon upgrade.
| name: rocketmq-operator | ||
| subjects: | ||
| - kind: ServiceAccount | ||
| name: rocketmq-operator |
There was a problem hiding this comment.
The ServiceAccount namespace is hardcoded to default. If the operator is deployed to any other namespace, the binding will reference a non-existent ServiceAccount and RBAC will deny all API calls. Make this configurable (e.g., via Kustomize or Helm templating).
| } | ||
| hostIps := getNameServers(podList.Items) | ||
|
|
||
| if len(hostIps) != int(instance.Spec.Size) || len(hostIps) == 0 { |
There was a problem hiding this comment.
Early return when len(hostIps) != instance.Spec.Size happens before the deferred Store, so no ShareItem is created for this key. This is correct behavior, but if the nameservice never reaches full size (e.g., a node shortage), brokers waiting on IsNameServersStrInitialized will block indefinitely (see broker_controller.go infinite loop issue). Consider setting a partial-readiness indicator or adding a timeout.
| SourceCluster string `json:"sourceCluster,omitempty"` | ||
| // The cluster where the topic will be transferred to | ||
| TargetCluster string `json:"targetCluster,omitempty"` | ||
| // // RocketMQ Name, the broker and nameserver in the same cluster must be filled with the same name |
There was a problem hiding this comment.
Malformed comment: // // RocketMQ Name... contains a stray tab and duplicate // prefix, likely a copy-paste artifact. Clean up to // RocketMQ Name, the broker and nameserver in the same cluster must be filled with the same name.
| - update | ||
| - apiGroups: | ||
| - rocketmq.apache.org | ||
| resources: |
There was a problem hiding this comment.
pods/exec is listed under the rocketmq.apache.org API group, which is incorrect — pods/exec belongs to the core ("") API group and is already listed there (line 30). The duplicate under the custom API group is meaningless and should be removed.
| sourceCluster := topicTransfer.Spec.SourceCluster | ||
|
|
||
| nameServer := strings.Split(share.NameServersStr, ";")[0] | ||
| actualKey := topicTransfer.Namespace + "-" + topicTransfer.Spec.RocketMQName |
There was a problem hiding this comment.
LoadOrStore with an empty ShareItem means if the TopicTransfer reconciles before any NameService has populated the map, an empty entry is persisted. strings.Split("", ";")[0] returns "" which is caught by the length check, but the stale empty entry remains in the map. Use Load and requeue if the key is not found.
| cmd = []string{"/bin/bash", "-c", MakeConfigDirCommand + " && " + ChmodDirCommand + " && " + topicsCommand + " && " + subscriptionGroupCommand} | ||
| } | ||
|
|
||
| // Update status.Nodes if needed |
There was a problem hiding this comment.
The new len(podNames) == 0 guard returns early with a requeue, but the subsequent status update at line 302 adds a len(broker.Status.Nodes) != 0 guard that prevents clearing Status.Nodes when all pods are gone. This asymmetry means the status can never reflect a fully-scaled-down state; if that is intentional (safety), document it.
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Summary
10 finding(s) to address.
Findings
- [CRITICAL]
pkg/controller/broker/broker_controller.go:162— actual.NameServersStr is only assigned on the local copy fetched at the top of Reconcile; it is written back to the sync.Map in the deferred Store (line 139), i.e. after getBrokerStatefulSet() has already run. getENV() (line 484) re-loads the item from the map, so on the first reconcile of a Broker with spec.nameServers set explicitly, the StatefulSet is created with an empty NAMESRV_ADDR env var and the brokers cannot start. The old global-variable code made the mutation immediately visible to getENV; the copy-in/copy-out semantics break that. Store the item immediately after mutating it, or pass the name-server string down into getBrokerStatefulSet/getENV as a parameter. - [WARNING]
pkg/controller/broker/broker_controller.go:139— ShareItem is copied out, mutated, and stored back as a whole by different controllers (broker, nameservice, topictransfer) with no per-key locking. Concurrent reconciles for the same key perform read-modify-write on independent struct copies, so the last Store wins and the other controller's changes are silently lost — e.g. a broker reconcile finishing here can revert a NameServersStr / IsNameServersStrUpdated value just written by the nameservice controller. sync.Map only protects the map itself, not lost updates on the values. Guard each key with a mutex, or have each controller store only the fields it owns. - [WARNING]
pkg/controller/broker/broker_controller.go:150— This busy-wait loop blocks the reconcile worker indefinitely. With per-key state, a mismatch between broker.spec.rocketMQName and the NameService CR's rocketMQName (a plain string with no cross-CRD validation — a single typo) means IsNameServersStrInitialized is never set and this goroutine sleeps forever. With the default MaxConcurrentReconciles=1, one misconfigured cluster starves every broker CR in every other cluster, defeating the multi-cluster goal of this PR. Prefer returning reconcile.Result{RequeueAfter: ...} like the pod-not-ready handling already added further down in this function. - [WARNING]
deploy/crds/rocketmq_v1alpha1_broker_crd.yaml:99— rocketMQName is added torequired(also in the nameservice and topictransfer CRDs). Existing Broker/NameService/TopicTransfer CRs created by older operator versions lack this field, so after the CRD update any subsequent write to those objects (kubectl apply/edit, and potentially the operator's own status updates) fails OpenAPI validation — there is no migration path documented. Also note that CRs patched with an empty value silently collide on the key "-". Consider making the field optional with a documented default, or document a mandatory pre-upgrade migration for all existing CRs. - [WARNING]
deploy/clusterrole_binding.yaml:21— The ClusterRoleBinding subject hardcodes namespace: default. If the operator is installed in any other namespace, its ServiceAccount never receives the ClusterRole and — since the manager now watches all namespaces — informer cache sync fails and the operator cannot start. The binding should be parameterized by the install namespace, and deploy/operator.yaml needs to be updated to reference this cluster-scoped RBAC (the diff does not touch it, so existing deployments still ship the namespaced Role and WATCH_NAMESPACE). - [WARNING]
cmd/manager/main.go:94— Removing GetWatchNamespace()/the Namespace option silently ignores the WATCH_NAMESPACE env var that existing operator deployments set. After upgrading, the operator expands from namespaced to cluster-wide watching with no notice; deployments that deliberately scoped it for least privilege will break at startup because the caches now need list/watch across all namespaces (and old namespaced Role manifests no longer suffice). Keep honoring WATCH_NAMESPACE, or at minimum log a loud warning when it is set. - [INFO]
pkg/controller/nameservice/nameservice_controller.go:233— clusterName (and GroupNum) come from in-memory cross-controller state that is only populated after a Broker reconcile for the same rocketMQName has run. After an operator restart the map is empty, so a name-server list change triggers the mqAdmin updateBrokerConfig command with-c "", which fails and silently leaves brokers configured with stale name-server addresses. Consider looking the broker cluster name up from the Broker CR (label/owner lookup) instead of relying on shared memory. This weakness is inherited from the old globals, but the restart-loss scenario is worth fixing while this state is being reworked. - [INFO]
pkg/share/share.go:28— No unit tests accompany the new share package or the reworked reconcile logic, although both are easily testable (LoadOrStore/Store round-trips, concurrent updates to one key, and the Reconcile path where spec.nameServers is set explicitly). A test asserting that a newly created broker StatefulSet carries the expected NAMESRV_ADDR would have caught the stale-copy bug in getENV. - [INFO]
pkg/controller/broker/broker_controller.go:205— The for loop underif actual.IsNameServersStrUpdatedis indented one level too deep — a gofmt violation introduced by this change; please run gofmt/goimports on the touched files. - [INFO]
pkg/apis/rocketmq/v1alpha1/topictransfer_types.go:40— The comment is doubled (// \t// RocketMQ Name...) — leftover from editing. Similar "and and" duplications appear in the new README and example YAML comments; worth a quick copy pass.
Automated review by github-manager-bot
| } | ||
| } else { | ||
| share.NameServersStr = broker.Spec.NameServers | ||
| actual.NameServersStr = broker.Spec.NameServers |
There was a problem hiding this comment.
actual.NameServersStr is only assigned on the local copy fetched at the top of Reconcile; it is written back to the sync.Map in the deferred Store (line 139), i.e. after getBrokerStatefulSet() has already run. getENV() (line 484) re-loads the item from the map, so on the first reconcile of a Broker with spec.nameServers set explicitly, the StatefulSet is created with an empty NAMESRV_ADDR env var and the brokers cannot start. The old global-variable code made the mutation immediately visible to getENV; the copy-in/copy-out semantics break that. Store the item immediately after mutating it, or pass the name-server string down into getBrokerStatefulSet/getENV as a parameter.
| defer func() { | ||
| reqLogger.Info("Broker actualKey:" + actualKey + " actual.NameServerStr:" + actual.NameServersStr + | ||
| " actual.BrokerClusterName:" + actual.BrokerClusterName + " IsNameServersStrInitialized:" + strconv.FormatBool(actual.IsNameServersStrInitialized)) | ||
| share.GetInstance().Store(actualKey, actual) |
There was a problem hiding this comment.
ShareItem is copied out, mutated, and stored back as a whole by different controllers (broker, nameservice, topictransfer) with no per-key locking. Concurrent reconciles for the same key perform read-modify-write on independent struct copies, so the last Store wins and the other controller's changes are silently lost — e.g. a broker reconcile finishing here can revert a NameServersStr / IsNameServersStrUpdated value just written by the nameservice controller. sync.Map only protects the map itself, not lost updates on the values. Guard each key with a mutex, or have each controller store only the fields it owns.
|
|
||
| if broker.Spec.NameServers == "" { | ||
| // wait for name server ready when create broker cluster if nameServers is omitted | ||
| for { |
There was a problem hiding this comment.
This busy-wait loop blocks the reconcile worker indefinitely. With per-key state, a mismatch between broker.spec.rocketMQName and the NameService CR's rocketMQName (a plain string with no cross-CRD validation — a single typo) means IsNameServersStrInitialized is never set and this goroutine sleeps forever. With the default MaxConcurrentReconciles=1, one misconfigured cluster starves every broker CR in every other cluster, defeating the multi-cluster goal of this PR. Prefer returning reconcile.Result{RequeueAfter: ...} like the pod-not-ready handling already added further down in this function.
| - volumes | ||
| - volumeClaimTemplates | ||
| - scalePodName | ||
| - rocketMQName |
There was a problem hiding this comment.
rocketMQName is added to required (also in the nameservice and topictransfer CRDs). Existing Broker/NameService/TopicTransfer CRs created by older operator versions lack this field, so after the CRD update any subsequent write to those objects (kubectl apply/edit, and potentially the operator's own status updates) fails OpenAPI validation — there is no migration path documented. Also note that CRs patched with an empty value silently collide on the key "-". Consider making the field optional with a documented default, or document a mandatory pre-upgrade migration for all existing CRs.
| metadata: | ||
| name: rocketmq-operator | ||
| subjects: | ||
| - kind: ServiceAccount |
There was a problem hiding this comment.
The ClusterRoleBinding subject hardcodes namespace: default. If the operator is installed in any other namespace, its ServiceAccount never receives the ClusterRole and — since the manager now watches all namespaces — informer cache sync fails and the operator cannot start. The binding should be parameterized by the install namespace, and deploy/operator.yaml needs to be updated to reference this cluster-scoped RBAC (the diff does not touch it, so existing deployments still ship the namespaced Role and WATCH_NAMESPACE).
| @@ -100,7 +93,6 @@ func main() { | |||
|
|
|||
| // Create a new Cmd to provide shared dependencies and start components | |||
There was a problem hiding this comment.
Removing GetWatchNamespace()/the Namespace option silently ignores the WATCH_NAMESPACE env var that existing operator deployments set. After upgrading, the operator expands from namespaced to cluster-wide watching with no notice; deployments that deliberately scoped it for least privilege will break at startup because the caches now need list/watch across all namespaces (and old namespaced Role manifests no longer suffice). Keep honoring WATCH_NAMESPACE, or at minimum log a loud warning when it is set.
|
|
||
|
|
||
| clusterName := share.BrokerClusterName | ||
| clusterName := actual.BrokerClusterName |
There was a problem hiding this comment.
clusterName (and GroupNum) come from in-memory cross-controller state that is only populated after a Broker reconcile for the same rocketMQName has run. After an operator restart the map is empty, so a name-server list change triggers the mqAdmin updateBrokerConfig command with -c "", which fails and silently leaves brokers configured with stale name-server addresses. Consider looking the broker cluster name up from the Broker CR (label/owner lookup) instead of relying on shared memory. This weakness is inherited from the old globals, but the restart-loss scenario is worth fixing while this state is being reworked.
| instance *Singleton | ||
| ) | ||
|
|
||
| type ShareItem struct { |
There was a problem hiding this comment.
No unit tests accompany the new share package or the reworked reconcile logic, although both are easily testable (LoadOrStore/Store round-trips, concurrent updates to one key, and the Reconcile path where spec.nameServers is set explicitly). A test asserting that a newly created broker StatefulSet carries the expected NAMESRV_ADDR would have caught the stale-copy bug in getENV.
| if share.IsNameServersStrUpdated { | ||
| for brokerGroupIndex := 0; brokerGroupIndex < broker.Spec.Size; brokerGroupIndex++ { | ||
| if actual.IsNameServersStrUpdated { | ||
| for brokerGroupIndex := 0; brokerGroupIndex < broker.Spec.Size; brokerGroupIndex++ { |
There was a problem hiding this comment.
The for loop under if actual.IsNameServersStrUpdated is indented one level too deep — a gofmt violation introduced by this change; please run gofmt/goimports on the touched files.
| SourceCluster string `json:"sourceCluster,omitempty"` | ||
| // The cluster where the topic will be transferred to | ||
| TargetCluster string `json:"targetCluster,omitempty"` | ||
| // // RocketMQ Name, the broker and nameserver in the same cluster must be filled with the same name |
There was a problem hiding this comment.
The comment is doubled (// \t// RocketMQ Name...) — leftover from editing. Similar "and and" duplications appear in the new README and example YAML comments; worth a quick copy pass.