@@ -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