RockteMQ-AI commented on code in PR #61:
URL: https://github.com/apache/rocketmq-operator/pull/61#discussion_r3902480013


##########
deploy/crds/rocketmq_v1alpha1_broker_crd.yaml:
##########
@@ -79,6 +79,31 @@ spec:
               items:
                 type: object
               type: array
+            affinity:
+              description: Affinity and anti-affinity scheduling
+              type: object

Review Comment:
   The `affinity` field is declared as `type: object` with no structural 
schema. This allows any arbitrary YAML to pass CRD validation, deferring errors 
to the kube-scheduler at runtime. Consider using 
`x-kubernetes-preserve-unknown-fields: true` with a more specific schema, or at 
minimum document the expected structure. Same issue applies to 
`securityContext`, `nodeSelector`, and `podAnnotations` (all `type: object`), 
and to `imagePullSecrets`/`tolerations` (`items: type: object`). While this 
pattern is common in early-stage operators, it provides zero admission-time 
validation.



##########
example/rocketmq_v1alpha1_rocketmq_feature_cluster.yaml:
##########
@@ -0,0 +1,180 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: broker-config
+data:
+  # BROKER_MEM sets the broker JVM, if set to "" then Xms = Xmx = max(min(1/2 
ram, 1024MB), min(1/4 ram, 8GB))
+  BROKER_MEM: " -Xms2g -Xmx2g -Xmn1g "
+  broker-common.conf: |
+    # brokerClusterName, brokerName, brokerId are automatically generated by 
the operator and do not set it manually!!!
+    deleteWhen=04
+    fileReservedTime=48
+    flushDiskType=ASYNC_FLUSH
+    # set brokerRole to ASYNC_MASTER or SYNC_MASTER. DO NOT set to SLAVE 
because the replica instance will automatically be set!!!
+    brokerRole=ASYNC_MASTER
+
+---
+apiVersion: rocketmq.apache.org/v1alpha1
+kind: Broker
+metadata:
+  # name of broker cluster
+  name: broker
+spec:
+  # size is the number of the broker cluster, each broker cluster contains a 
master broker and [replicaPerGroup] replica brokers.
+  size: 1
+  # nameServers is the [ip:port] list of name service
+  nameServers: ""
+  # replicaPerGroup is the number of each broker cluster
+  replicaPerGroup: 0
+  # brokerImage is the customized docker image repo of the RocketMQ broker
+  brokerImage: apacherocketmq/rocketmq-broker:4.5.0-alpine-operator-0.3.0
+  # imagePullPolicy is the image pull policy
+  imagePullPolicy: Always
+  # resources describes the compute resource requirements and limits
+  resources:
+    requests:
+      memory: "2048Mi"
+      cpu: "250m"
+    limits:
+      memory: "12288Mi"
+      cpu: "500m"
+  # allowRestart defines whether allow pod restart
+  allowRestart: true
+  # storageMode can be EmptyDir, HostPath, StorageClass
+  storageMode: EmptyDir
+  # hostPath is the local path to store data
+  hostPath: /tmp/data/rocketmq/broker
+  # scalePodName is [Broker name]-[broker group number]-master-0
+  scalePodName: broker-0-master-0
+  # env defines custom env, e.g. BROKER_MEM
+  env:
+    - name: BROKER_MEM
+      valueFrom:
+        configMapKeyRef:
+          name: broker-config
+          key: BROKER_MEM
+  # volumes defines the broker.conf
+  volumes:
+    - name: broker-config
+      configMap:
+        name: broker-config
+        items:
+          - key: broker-common.conf
+            path: broker-common.conf
+  # volumeClaimTemplates defines the storageClass
+  volumeClaimTemplates:
+    - metadata:
+        name: broker-storage
+      spec:
+        accessModes:
+          - ReadWriteOnce
+        resources:
+          requests:
+            storage: 8Gi
+        selector:
+          matchLabels:
+            app: broker-storage-pv
+---
+apiVersion: rocketmq.apache.org/v1alpha1
+kind: NameService
+metadata:
+  name: name-service
+spec:
+  # size is the the name service instance number of the name service cluster
+  size: 1
+  # nameServiceImage is the customized docker image repo of the RocketMQ name 
service
+  nameServiceImage: 
apacherocketmq/rocketmq-nameserver:4.5.0-alpine-operator-0.3.0
+  # imagePullPolicy is the image pull policy
+  imagePullPolicy: Always
+  # hostNetwork can be true or false
+  hostNetwork: true
+  podAnnotations:
+    prometheus.io/path: /metrics
+    prometheus.io/port: "5557"
+    prometheus.io/scrape: "true"
+  securityContext:
+    allowPrivilegeEscalation: true
+    runAsUser: 0
+    runAsGroup: 0
+  affinity:
+    nodeAffinity:
+      requiredDuringSchedulingIgnoredDuringExecution:
+        nodeSelectorTerms:
+          - matchExpressions:
+              - key: kubernetes.io/hostname
+                operator: In
+                values:
+                  - azure-k8s-7
+                  - azure-k8s-1
+                  - azure-k8s-3
+                  - azure-k8s-2
+    podAntiAffinity:
+      preferredDuringSchedulingIgnoredDuringExecution:
+        - weight: 100

Review Comment:
   The example sets `allowPrivilegeEscalation: true` and `runAsUser: 0` / 
`runAsGroup: 0`, which runs the NameService container as root with privilege 
escalation enabled. This is a security anti-pattern and should not be in an 
example file that users will copy. If root is truly required for RocketMQ, add 
a comment explaining why and recommend dropping to a non-root user where 
possible. At minimum, set `allowPrivilegeEscalation: false`.



##########
deploy/crds/rocketmq_v1alpha1_nameservice_crd.yaml:
##########
@@ -63,6 +63,31 @@ spec:
               items:
                 type: object
               type: array
+            affinity:
+              description: Affinity and anti-affinity scheduling
+              type: object

Review Comment:
   Same unstructured schema issue as the broker CRD — `affinity`, 
`securityContext`, `nodeSelector`, `podAnnotations` all accept arbitrary 
objects. Since these fields are duplicated across two CRDs, consider extracting 
a shared validation schema (or a shared struct with code-generated OpenAPI) to 
keep them in sync and avoid drift.



##########
pkg/controller/broker/broker_controller.go:
##########
@@ -401,8 +401,15 @@ func (r *ReconcileBroker) getBrokerStatefulSet(broker 
*rocketmqv1alpha1.Broker,
                        Template: corev1.PodTemplateSpec{
                                ObjectMeta: metav1.ObjectMeta{
                                        Labels: ls,
+                                       Annotations: broker.Spec.PodAnnotations,

Review Comment:
   `Annotations: broker.Spec.PodAnnotations` directly assigns the spec map to 
the pod template. If a user later removes all annotations from the spec 
(setting it to `nil` or `{}`), the existing annotations on the live 
StatefulSet's pod template won't be cleared during an update unless the 
controller explicitly handles this in its update/reconciliation path. Verify 
that the update logic in `updateBrokerStatefulSet` (or equivalent) properly 
propagates annotation removal, not just addition.



##########
pkg/apis/rocketmq/v1alpha1/broker_types.go:
##########
@@ -56,6 +56,21 @@ type BrokerSpec struct {
        VolumeClaimTemplates []corev1.PersistentVolumeClaim 
`json:"volumeClaimTemplates"`
        // The name of pod where the metadata from
        ScalePodName string `json:"scalePodName"`
+       // Affinity, affinity and anti-affinity scheduling
+       Affinity *corev1.Affinity `json:"affinity,omitempty"`
+       // SecurityContext defines privilege and access control settings for a 
Pod or Container.
+       SecurityContext *corev1.PodSecurityContext 
`json:"securityContext,omitempty"`
+       // ImagePullSecrets pull an image from a private registry
+       ImagePullSecrets     []corev1.LocalObjectReference 
`json:"imagePullSecrets,omitempty"`
+       // Tolerations taints and tolerations work together to ensure that pods 
are not scheduled onto inappropriate nodes
+       Tolerations          []corev1.Toleration           
`json:"tolerations,omitempty"`
+       // NodeSelector is the simplest recommended form of node selection 
constraint.
+       NodeSelector         map[string]string             
`json:"nodeSelector,omitempty"`
+       // PodAnnotations you can use annotations to attach arbitrary 
non-identifying metadata to objects.
+       PodAnnotations       map[string]string             
`json:"podAnnotations,omitempty"`
+       // PriorityClassName defines priority class's name
+       PriorityClassName    string                        
`json:"priorityClassName,omitempty"`

Review Comment:
   No test coverage is added for the new fields. The broker and nameservice 
controller tests should verify that: (1) a CR with these fields produces a 
StatefulSet with the correct PodSpec, (2) nil/empty values produce the same 
StatefulSet as before (backward compat), and (3) updates to these fields 
trigger a rolling update. Without tests, regressions in the reconciliation 
logic are likely to go undetected.



##########
pkg/controller/broker/broker_controller.go:
##########
@@ -401,8 +401,15 @@ func (r *ReconcileBroker) getBrokerStatefulSet(broker 
*rocketmqv1alpha1.Broker,
                        Template: corev1.PodTemplateSpec{
                                ObjectMeta: metav1.ObjectMeta{
                                        Labels: ls,
+                                       Annotations: broker.Spec.PodAnnotations,
                                },

Review Comment:
   All six new PodSpec fields (`Affinity`, `SecurityContext`, 
`ImagePullSecrets`, `Tolerations`, `NodeSelector`, `PriorityClassName`) are 
assigned directly from the CR spec with no nil-guard. This is safe for the 
Kubernetes API (nil/empty values are valid), but it means any change to these 
fields will trigger a StatefulSet rolling update. For fields like 
`nodeSelector` or `tolerations` that an operator might want to change 
frequently, consider documenting this behavior so users understand the pod 
churn implications.



##########
pkg/controller/nameservice/nameservice_controller.go:
##########
@@ -316,10 +316,17 @@ func (r *ReconcileNameService) 
statefulSetForNameService(nameService *rocketmqv1
                        Template: corev1.PodTemplateSpec{
                                ObjectMeta: metav1.ObjectMeta{
                                        Labels: ls,
+                                       Annotations: 
nameService.Spec.PodAnnotations,

Review Comment:
   Same annotation propagation concern as the broker controller: `Annotations: 
nameService.Spec.PodAnnotations` is a direct assignment. If the existing 
StatefulSet's pod template has annotations set by a mutating webhook or by a 
previous spec version, they will be silently overwritten on reconciliation. 
Consider merging annotations (existing + spec) rather than replacing, or 
document that spec annotations are authoritative.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to