@@ -18,52 +18,8 @@ import (
1818 "sigs.k8s.io/controller-runtime/pkg/reconcile"
1919)
2020
21- type statefulSetParameters struct {
22- Replicas * int32
23- Name string
24- PersistentVolumeClaim corev1.PersistentVolumeClaim
25- ServiceName string
26- TerminationGracePeriodSeconds * int64
27- UpdateStrategy appsv1.StatefulSetUpdateStrategyType
28- NodeSelector map [string ]string
29- Affinity * corev1.Affinity
30- TopologySpreadConstraints []corev1.TopologySpreadConstraint
31- PriorityClassName string
32- ImagePullSecrets []corev1.LocalObjectReference
33- AdditionalVolumeClaimTemplates * []corev1.PersistentVolumeClaim
34- ServiceAccountName string
35- AutomountServiceAccountToken * bool
36- }
37-
38- type containerParameters struct {
39- Name string
40- Namespace string
41- ClusterDomain string
42- Image string
43- ImagePullPolicy corev1.PullPolicy
44- Resources * corev1.ResourceRequirements
45- Persistence * marklogicv1.Persistence
46- Volumes []corev1.Volume
47- MountPaths []corev1.VolumeMount
48- LicenseKey string
49- Licensee string
50- BootstrapHost string
51- LivenessProbe marklogicv1.ContainerProbe
52- ReadinessProbe marklogicv1.ContainerProbe
53- LogCollection * marklogicv1.LogCollection
54- GroupConfig * marklogicv1.GroupConfig
55- PodSecurityContext * corev1.PodSecurityContext
56- SecurityContext * corev1.SecurityContext
57- EnableConverters bool
58- HugePages * marklogicv1.HugePages
59- PathBasedRouting bool
60- Tls * marklogicv1.Tls
61- AdditionalVolumes * []corev1.Volume
62- AdditionalVolumeMounts * []corev1.VolumeMount
63- SecretName string
64- }
65-
6621// getDefaultPodSecurityContext returns the default pod-level security context for MarkLogic StatefulSets
22+ // MarkLogic runs as user 1000 and group 2 (mlusers) - Must not be changed
6723func getDefaultPodSecurityContext () * corev1.PodSecurityContext {
6824 fsGroup := int64 (2 )
6925 fsGroupChangePolicy := corev1 .FSGroupChangeOnRootMismatch
@@ -74,8 +30,8 @@ func getDefaultPodSecurityContext() *corev1.PodSecurityContext {
7430}
7531
7632// getDefaultContainerSecurityContext returns the default container-level security context for MarkLogic containers
77- // This enforces:
78- // - runAsUser: 1000 (non-root user)
33+ // This enforces strict security requirements :
34+ // - runAsUser: 1000 - MarkLogic runs as user 1000 and group 2 (mlusers) - Must not be changed
7935// - runAsNonRoot: true (prevents running as root)
8036// - allowPrivilegeEscalation: false (prevents privilege escalation)
8137// - readOnlyRootFilesystem: true (makes root filesystem read-only)
@@ -97,7 +53,7 @@ func getDefaultContainerSecurityContext() *corev1.SecurityContext {
9753}
9854
9955// mergeSecurityContext merges user-provided SecurityContext with defaults
100- // User-provided values take precedence over defaults
56+ // User-provided values take precedence over defaults for flexibility
10157func mergeSecurityContext (userContext , defaultContext * corev1.SecurityContext ) * corev1.SecurityContext {
10258 if userContext == nil {
10359 return defaultContext
@@ -134,7 +90,7 @@ func mergeSecurityContext(userContext, defaultContext *corev1.SecurityContext) *
13490}
13591
13692// mergePodSecurityContext merges user-provided PodSecurityContext with defaults
137- // User-provided values take precedence over defaults
93+ // User-provided values take precedence over defaults for flexibility
13894func mergePodSecurityContext (userContext , defaultContext * corev1.PodSecurityContext ) * corev1.PodSecurityContext {
13995 if userContext == nil {
14096 return defaultContext
@@ -170,6 +126,51 @@ func mergePodSecurityContext(userContext, defaultContext *corev1.PodSecurityCont
170126 return merged
171127}
172128
129+ type statefulSetParameters struct {
130+ Replicas * int32
131+ Name string
132+ PersistentVolumeClaim corev1.PersistentVolumeClaim
133+ ServiceName string
134+ TerminationGracePeriodSeconds * int64
135+ UpdateStrategy appsv1.StatefulSetUpdateStrategyType
136+ NodeSelector map [string ]string
137+ Affinity * corev1.Affinity
138+ TopologySpreadConstraints []corev1.TopologySpreadConstraint
139+ PriorityClassName string
140+ ImagePullSecrets []corev1.LocalObjectReference
141+ AdditionalVolumeClaimTemplates * []corev1.PersistentVolumeClaim
142+ ServiceAccountName string
143+ AutomountServiceAccountToken * bool
144+ }
145+
146+ type containerParameters struct {
147+ Name string
148+ Namespace string
149+ ClusterDomain string
150+ Image string
151+ ImagePullPolicy corev1.PullPolicy
152+ Resources * corev1.ResourceRequirements
153+ Persistence * marklogicv1.Persistence
154+ Volumes []corev1.Volume
155+ MountPaths []corev1.VolumeMount
156+ LicenseKey string
157+ Licensee string
158+ BootstrapHost string
159+ LivenessProbe marklogicv1.ContainerProbe
160+ ReadinessProbe marklogicv1.ContainerProbe
161+ LogCollection * marklogicv1.LogCollection
162+ GroupConfig * marklogicv1.GroupConfig
163+ PodSecurityContext * corev1.PodSecurityContext
164+ SecurityContext * corev1.SecurityContext
165+ EnableConverters bool
166+ HugePages * marklogicv1.HugePages
167+ PathBasedRouting bool
168+ Tls * marklogicv1.Tls
169+ AdditionalVolumes * []corev1.Volume
170+ AdditionalVolumeMounts * []corev1.VolumeMount
171+ SecretName string
172+ }
173+
173174func (oc * OperatorContext ) ReconcileStatefulset () (reconcile.Result , error ) {
174175 cr := oc .GetMarkLogicServer ()
175176 logger := oc .ReqLogger
@@ -195,15 +196,44 @@ func (oc *OperatorContext) ReconcileStatefulset() (reconcile.Result, error) {
195196 oc .Recorder .Event (oc .MarklogicGroup , "Normal" , "StatefulSetCreated" , "MarkLogic statefulSet created successfully" )
196197 return result .Done ().Output ()
197198 }
198- _ , outputErr := result .Error (err ).Output ()
199- if outputErr != nil {
200- logger .Error (outputErr , "Failed to process result error" )
201- }
199+ logger .Error (err , "Cannot get statefulSet for MarkLogic" )
200+ return result .Error (err ).Output ()
202201 }
202+
203+ patchDiff , err := patch .DefaultPatchMaker .Calculate (currentSts , statefulSetDef ,
204+ patch .IgnoreStatusFields (),
205+ patch .IgnoreVolumeClaimTemplateTypeMetaAndStatus (),
206+ patch .IgnoreField ("kind" ))
207+ logger .Info ("Patch Diff:" , "Diff" , patchDiff .String ())
208+ logger .Info ("statefulSetDef Spec:" , "Spec" , statefulSetDef .Spec .Replicas )
203209 if err != nil {
204- logger .Error (err , "Cannot create standalone statefulSet for MarkLogic " )
210+ logger .Error (err , "Error calculating patch " )
205211 return result .Error (err ).Output ()
206212 }
213+
214+ if ! patchDiff .IsEmpty () {
215+ logger .Info ("MarkLogic statefulSet spec is different from the MarkLogicGroup spec, updating the statefulSet" )
216+ currentSts .Spec = statefulSetDef .Spec
217+ currentSts .ObjectMeta .Annotations = statefulSetDef .ObjectMeta .Annotations
218+ currentSts .ObjectMeta .Labels = statefulSetDef .ObjectMeta .Labels
219+ err := oc .Client .Update (oc .Ctx , currentSts )
220+ if err != nil {
221+ logger .Error (err , "Error updating statefulSet" )
222+ return result .Error (err ).Output ()
223+ }
224+ } else {
225+ logger .Info ("MarkLogic statefulSet spec is the same as the current spec, no update needed" )
226+ }
227+ logger .Info ("Operator Status:" , "Stage" , cr .Status .Stage )
228+ if cr .Status .Stage == "STS_CREATED" {
229+ logger .Info ("MarkLogic statefulSet created successfully, waiting for pods to be ready" )
230+ pods , err := GetPodsForStatefulSet (oc .Ctx , cr .Namespace , cr .Spec .Name )
231+ if err != nil {
232+ logger .Error (err , "Error getting pods for statefulset" )
233+ }
234+ logger .Info ("Pods in statefulSet: " , "Pods" , pods )
235+ }
236+
207237 patchClient := client .MergeFrom (oc .MarklogicGroup .DeepCopy ())
208238 updated := false
209239 if currentSts .Status .ReadyReplicas == 0 || currentSts .Status .ReadyReplicas != currentSts .Status .Replicas {
@@ -239,37 +269,6 @@ func (oc *OperatorContext) ReconcileStatefulset() (reconcile.Result, error) {
239269 }
240270 }
241271
242- patchDiff , err := patch .DefaultPatchMaker .Calculate (currentSts , statefulSetDef ,
243- patch .IgnoreStatusFields (),
244- patch .IgnoreVolumeClaimTemplateTypeMetaAndStatus (),
245- patch .IgnoreField ("kind" ))
246- if err != nil {
247- logger .Error (err , "Error calculating patch" )
248- return result .Error (err ).Output ()
249- }
250- if ! patchDiff .IsEmpty () {
251- logger .Info ("MarkLogic statefulSet spec is different from the MarkLogicGroup spec, updating the statefulSet" )
252- currentSts .Spec = statefulSetDef .Spec
253- currentSts .ObjectMeta .Annotations = statefulSetDef .ObjectMeta .Annotations
254- currentSts .ObjectMeta .Labels = statefulSetDef .ObjectMeta .Labels
255- err := oc .Client .Update (oc .Ctx , currentSts )
256- if err != nil {
257- logger .Error (err , "Error updating statefulSet" )
258- return result .Error (err ).Output ()
259- }
260- } else {
261- logger .Info ("MarkLogic statefulSet spec is the same as the current spec, no update needed" )
262- }
263- logger .Info ("Operator Status:" , "Stage" , cr .Status .Stage )
264- if cr .Status .Stage == "STS_CREATED" {
265- logger .Info ("MarkLogic statefulSet created successfully, waiting for pods to be ready" )
266- pods , err := GetPodsForStatefulSet (cr .Namespace , cr .Spec .Name )
267- if err != nil {
268- logger .Error (err , "Error getting pods for statefulset" )
269- }
270- logger .Info ("Pods in statefulSet: " , "Pods" , pods )
271- }
272-
273272 return result .Done ().Output ()
274273}
275274
@@ -287,7 +286,7 @@ func (oc *OperatorContext) setCondition(condition *metav1.Condition) bool {
287286func (oc * OperatorContext ) GetStatefulSet (namespace string , stateful string ) (* appsv1.StatefulSet , error ) {
288287 logger := oc .ReqLogger
289288 statefulInfo := & appsv1.StatefulSet {}
290- err := oc .Client .Get (context . TODO () , client.ObjectKey {Namespace : namespace , Name : stateful }, statefulInfo )
289+ err := oc .Client .Get (oc . Ctx , client.ObjectKey {Namespace : namespace , Name : stateful }, statefulInfo )
291290 if err != nil {
292291 logger .Info ("MarkLogic statefulSet get action failed" )
293292 return nil , err
@@ -298,7 +297,7 @@ func (oc *OperatorContext) GetStatefulSet(namespace string, stateful string) (*a
298297
299298func (oc * OperatorContext ) createStatefulSet (statefulset * appsv1.StatefulSet , cr * marklogicv1.MarklogicGroup ) error {
300299 logger := oc .ReqLogger
301- err := oc .Client .Create (context . TODO () , statefulset )
300+ err := oc .Client .Create (oc . Ctx , statefulset )
302301 if err != nil {
303302 logger .Error (err , "MarkLogic stateful creation failed" )
304303 return err
@@ -309,8 +308,8 @@ func (oc *OperatorContext) createStatefulSet(statefulset *appsv1.StatefulSet, cr
309308}
310309
311310func generateStatefulSetsDef (stsMeta metav1.ObjectMeta , params statefulSetParameters , ownerDef metav1.OwnerReference , containerParams containerParameters ) * appsv1.StatefulSet {
312- // Enforce default security contexts , merging with user-provided values
313- // User values take precedence, but defaults ensure minimum security standards
311+ // Enforce default pod security context , merging with user-provided values
312+ // This ensures all MarkLogic pods run with secure defaults
314313 podSecurityContext := mergePodSecurityContext (containerParams .PodSecurityContext , getDefaultPodSecurityContext ())
315314
316315 statefulSet := & appsv1.StatefulSet {
@@ -417,11 +416,11 @@ func generateStatefulSetsDef(stsMeta metav1.ObjectMeta, params statefulSetParame
417416 return statefulSet
418417}
419418
420- func GetPodsForStatefulSet (namespace , name string ) ([]corev1.Pod , error ) {
419+ func GetPodsForStatefulSet (ctx context. Context , namespace , name string ) ([]corev1.Pod , error ) {
421420 selector := fmt .Sprintf ("app.kubernetes.io/name=marklogic,app.kubernetes.io/instance=%s" , name )
422421 // List Pods with the label selector
423422 listOptions := metav1.ListOptions {LabelSelector : selector }
424- pods , err := GenerateK8sClient ().CoreV1 ().Pods (namespace ).List (context . TODO () , listOptions )
423+ pods , err := GenerateK8sClient ().CoreV1 ().Pods (namespace ).List (ctx , listOptions )
425424 if err != nil {
426425 return nil , err
427426 }
@@ -431,7 +430,7 @@ func GetPodsForStatefulSet(namespace, name string) ([]corev1.Pod, error) {
431430
432431func generateContainerDef (name string , containerParams containerParameters ) []corev1.Container {
433432 // Enforce default container security context, merging with user-provided values
434- // This ensures minimum security standards are always applied
433+ // This ensures all MarkLogic containers run with strict security settings
435434 securityContext := mergeSecurityContext (containerParams .SecurityContext , getDefaultContainerSecurityContext ())
436435
437436 containerDef := []corev1.Container {
0 commit comments