Skip to content

MLE-20428: add labels and annotation in group level #82

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jun 24, 2025
Merged
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
4 changes: 3 additions & 1 deletion api/v1/marklogiccluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ type MarklogicGroups struct {
// +kubebuilder:default:=1
Replicas *int32 `json:"replicas,omitempty"`
// +kubebuilder:validation:Required
Name string `json:"name,omitempty"`
Name string `json:"name,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
// +kubebuilder:default:={name: "Default", enableXdqpSsl: true}
GroupConfig *GroupConfig `json:"groupConfig,omitempty"`
Image string `json:"image,omitempty"`
Expand Down
6 changes: 4 additions & 2 deletions api/v1/marklogicgroup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ import (
// MarklogicGroupSpec defines the desired state of MarklogicGroup
type MarklogicGroupSpec struct {
// +kubebuilder:default:=1
Replicas *int32 `json:"replicas,omitempty"`
Name string `json:"name,omitempty"`
Replicas *int32 `json:"replicas,omitempty"`
Name string `json:"name,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
// +kubebuilder:default:="cluster.local"
ClusterDomain string `json:"clusterDomain,omitempty"`
// +kubebuilder:default:="progressofficial/marklogic-db:11.3.0-ubi-rootless"
Expand Down
28 changes: 28 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -7965,6 +7965,10 @@ spec:
x-kubernetes-list-type: atomic
type: object
type: object
annotations:
additionalProperties:
type: string
type: object
groupConfig:
default:
enableXdqpSsl: true
Expand Down Expand Up @@ -9331,6 +9335,10 @@ spec:
isBootstrap:
default: false
type: boolean
labels:
additionalProperties:
type: string
type: object
logCollection:
properties:
enabled:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3243,6 +3243,10 @@ spec:
x-kubernetes-list-type: atomic
type: object
type: object
annotations:
additionalProperties:
type: string
type: object
auth:
properties:
adminPassword:
Expand Down Expand Up @@ -3310,6 +3314,10 @@ spec:
type: object
x-kubernetes-map-type: atomic
type: array
labels:
additionalProperties:
type: string
type: object
license:
properties:
key:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7987,6 +7987,10 @@ spec:
x-kubernetes-list-type: atomic
type: object
type: object
annotations:
additionalProperties:
type: string
type: object
groupConfig:
default:
enableXdqpSsl: true
Expand Down Expand Up @@ -9356,6 +9360,10 @@ spec:
isBootstrap:
default: false
type: boolean
labels:
additionalProperties:
type: string
type: object
logCollection:
properties:
enabled:
Expand Down
8 changes: 8 additions & 0 deletions config/crd/bases/marklogic.progress.com_marklogicgroups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3250,6 +3250,10 @@ spec:
x-kubernetes-list-type: atomic
type: object
type: object
annotations:
additionalProperties:
type: string
type: object
auth:
properties:
adminPassword:
Expand Down Expand Up @@ -3317,6 +3321,10 @@ spec:
type: object
x-kubernetes-map-type: atomic
type: array
labels:
additionalProperties:
type: string
type: object
license:
properties:
key:
Expand Down
4 changes: 4 additions & 0 deletions config/samples/complete.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ spec:
# additionalVolumeClaimTemplates: []
markLogicGroups:
- name: dnode
labels:
group-level-label: "group-level-label"
annotations:
group-level-annotation: "group-level-annotation"
replicas: 3
groupConfig:
name: dnode
Expand Down
48 changes: 48 additions & 0 deletions internal/controller/marklogiccluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ import (
"github.com/go-logr/logr"
marklogicv1 "github.com/marklogic/marklogic-operator-kubernetes/api/v1"
"github.com/marklogic/marklogic-operator-kubernetes/pkg/k8sutil"
"reflect"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
)

// MarklogicClusterReconciler reconciles a MarklogicCluster object
Expand Down Expand Up @@ -81,10 +84,55 @@ func (r *MarklogicClusterReconciler) Reconcile(ctx context.Context, req ctrl.Req
return result, nil
}

func markLogicClusterCreateUpdateDeletePredicate() predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return true // Reconcile on create
},
UpdateFunc: func(e event.UpdateEvent) bool {
switch e.ObjectNew.(type) {
case *marklogicv1.MarklogicCluster:
oldAnnotations := e.ObjectOld.GetAnnotations()
newAnnotations := e.ObjectNew.GetAnnotations()
delete(newAnnotations, "banzaicloud.com/last-applied")
delete(oldAnnotations, "banzaicloud.com/last-applied")
delete(newAnnotations, "kubectl.kubernetes.io/last-applied-configuration")
delete(oldAnnotations, "kubectl.kubernetes.io/last-applied-configuration")
if !reflect.DeepEqual(oldAnnotations, newAnnotations) {
return true // Reconcile if annotations have changed
}
oldLables := e.ObjectOld.GetLabels()
newLabels := e.ObjectNew.GetLabels()
if !reflect.DeepEqual(oldLables, newLabels) {
return true // Reconcile if labels have changed
}
// If annotations and labels are the same, check if the spec has changed
oldObj := e.ObjectOld.(*marklogicv1.MarklogicCluster)
// Check if the spec has changed
newObj := e.ObjectNew.(*marklogicv1.MarklogicCluster)
if !reflect.DeepEqual(oldObj.Spec, newObj.Spec) {
return true // Reconcile if spec has changed
}
default:
return false // Ignore updates for other types
}
return false // Reconcile on update of MarklogicCluster

},
DeleteFunc: func(e event.DeleteEvent) bool {
return true // Reconcile on delete
},
GenericFunc: func(e event.GenericEvent) bool {
return false // Ignore generic events (optional)
},
}
}

// SetupWithManager sets up the controller with the Manager.
func (r *MarklogicClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&marklogicv1.MarklogicCluster{}).
WithEventFilter(markLogicClusterCreateUpdateDeletePredicate()).
Owns(&marklogicv1.MarklogicGroup{}).
Complete(r)
}
61 changes: 57 additions & 4 deletions internal/controller/marklogicgroup_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@ package controller
import (
"context"

"github.com/go-logr/logr"
marklogicv1 "github.com/marklogic/marklogic-operator-kubernetes/api/v1"
"github.com/marklogic/marklogic-operator-kubernetes/pkg/k8sutil"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/record"
"reflect"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/log"

"github.com/go-logr/logr"
marklogicv1 "github.com/marklogic/marklogic-operator-kubernetes/api/v1"
"github.com/marklogic/marklogic-operator-kubernetes/pkg/k8sutil"
"sigs.k8s.io/controller-runtime/pkg/predicate"
)

// MarklogicGroupReconciler reconciles a MarklogicGroup object
Expand Down Expand Up @@ -94,12 +96,63 @@ func (r *MarklogicGroupReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return result, nil
}

func markLogicGroupCreateUpdateDeletePredicate() predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return true // Reconcile on create
},
UpdateFunc: func(e event.UpdateEvent) bool {
switch e.ObjectNew.(type) {
case *marklogicv1.MarklogicGroup:
oldAnnotations := e.ObjectOld.GetAnnotations()
newAnnotations := e.ObjectNew.GetAnnotations()
delete(newAnnotations, "banzaicloud.com/last-applied")
Copy link
Preview

Copilot AI Jun 23, 2025

Choose a reason for hiding this comment

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

You're mutating the event object's annotation map directly. Clone the annotations map before deleting keys to avoid side effects on the cached resource.

Copilot uses AI. Check for mistakes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@pengzhouml : Could you check this ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is on purpose, I do not want This annotation passed down.

delete(oldAnnotations, "banzaicloud.com/last-applied")
delete(newAnnotations, "kubectl.kubernetes.io/last-applied-configuration")
delete(oldAnnotations, "kubectl.kubernetes.io/last-applied-configuration")
if !reflect.DeepEqual(oldAnnotations, newAnnotations) {
return true // Reconcile if annotations have changed
}
oldLables := e.ObjectOld.GetLabels()
newLabels := e.ObjectNew.GetLabels()
if !reflect.DeepEqual(oldLables, newLabels) {
return true // Reconcile if labels have changed
}
oldObj := e.ObjectOld.(*marklogicv1.MarklogicGroup)
newObj := e.ObjectNew.(*marklogicv1.MarklogicGroup)
if !reflect.DeepEqual(oldObj.Spec, newObj.Spec) {
return true // Reconcile if the spec has changed
}
return false
case *appsv1.StatefulSet:
return true // Reconcile on update of StatefulSet
case *corev1.Service:
oldObj := e.ObjectOld.(*corev1.Service)
newObj := e.ObjectNew.(*corev1.Service)
if !reflect.DeepEqual(oldObj.Spec, newObj.Spec) {
return true // Reconcile if the spec has changed
}
return false // Reconcile on update of Service
default:
return false // Ignore updates for other types
}
},
DeleteFunc: func(e event.DeleteEvent) bool {
return true // Reconcile on delete
},
GenericFunc: func(e event.GenericEvent) bool {
return false // Ignore generic events (optional)
},
}
}

// SetupWithManager sets up the controller with the Manager.
func (r *MarklogicGroupReconciler) SetupWithManager(mgr ctrl.Manager) error {

builder := ctrl.NewControllerManagedBy(mgr).
Named("marklogicgroup-controller").
For(&marklogicv1.MarklogicGroup{}).
WithEventFilter(markLogicGroupCreateUpdateDeletePredicate()).
Owns(&appsv1.StatefulSet{}).
Owns(&corev1.Service{})

Expand Down
29 changes: 29 additions & 0 deletions pkg/k8sutil/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func SetCommonLabels(labels map[string]string) {
}

func SetCommonAnnotations(annotations map[string]string) {
delete(annotations, "kubectl.kubernetes.io/last-applied-configuration")
CustomAnnotations = annotations
}

Expand All @@ -67,6 +68,34 @@ func getSelectorLabels(name string) map[string]string {
return selectorLabels
}

func getHAProxySelectorLabels(name string) map[string]string {
selectorLabels := map[string]string{
"app.kubernetes.io/name": "marklogic",
"app.kubernetes.io/instance": name,
"app.kubernetes.io/managed-by": "marklogic-operator",
"app.kubernetes.io/component": "haproxy",
}
return selectorLabels
}

func getHAProxyLabels(name string) map[string]string {
defaultHaproxyLabels := getHAProxySelectorLabels(name)
mergedLabels := map[string]string{}
if len(CustomLabels) > 0 {
for k, v := range defaultHaproxyLabels {
mergedLabels[k] = v
}
for k, v := range CustomLabels {
if _, ok := defaultHaproxyLabels[k]; !ok {
mergedLabels[k] = v
}
}
} else {
return defaultHaproxyLabels
}
return mergedLabels
}

func getCommonLabels(name string) map[string]string {
defaultLabels := getSelectorLabels(name)
mergedLabels := map[string]string{}
Expand Down
Loading