Skip to content

Commit e5534ca

Browse files
enyachokerbuisson
andauthored
INFRA-427: Add a new deployment type to accommodate the new Ozone packaging (#42)
* INFRA-427: Add a new deployment type to accommodate the new Ozone packaging * Allow cd to legacy docker compose folder * Add legacy Spec * Update review * Remove debug * Rename project type * Update JS doc for DockerComposeFromArtifactDeployment * Fix typo --------- Co-authored-by: Romain Buisson <[email protected]>
1 parent 896ca15 commit e5534ca

File tree

11 files changed

+583
-24
lines changed

11 files changed

+583
-24
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ That is because the bulk of the logic of what OCD3 does lives here. Almost all J
216216
217217
This is how one would build the underlying Node JS scripts:
218218
```bash
219-
gradle node-scripts:build
219+
./gradlew node-scripts:build
220220
```
221221
And this must be done before submitting code commits.
222222
However note that the code base is not really built into anything since the container links directly to **/node-scripts**, but this formats the code and runs the test suite.
@@ -231,7 +231,7 @@ See [here](readme/docker/README.md).
231231
OCD3 not only needs a Docker image for its binaries but also requires a 'Jenkins home' folder that provides a pre-configured Jenkins setup:
232232

233233
```bash
234-
gradle jenkins:build
234+
./gradlew jenkins:build
235235
```
236236
This will package a zip archive of the jenkins folder.
237237

docker/Dockerfile

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
ARG VERSION=2.346.3
1+
ARG VERSION=2.387.3
22
FROM jenkins/jenkins:$VERSION
33
MAINTAINER Mekom Solutions <[email protected]>
44

55
USER root
66

7-
# Add the APP_DATA_DIR volume to keep OpenMRS CD data out of the Jenkins Home
8-
ARG APP_DATA_DIR="/var/lib/openmrs_cd/app_data"
9-
RUN mkdir -p $APP_DATA_DIR && chown -R jenkins:jenkins $APP_DATA_DIR
10-
117
RUN apt update --fix-missing
128
RUN apt -y install nano jq openssh-server rsync libxml2-utils
139

@@ -22,6 +18,10 @@ RUN sudo apt install -y nodejs
2218
# Jenkins needs to be a sudo to execute some build tasks (particularly Bahmni Apps)
2319
RUN echo "jenkins ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
2420

21+
# Add the APP_DATA_DIR volume to keep OpenMRS CD data out of the Jenkins Home
22+
ARG APP_DATA_DIR="/var/lib/openmrs_cd/app_data"
23+
RUN mkdir -p $APP_DATA_DIR && chown -R jenkins:jenkins $APP_DATA_DIR
24+
2525
# Provide access to the /usr/share/jenkins directory
2626
RUN chown -R jenkins /usr/share/jenkins
2727

docker/build.gradle

+7-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@ repositories {
2020

2121
def dockerHubRepo = "mekomsolutions/openmrscd"
2222
def getShortCommit() {
23-
return ['sh', '-c', 'git log -1 --format=%h'].execute().text.trim()
23+
def stdout = new ByteArrayOutputStream()
24+
exec {
25+
commandLine 'git', 'rev-parse', '--short', 'HEAD'
26+
standardOutput = stdout
27+
}
28+
return stdout.toString().trim()
29+
2430
}
2531

2632
task buildDockerImage(type: DockerBuildImage) {

docker/config/plugins.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
git:4.12.1
1+
git:5.2.0
22
ansicolor:1.0.2
33
workflow-aggregator:590.v6a_d052e5a_a_b_5
44
nodejs:1.5.1
55
envinject:2.866.v5c0403e3d4df
66
conditional-buildstep:1.4.2
77
parameterized-trigger:2.45
88
build-name-setter:2.2.0
9-
pipeline-build-step:2.18
9+
pipeline-build-step:496.v2449a_9a_221f2
1010
generic-webhook-trigger:1.84
1111
matrix-auth:3.1.5
1212
pipeline-utility-steps:2.13.0

jenkins/jenkins_home/config.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version='1.1' encoding='UTF-8'?>
22
<hudson>
33
<disabledAdministrativeMonitors/>
4-
<version>2.346.2</version>
4+
<version>2.387.3</version>
55
<numExecutors>2</numExecutors>
66
<mode>NORMAL</mode>
77
<useSecurity>true</useSecurity>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
"use strict";
2+
3+
describe("Docker Compose Generic Deployment implementation", function() {
4+
// deps
5+
const path = require("path");
6+
const config = require(path.resolve("src/utils/config"));
7+
const cst = require(path.resolve("src/const"));
8+
const dockerCompose = require(path.resolve(
9+
"src/pipeline3/impl/dockerComposeFromArtifact"
10+
));
11+
12+
const scripts = require(path.resolve(
13+
"src/" + config.getJobNameForPipeline3() + "/scripts"
14+
));
15+
16+
var instanceDef = {
17+
uuid: "336af1ee-90a1-4d1b-baaf-db12c84deec0",
18+
name: "cambodia1",
19+
type: "dev",
20+
group: "tlc",
21+
deployment: {
22+
hostDir: "/var/docker-volumes/",
23+
type: "dockerComposeFromArtifact",
24+
composePlugin: true,
25+
dockerComposeFiles: ["docker-compose.yml", "docker-compose-2.yml"],
26+
envFiles: ["env-file-1", "env-file-2"],
27+
value: {
28+
projectPath: "/var/docker-volumes/artifacts/run/docker",
29+
services: ["proxy", "openmrs", "mysql"]
30+
},
31+
timezone: "Europe/Amsterdam",
32+
host: {
33+
type: "ssh",
34+
value: {
35+
ip: "hsc-dev.mekomsolutions.net",
36+
user: "mekom",
37+
port: "22"
38+
}
39+
}
40+
},
41+
data: [
42+
{
43+
type: "sqlDocker",
44+
value: {
45+
service: "mysql",
46+
sourceFile: "/var/instance-data/sql-script.sql"
47+
}
48+
}
49+
]
50+
};
51+
it("should use the correct compose command if composePlugin is set to true", () => {
52+
var expected = "docker compose";
53+
expect(dockerCompose.composeExec(true)).toEqual(expected);
54+
});
55+
56+
it("should use the correct compose command if composePlugin is set to false", () => {
57+
var expected = "docker-compose";
58+
expect(dockerCompose.composeExec(false)).toEqual(expected);
59+
});
60+
61+
it("should generate the correct compose command given multiple docker compose files", () => {
62+
var expected = " -f docker-compose.yml -f docker-compose-2.yml ";
63+
expect(
64+
dockerCompose.combineComposeFiles(
65+
instanceDef.deployment.dockerComposeFiles
66+
)
67+
).toEqual(expected);
68+
});
69+
it("should generate Pre-Host Preparation deployment script", () => {
70+
var expected = "";
71+
expected += scripts.initFolder(
72+
config.getCDDockerDirPath(instanceDef.uuid),
73+
"jenkins",
74+
"jenkins",
75+
true
76+
);
77+
78+
expect(
79+
dockerCompose.preHostPreparation.getDeploymentScript(instanceDef)
80+
).toEqual(expected);
81+
});
82+
83+
it("should generate Host Preparation deployment script", () => {
84+
var expected = "";
85+
86+
expected +=
87+
scripts.remote(
88+
instanceDef.deployment.host.value,
89+
scripts.writeProperty(
90+
"TIMEZONE",
91+
instanceDef.deployment.timezone,
92+
path
93+
.resolve(instanceDef.deployment.value.projectPath, ".env")
94+
.toString()
95+
)
96+
) + "\n";
97+
98+
expected +=
99+
scripts.remote(
100+
instanceDef.deployment.host.value,
101+
scripts.createEnvVarFileDockerGeneric(instanceDef)
102+
) +
103+
"\n" +
104+
scripts.remote(
105+
instanceDef.deployment.host.value,
106+
"cd " +
107+
path.resolve(instanceDef.deployment.value.projectPath).toString() +
108+
" && docker compose -p " +
109+
instanceDef.name +
110+
" -f docker-compose.yml -f docker-compose-2.yml " +
111+
" --env-file=env-file-1 --env-file=env-file-2 --env-file=/var/docker-volumes/artifacts/run/docker/cambodia1.env" +
112+
" build --pull proxy openmrs mysql" +
113+
"\n"
114+
) +
115+
scripts.remote(
116+
instanceDef.deployment.host.value,
117+
"cd " +
118+
path.resolve(instanceDef.deployment.value.projectPath).toString() +
119+
" && docker compose -p " +
120+
instanceDef.name +
121+
" -f docker-compose.yml -f docker-compose-2.yml " +
122+
" --env-file=env-file-1 --env-file=env-file-2 --env-file=/var/docker-volumes/artifacts/run/docker/cambodia1.env" +
123+
" pull proxy openmrs mysql" +
124+
"\n"
125+
) +
126+
scripts.remote(
127+
instanceDef.deployment.host.value,
128+
"sudo chown -R root:root " +
129+
path
130+
.resolve(instanceDef.deployment.hostDir, instanceDef.name)
131+
.toString()
132+
);
133+
let generated = dockerCompose.hostPreparation.getDeploymentScript(
134+
instanceDef
135+
);
136+
expect(generated).toEqual(expected);
137+
});
138+
});

node-scripts/src/instance-event/validator.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ module.exports = {
112112
} else if (deployment.hostDir === "") {
113113
throw new Error("The 'host dir' is not specified.");
114114
}
115-
116115
// validating the actual config based on its type
117116
module.exports
118117
.getConfigValidatorsMap()
@@ -248,6 +247,18 @@ module.exports = {
248247
);
249248
}
250249
},
250+
validateDockerComposeFromArtifactDeploymentConfigValue: function(value) {
251+
if (
252+
JSON.stringify(Object.keys(value).sort()) >=
253+
JSON.stringify(
254+
Object.keys(new model.DockerComposeFromArtifactDeployment()).sort()
255+
)
256+
) {
257+
throw new Error(
258+
"The Docker compose deployment value should be provided as an instance of 'DockerComposeFromArtifactDeployment'."
259+
);
260+
}
261+
},
251262
validateFileTLSDeploymentConfigValue: function(value) {
252263
if (
253264
JSON.stringify(Object.keys(value).sort()) !==
@@ -306,8 +317,9 @@ module.exports = {
306317
);
307318
}
308319
} else if (element.type === "sqlDocker") {
320+
// Since we just check the number of keys we can loosen the check to just if the keys are more than the model
309321
if (
310-
JSON.stringify(Object.keys(element.value).sort()) !==
322+
JSON.stringify(Object.keys(element.value).sort()) >=
311323
JSON.stringify(Object.keys(new model.SqlDocker()).sort())
312324
) {
313325
throw new Error(
@@ -369,7 +381,9 @@ module.exports = {
369381
dockerComposeMaven:
370382
module.exports.validateDockerComposeMavenDeploymentConfigValue,
371383
dockerComposeGenericMaven:
372-
module.exports.validateDockerComposeGenericMavenDeploymentConfigValue
384+
module.exports.validateDockerComposeGenericMavenDeploymentConfigValue,
385+
dockerComposeFromArtifact:
386+
module.exports.validateDockerComposeFromArtifactDeploymentConfigValue
373387
};
374388
}
375389
};

0 commit comments

Comments
 (0)