Skip to content
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
3 changes: 2 additions & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ pipeline {
// }

parameters {
string(name: 'dockerImage', defaultValue: 'ml-docker-db-dev-tierpoint.bed-artifactory.bedford.progress.com/marklogic/marklogic-server-ubi:latest-11', description: 'Docker image to use for tests.', trim: true)
string(name: 'E2E_MARKLOGIC_IMAGE_VERSION', defaultValue: 'ml-docker-db-dev-tierpoint.bed-artifactory.bedford.progress.com/marklogic/marklogic-server-ubi-rootless:latest-12', description: 'Docker image to use for tests.', trim: true)
string(name: 'IMG', defaultValue: 'testrepo/marklogic-operator-image-dev:internal', description: 'Docker image for Running Operator Container', trim: true)
string(name: 'emailList', defaultValue: emailList, description: 'List of email for build notification', trim: true)
}

Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ VERIFY_HUGE_PAGES ?= false
export E2E_DOCKER_IMAGE ?= $(IMG)
export E2E_KUSTOMIZE_VERSION ?= $(KUSTOMIZE_VERSION)
export E2E_CONTROLLER_TOOLS_VERSION ?= $(CONTROLLER_TOOLS_VERSION)
export E2E_MARKLOGIC_IMAGE_VERSION ?= progressofficial/marklogic-db:11.3.1-ubi-rootless-2.1.0
export E2E_MARKLOGIC_IMAGE_VERSION ?= progressofficial/marklogic-db:11.3.1-ubi-rootless-2.1.3
export E2E_KUBERNETES_VERSION ?= v1.31.0

# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
Expand Down Expand Up @@ -65,7 +65,8 @@ OPERATOR_SDK_VERSION ?= v1.34.2

# Image URL to use all building/pushing image targets
# Image for dev: ml-marklogic-operator-dev.bed-artifactory.bedford.progress.com/marklogic-operator-kubernetes
IMG ?= progressofficial/marklogic-operator-kubernetes:$(VERSION)
# IMG ?= progressofficial/marklogic-operator-kubernetes:$(VERSION)
IMG = "testrepo/marklogic-operator-image-dev:1.0.0"


# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
Expand Down Expand Up @@ -162,6 +163,9 @@ e2e-setup-minikube: kustomize controller-gen build docker-build
minikube start --driver=docker --kubernetes-version=$(E2E_KUBERNETES_VERSION) --memory=8192 --cpus=2
minikube addons enable ingress
minikube image load $(IMG)
minikube image load $(E2E_MARKLOGIC_IMAGE_VERSION)
minikube image load "docker.io/haproxytech/haproxy-alpine:3.2"
minikube image ls

.PHONY: e2e-cleanup-minikube
e2e-cleanup-minikube:
Expand Down
2 changes: 1 addition & 1 deletion api/v1/marklogiccluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

// MarklogicClusterSpec defines the desired state of MarklogicCluster

// +kubebuilder:validation:XValidation:rule="!(self.haproxy.enabled == true && self.haproxy.pathBasedRouting == true) || int(self.image.split(':')[1].split('.')[0] + self.image.split(':')[1].split('.')[1]) >= 111", message="HAProxy and Pathbased Routing is enabled. PathBasedRouting is only supported for MarkLogic 11.1 and above"
// +kubebuilder:validation:XValidation:rule="!(self.haproxy.enabled == true && self.haproxy.pathBasedRouting == true) || self.image.split(':')[1].matches('.*latest.*') || int(self.image.split(':')[1].split('.')[0] + self.image.split(':')[1].split('.')[1]) >= 111", message="HAProxy and Pathbased Routing is enabled. PathBasedRouting is only supported for MarkLogic 11.1 and above"
type MarklogicClusterSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11037,7 +11037,8 @@ spec:
- message: HAProxy and Pathbased Routing is enabled. PathBasedRouting
is only supported for MarkLogic 11.1 and above
rule: '!(self.haproxy.enabled == true && self.haproxy.pathBasedRouting
== true) || int(self.image.split('':'')[1].split(''.'')[0] + self.image.split('':'')[1].split(''.'')[1])
== true) || self.image.split('':'')[1].matches(''.*latest.*'') ||
int(self.image.split('':'')[1].split(''.'')[0] + self.image.split('':'')[1].split(''.'')[1])
>= 111'
status:
description: MarklogicClusterStatus defines the observed state of MarklogicCluster
Expand Down
31 changes: 0 additions & 31 deletions pkg/k8sutil/scripts/liveness-probe.sh

This file was deleted.

23 changes: 21 additions & 2 deletions pkg/k8sutil/scripts/poststart-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,25 @@ log () {
echo $message >> /tmp/script.log
}

# Function to retry a command based on the return code
# $1: The number of retries
# $2: The command to run
retry() {
local retries=$1
shift
local count=0
until "$@"; do
exit_code=$?
count=$((count + 1))
if [ $count -ge $retries ]; then
echo "Command failed after $retries attempts."
return $exit_code
fi
echo "Attempt $count failed. Retrying..."
Comment on lines +67 to +70
Copy link

Copilot AI Jul 8, 2025

Choose a reason for hiding this comment

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

[nitpick] Use the existing log function instead of echo so retries are recorded in the pod log and /tmp/script.log.

Suggested change
echo "Command failed after $retries attempts."
return $exit_code
fi
echo "Attempt $count failed. Retrying..."
log "Error" "Command failed after $retries attempts."
return $exit_code
fi
log "Info" "Attempt $count failed. Retrying..."

Copilot uses AI. Check for mistakes.

Copy link

Copilot AI Jul 8, 2025

Choose a reason for hiding this comment

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

[nitpick] Replace this echo with the log helper to ensure consistent logging with timestamps and PID handling.

Suggested change
echo "Attempt $count failed. Retrying..."
info "Attempt $count failed. Retrying..."

Copilot uses AI. Check for mistakes.

sleep 5
done
}

###############################################################
# Function to get the current host protocol
# $1: The host name
Expand Down Expand Up @@ -699,10 +718,10 @@ if [[ "$IS_BOOTSTRAP_HOST" == "true" ]]; then
if [[ "${MARKLOGIC_CLUSTER_TYPE}" == "bootstrap" ]]; then
log "Info: bootstrap host is ready"
init_security_db
configure_group
retry 5 configure_group
else
log "Info: bootstrap host is ready"
configure_group
retry 5 configure_group
join_cluster $HOST_FQDN
fi
configure_path_based_routing
Expand Down
7 changes: 5 additions & 2 deletions pkg/k8sutil/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,8 +696,11 @@ func getLivenessProbe(probe marklogicv1.ContainerProbe) *corev1.Probe {
TimeoutSeconds: probe.TimeoutSeconds,
SuccessThreshold: probe.SuccessThreshold,
ProbeHandler: corev1.ProbeHandler{
Exec: &corev1.ExecAction{
Command: []string{"/bin/bash", "/tmp/helm-scripts/liveness-probe.sh"},
TCPSocket: &corev1.TCPSocketAction{
Port: intstr.IntOrString{
Type: intstr.Int,
IntVal: 8001,
},
},
},
}
Expand Down
15 changes: 11 additions & 4 deletions test/e2e/2_marklogic_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,17 @@ func TestMarklogicCluster(t *testing.T) {
if err != nil {
t.Fatalf("Failed to install grafana helm chart: %v", err)
}

// Wait for Grafana pod to be ready
time.Sleep(5 * time.Second) // Give some time for Grafana to start
podList := &corev1.PodList{}
if err := client.Resources().List(ctx, podList, func(lo *metav1.ListOptions) {
lo.FieldSelector = "metadata.namespace=" + "grafana"
}); err != nil {
t.Fatal(err)
}

if len(podList.Items) == 0 {
t.Fatal("No Grafana pods found")
}
grafanaPodName := podList.Items[0].Name
err = utils.WaitForPod(ctx, t, client, "grafana", grafanaPodName, 120*time.Second)
if err != nil {
Expand Down Expand Up @@ -228,7 +231,7 @@ func TestMarklogicCluster(t *testing.T) {
client := c.Client()

podName := "node-0"
err := utils.WaitForPod(ctx, t, client, mlNamespace, podName, 180*time.Second)
err := utils.WaitForPod(ctx, t, client, mlNamespace, podName, 240*time.Second)
if err != nil {
t.Fatalf("Failed to wait for pod creation: %v", err)
}
Expand All @@ -245,6 +248,10 @@ func TestMarklogicCluster(t *testing.T) {
}); err != nil {
t.Fatal(err)
}
time.Sleep(5 * time.Second) // Wait for Grafana to be fully ready
if len(podList.Items) == 0 {
t.Fatal("No Grafana pods found")
}
grafanaPodName := podList.Items[0].Name
grafanaAdminUser, grafanaAdminPassword, err := utils.GetSecretData(ctx, client, "grafana", "grafana", "admin-user", "admin-password")
if err != nil {
Expand Down Expand Up @@ -337,7 +344,7 @@ func TestMarklogicCluster(t *testing.T) {
if err := client.Resources().Get(ctx, "marklogicclusters", mlNamespace, &mlcluster); err != nil {
t.Fatal(err)
}

mlcluster.Spec.MarkLogicGroups[0].Resources = &resources
if err := client.Resources().Update(ctx, &mlcluster); err != nil {
t.Log("Failed to update MarkLogic group resources")
Expand Down
7 changes: 7 additions & 0 deletions test/e2e/4_tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ func TestTlsWithNamedCert(t *testing.T) {
}
certURIs := gjson.Get(certs, `certificate-default-list.list-items.list-item.#.uriref`).Array()
t.Log("Certificates URL list", certURIs)
if len(certURIs) < 2 {
t.Fatalf("Expected at least 2 certificates, found %d", len(certURIs))
}
cert0Url := fmt.Sprintf("https://localhost:8002%s?format=json", certURIs[0])
cert1Url := fmt.Sprintf("https://localhost:8002%s?format=json", certURIs[1])
command = fmt.Sprintf("curl -k --anyauth -u %s:%s %s", adminUsername, adminPassword, cert0Url)
Expand Down Expand Up @@ -404,8 +407,12 @@ func TestTlsWithMultiNode(t *testing.T) {
if err != nil {
t.Fatalf("Failed to get certificates list: %v", err)
}
t.Log("Certificates list", certs)
certURIs := gjson.Get(certs, `certificate-default-list.list-items.list-item.#.uriref`).Array()
t.Log("Dnode Cert Url", certURIs)
if len(certURIs) < 2 {
t.Fatalf("Expected at least 2 certificates, found %d", len(certURIs))
}
cert0Url := fmt.Sprintf("https://localhost:8002%s?format=json", certURIs[0])
cert1Url := fmt.Sprintf("https://localhost:8002%s?format=json", certURIs[1])
command = fmt.Sprintf("curl -k --anyauth -u %s:%s %s", adminUsername, adminPassword, cert0Url)
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ func TestMain(m *testing.M) {
log.Println("Deploying controller-manager resources...")
p := utils.RunCommand(`kubectl version`)
log.Printf("Output of kubectl: %s", p.Result())
p = utils.RunCommand(`bash -c "kustomize build config/default | kubectl apply --server-side -f -"`)
log.Printf("Output: %s", p.Result())
p = utils.RunCommand(`make deploy`)
log.Printf("Output of make deploy: %s", p.Result())
if p.Err() != nil {
log.Printf("Failed to deploy resource configurations: %s: %s", p.Err(), p.Result())
return ctx, p.Err()
Expand Down
3 changes: 3 additions & 0 deletions test/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ func WaitForPod(ctx context.Context, t *testing.T, client klient.Client, namespa
pod := &corev1.Pod{}
p := utils.RunCommand(`kubectl get ns`)
t.Logf("Kubernetes namespace: %s", p.Result())
p = utils.RunCommand("kubectl get pods --namespace " + "marklogic-operator-system" + " -o wide")
t.Logf("Kubernetes Operator Running Status: %s", p.Result())

for {
t.Logf("Waiting for pod %s in namespace %s ", podName, namespace)
p := utils.RunCommand("kubectl get pods --namespace " + namespace)
Expand Down