Skip to content

Commit 35bdb6a

Browse files
Merge pull request #83 from barkhachoithani/feature/CLD-706
CLD-706: Support upgradeStrategy for ML K8s
2 parents 1d42286 + 6f6085b commit 35bdb6a

File tree

7 files changed

+181
-5
lines changed

7 files changed

+181
-5
lines changed

Jenkinsfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ void pullImage() {
135135
sh """
136136
echo "\$docker_password" | docker login --username \$docker_user --password-stdin ${dockerRegistry}
137137
docker pull ${dockerRepository}:${dockerVersion}
138+
docker pull ${dockerRepository}:${dockerVersion}
139+
docker pull ${dockerRepository}:${prevDockerVersion}
138140
"""
139141
}
140142
}
@@ -169,14 +171,18 @@ pipeline {
169171
dockerRegistry = 'ml-docker-dev.marklogic.com'
170172
dockerRepository = "${dockerRegistry}/marklogic/marklogic-server-centos"
171173
dockerVerDivider = getVersionDiv(params.ML_VERSION)
174+
prevDockerVerDivider = getVersionDiv(params.PREV_ML_VERSION)
172175
dockerVersion = "${ML_VERSION}${dockerVerDivider}${timeStamp}-centos-${dockerReleaseVer}"
176+
prevDockerVersion = "${PREV_ML_VERSION}${prevDockerVerDivider}${timeStamp}-centos-${prevDockerReleaseVer}"
173177
}
174178

175179
parameters {
176180
string(name: 'emailList', defaultValue: emailList, description: 'List of email for build notification', trim: true)
177181
choice(name: 'ML_VERSION', choices: '11.0\n12.0\n10.0\n9.0', description: 'MarkLogic version. used to pick appropriate docker image')
178182
booleanParam(name: 'KUBERNETES_TESTS', defaultValue: true, description: 'Run kubernetes tests')
179183
string(name: 'dockerReleaseVer', defaultValue: '1.0.1', description: 'Current Docker version. (e.g. 1.0.1)', trim: true)
184+
choice(name: 'PREV_ML_VERSION', choices: '10.0\n9.0', description: 'Previous MarkLogic version for MarkLogic upgrade tests')
185+
string(name: 'prevDockerReleaseVer', defaultValue: '1.0.1', description: 'Previous Docker version for MarkLogic upgrade tests. (e.g. 1.0.1)', trim: true)
180186
}
181187

182188
stages {
@@ -205,7 +211,7 @@ pipeline {
205211
steps {
206212
sh """
207213
export MINIKUBE_HOME=/space;
208-
make test dockerImage=${dockerRepository}:${dockerVersion} saveOutput=true
214+
make test dockerImage=${dockerRepository}:${dockerVersion} prevDockerImage=${dockerRepository}:${prevDockerVersion} saveOutput=true
209215
"""
210216
}
211217
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ This table describes the list of available parameters for Helm Chart.
516516
| `networkPolicy.customRules` | Placeholder to specify selectors | `{}` |
517517
| `networkPolicy.ports` | Ports to which traffic is allowed | `[8000, 8001, 8002]` |
518518
| `priorityClassName` | Name of a PriortyClass defined to set pod priority | `""` |
519+
| `updateStrategy` | Update strategy for helm chart and app version updates | `OnDelete` |
519520

520521
# Known Issues and Limitations
521522

charts/templates/statefulset.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ metadata:
88
spec:
99
serviceName: {{ include "marklogic.headlessServiceName" . }}
1010
replicas: {{ .Values.replicaCount }}
11+
updateStrategy:
12+
type: {{ .Values.updateStrategy.type }}
1113
selector:
1214
matchLabels:
1315
{{- include "marklogic.selectorLabels" . | nindent 6 }}

charts/values.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
# Number of Marklogic nodes
44
replicaCount: 1
55

6+
# update strategy for MarkLogic and Helm chart upgrades
7+
# It is recommended to use OnDelete updateStrategy as MarkLogic bootstrap host (pod-0) needs to be upgraded first in the cluster
8+
# and onDelete allows more control over the upgrade and recovery in case of failure.
9+
updateStrategy:
10+
type: OnDelete
11+
612
# Termination Grace Period
713
terminationGracePeriod: 120
814

makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
dockerImage?=marklogic-centos/marklogic-server-centos:10-internal
2-
1+
dockerImage?=ml-docker-dev.marklogic.com/marklogic/marklogic-server-centos:11.0.20230307-centos-1.0.2
2+
prevDockerImage?=ml-docker-dev.marklogic.com/marklogic/marklogic-server-centos:10.0-20230307-centos-1.0.2
33
## System requirement:
44
## - Go
55
## - gotestsum (if you want to enable saveOutput for testing commands)
@@ -80,6 +80,7 @@ lint:
8080
## Run all end to end tests
8181
## Options:
8282
## * [dockerImage] optional. default is marklogicdb/marklogic-db:latest. Example: dockerImage=marklogic-centos/marklogic-server-centos:10-internal
83+
## * [prevDockerImage] optional. used for marklogic upgrade tests
8384
## * [saveOutput] optional. Save the output to a xml file. Example: saveOutput=true
8485
.PHONY: e2e-test
8586
e2e-test: prepare
@@ -92,6 +93,9 @@ lint:
9293
@echo "=====Loading marklogc image $(dockerImage) to minikube cluster"
9394
minikube image load $(dockerImage)
9495

96+
@echo "=====Loading marklogc image $(prevDockerImage) to minikube cluster"
97+
minikube image load $(prevDockerImage)
98+
9599
@echo "=====Running e2e tests"
96100
$(if $(saveOutput),gotestsum --junitfile test/test_results/e2e-tests.xml ./test/e2e/... -count=1 -timeout 30m, go test -v -count=1 -timeout 30m ./test/e2e/...)
97101

test/e2e/upgrade_test.go

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package e2e
33
import (
44
"crypto/tls"
55
"fmt"
6+
"io/ioutil"
67
"os"
78
"path/filepath"
89
"strings"
@@ -14,6 +15,8 @@ import (
1415
"github.com/gruntwork-io/terratest/modules/k8s"
1516
"github.com/gruntwork-io/terratest/modules/random"
1617
"github.com/stretchr/testify/assert"
18+
"github.com/tidwall/gjson"
19+
digestAuth "github.com/xinsnake/go-http-digest-auth-client"
1720
)
1821

1922
func TestHelmUpgrade(t *testing.T) {
@@ -26,12 +29,12 @@ func TestHelmUpgrade(t *testing.T) {
2629
imageTag, tagPres := os.LookupEnv("dockerVersion")
2730

2831
if !repoPres {
29-
imageRepo = "marklogic-centos/marklogic-server-centos"
32+
imageRepo = "ml-docker-dev.marklogic.com/marklogic/marklogic-server-centos"
3033
t.Logf("No imageRepo variable present, setting to default value: " + imageRepo)
3134
}
3235

3336
if !tagPres {
34-
imageTag = "10-internal"
37+
imageTag = "11.0.20230307-centos-1.0.2"
3538
t.Logf("No imageTag variable present, setting to default value: " + imageTag)
3639
}
3740

@@ -106,3 +109,104 @@ func TestHelmUpgrade(t *testing.T) {
106109
passwordAfterUpgrade := string(passwordArr[:])
107110
assert.Equal(t, passwordAfterUpgrade, passwordAfterInstall)
108111
}
112+
113+
func TestMLupgrade(t *testing.T) {
114+
// Path to the helm chart we will test
115+
helmChartPath, e := filepath.Abs("../../charts")
116+
if e != nil {
117+
t.Fatalf(e.Error())
118+
}
119+
imageRepo, repoPres := os.LookupEnv("dockerRepository")
120+
imageTag, tagPres := os.LookupEnv("dockerVersion")
121+
prevImageTag, prevTagPres := os.LookupEnv("dockerVersion")
122+
123+
if !repoPres {
124+
imageRepo = "ml-docker-dev.marklogic.com/marklogic/marklogic-server-centos"
125+
t.Logf("No imageRepo variable present, setting to default value: " + imageRepo)
126+
}
127+
if !tagPres {
128+
imageTag = "11.0.20230307-centos-1.0.2"
129+
t.Logf("No imageTag variable present, setting to default value: " + imageTag)
130+
}
131+
if !prevTagPres {
132+
prevImageTag = "10.0-20230307-centos-1.0.2"
133+
t.Logf("No imageTag variable present, setting to default value: " + prevImageTag)
134+
}
135+
136+
username := "admin"
137+
password := "admin"
138+
139+
namespaceName := "marklogic-" + strings.ToLower(random.UniqueId())
140+
kubectlOptions := k8s.NewKubectlOptions("", "", namespaceName)
141+
options := &helm.Options{
142+
KubectlOptions: kubectlOptions,
143+
SetValues: map[string]string{
144+
"persistence.enabled": "false",
145+
"replicaCount": "1",
146+
"updateStrategy.type": "OnDelete",
147+
"image.repository": imageRepo,
148+
"image.tag": prevImageTag,
149+
"auth.adminUsername": username,
150+
"auth.adminPassword": password,
151+
},
152+
}
153+
154+
t.Logf("====Creating namespace: " + namespaceName)
155+
k8s.CreateNamespace(t, kubectlOptions, namespaceName)
156+
defer t.Logf("====Deleting namespace: " + namespaceName)
157+
defer k8s.DeleteNamespace(t, kubectlOptions, namespaceName)
158+
159+
t.Logf("====Installing Helm Chart")
160+
releaseName := "test-ml-upgrade"
161+
helm.Install(t, options, helmChartPath, releaseName)
162+
163+
podName := releaseName + "-marklogic-0"
164+
165+
// wait until second pod is in Ready status
166+
k8s.WaitUntilPodAvailable(t, kubectlOptions, podName, 20, 20*time.Second)
167+
168+
k8s.RunKubectl(t, kubectlOptions, "describe", "pod", podName)
169+
170+
newOptions := &helm.Options{
171+
KubectlOptions: kubectlOptions,
172+
SetValues: map[string]string{
173+
"persistence.enabled": "false",
174+
"image.repository": imageRepo,
175+
"image.tag": imageTag,
176+
"logCollection.enabled": "false",
177+
},
178+
}
179+
180+
t.Logf("====Upgrading Helm Chart")
181+
helm.Upgrade(t, newOptions, helmChartPath, releaseName)
182+
183+
// delete pods to allow upgrades
184+
k8s.RunKubectl(t, kubectlOptions, "delete", "pod", podName)
185+
186+
// wait until pod is in Ready status with new configuration
187+
k8s.WaitUntilPodAvailable(t, kubectlOptions, podName, 15, 30*time.Second)
188+
189+
tunnel := k8s.NewTunnel(
190+
kubectlOptions, k8s.ResourceTypePod, podName, 8002, 8002)
191+
defer tunnel.Close()
192+
tunnel.ForwardPort(t)
193+
194+
clusterEndpoint := fmt.Sprintf("http://%s/manage/v2?format=json", tunnel.Endpoint())
195+
t.Logf(`Endpoint: %s`, clusterEndpoint)
196+
197+
getMLversion := digestAuth.NewRequest(username, password, "GET", clusterEndpoint, "")
198+
199+
resp, err := getMLversion.Execute()
200+
if err != nil {
201+
t.Fatalf(err.Error())
202+
}
203+
defer resp.Body.Close()
204+
body, err := ioutil.ReadAll(resp.Body)
205+
if err != nil {
206+
t.Fatalf(err.Error())
207+
}
208+
mlVersion := gjson.Get(string(body), `local-cluster-default.version`)
209+
expectedMlVersion := strings.Split(imageTag, "-centos")[0]
210+
// verify latest MarkLogic version after upgrade
211+
assert.Equal(t, mlVersion.Str, expectedMlVersion)
212+
}

test/template/upgrade_templ_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package template_test
2+
3+
import (
4+
"path/filepath"
5+
"strings"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
appsv1 "k8s.io/api/apps/v1"
10+
11+
"github.com/gruntwork-io/terratest/modules/helm"
12+
"github.com/gruntwork-io/terratest/modules/k8s"
13+
"github.com/gruntwork-io/terratest/modules/random"
14+
)
15+
16+
func TestChartTemplateUpgradeStrategy(t *testing.T) {
17+
t.Parallel()
18+
19+
// Path to the helm chart we will test
20+
helmChartPath, err := filepath.Abs("../../charts")
21+
releaseName := "marklogic-upgrade-test"
22+
t.Log(helmChartPath, releaseName)
23+
require.NoError(t, err)
24+
25+
// Set up the namespace; confirm that the template renders the expected value for the namespace.
26+
namespaceName := "marklogic-" + strings.ToLower(random.UniqueId())
27+
t.Logf("Namespace: %s\n", namespaceName)
28+
29+
// Setup the args for helm install
30+
options := &helm.Options{
31+
SetValues: map[string]string{
32+
"image.repository": "marklogicdb/marklogic-db",
33+
"image.tag": "latest",
34+
"persistence.enabled": "false",
35+
"updateStrategy.type": "RollingUpdate",
36+
},
37+
KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName),
38+
}
39+
40+
// render the tempate
41+
output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/statefulset.yaml"})
42+
43+
var statefulset appsv1.StatefulSet
44+
helm.UnmarshalK8SYaml(t, output, &statefulset)
45+
46+
// Verify the name and namespace matches
47+
require.Equal(t, namespaceName, statefulset.Namespace)
48+
49+
// Verify the updateStrategy type set for upgrade
50+
expectedUpgradeStrategy := "RollingUpdate"
51+
actualUpgradeStrategy := statefulset.Spec.UpdateStrategy.Type
52+
require.Equal(t, string(actualUpgradeStrategy), expectedUpgradeStrategy)
53+
}

0 commit comments

Comments
 (0)