Skip to content
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

INFRA-427: Add a new deployment type to accommodate the new Ozone packaging #42

Merged
merged 8 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ That is because the bulk of the logic of what OCD3 does lives here. Almost all J

This is how one would build the underlying Node JS scripts:
```bash
gradle node-scripts:build
./gradlew node-scripts:build
```
And this must be done before submitting code commits.
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.
Expand All @@ -231,7 +231,7 @@ See [here](readme/docker/README.md).
OCD3 not only needs a Docker image for its binaries but also requires a 'Jenkins home' folder that provides a pre-configured Jenkins setup:

```bash
gradle jenkins:build
./gradlew jenkins:build
```
This will package a zip archive of the jenkins folder.

Expand Down
10 changes: 5 additions & 5 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
ARG VERSION=2.346.3
ARG VERSION=2.387.3
FROM jenkins/jenkins:$VERSION
MAINTAINER Mekom Solutions <[email protected]>

USER root

# Add the APP_DATA_DIR volume to keep OpenMRS CD data out of the Jenkins Home
ARG APP_DATA_DIR="/var/lib/openmrs_cd/app_data"
RUN mkdir -p $APP_DATA_DIR && chown -R jenkins:jenkins $APP_DATA_DIR

RUN apt update --fix-missing
RUN apt -y install nano jq openssh-server rsync libxml2-utils

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

# Add the APP_DATA_DIR volume to keep OpenMRS CD data out of the Jenkins Home
ARG APP_DATA_DIR="/var/lib/openmrs_cd/app_data"
RUN mkdir -p $APP_DATA_DIR && chown -R jenkins:jenkins $APP_DATA_DIR

# Provide access to the /usr/share/jenkins directory
RUN chown -R jenkins /usr/share/jenkins

Expand Down
8 changes: 7 additions & 1 deletion docker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ repositories {

def dockerHubRepo = "mekomsolutions/openmrscd"
def getShortCommit() {
return ['sh', '-c', 'git log -1 --format=%h'].execute().text.trim()
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim()

}

task buildDockerImage(type: DockerBuildImage) {
Expand Down
4 changes: 2 additions & 2 deletions docker/config/plugins.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
git:4.12.1
git:5.2.0
ansicolor:1.0.2
workflow-aggregator:590.v6a_d052e5a_a_b_5
nodejs:1.5.1
envinject:2.866.v5c0403e3d4df
conditional-buildstep:1.4.2
parameterized-trigger:2.45
build-name-setter:2.2.0
pipeline-build-step:2.18
pipeline-build-step:496.v2449a_9a_221f2
generic-webhook-trigger:1.84
matrix-auth:3.1.5
pipeline-utility-steps:2.13.0
Expand Down
2 changes: 1 addition & 1 deletion jenkins/jenkins_home/config.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version='1.1' encoding='UTF-8'?>
<hudson>
<disabledAdministrativeMonitors/>
<version>2.346.2</version>
<version>2.387.3</version>
<numExecutors>2</numExecutors>
<mode>NORMAL</mode>
<useSecurity>true</useSecurity>
Expand Down
138 changes: 138 additions & 0 deletions node-scripts/spec/pipeline3/impl/dockerComposeProjectDir.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
"use strict";

describe("Docker Compose Generic Deployment implementation", function() {
// deps
const path = require("path");
const config = require(path.resolve("src/utils/config"));
const cst = require(path.resolve("src/const"));
const dockerCompose = require(path.resolve(
"src/pipeline3/impl/dockerComposeProjectDir"
));

const scripts = require(path.resolve(
"src/" + config.getJobNameForPipeline3() + "/scripts"
));

var instanceDef = {
uuid: "336af1ee-90a1-4d1b-baaf-db12c84deec0",
name: "cambodia1",
type: "dev",
group: "tlc",
deployment: {
hostDir: "/var/docker-volumes/",
type: "dockerComposeProjectDir",
composePlugin: true,
dockerComposeFiles: ["docker-compose.yml", "docker-compose-2.yml"],
envFiles: ["env-file-1", "env-file-2"],
value: {
projectPath: "/var/docker-volumes/artifacts/run/docker",
services: ["proxy", "openmrs", "mysql"]
},
timezone: "Europe/Amsterdam",
host: {
type: "ssh",
value: {
ip: "hsc-dev.mekomsolutions.net",
user: "mekom",
port: "22"
}
}
},
data: [
{
type: "sqlDocker",
value: {
service: "mysql",
sourceFile: "/var/instance-data/sql-script.sql"
}
}
]
};
it("should use the correct compose command if composePlugin is set to true", () => {
var expected = "docker compose";
expect(dockerCompose.composeExec(true)).toEqual(expected);
});

it("should use the correct compose command if composePlugin is set to false", () => {
var expected = "docker-compose";
expect(dockerCompose.composeExec(false)).toEqual(expected);
});

it("should generate the correct compose command given multiple docker compose files", () => {
var expected = " -f docker-compose.yml -f docker-compose-2.yml ";
expect(
dockerCompose.combineComposeFiles(
instanceDef.deployment.dockerComposeFiles
)
).toEqual(expected);
});
it("should generate Pre-Host Preparation deployment script", () => {
var expected = "";
expected += scripts.initFolder(
config.getCDDockerDirPath(instanceDef.uuid),
"jenkins",
"jenkins",
true
);

expect(
dockerCompose.preHostPreparation.getDeploymentScript(instanceDef)
).toEqual(expected);
});

it("should generate Host Preparation deployment script", () => {
var expected = "";

expected +=
scripts.remote(
instanceDef.deployment.host.value,
scripts.writeProperty(
"TIMEZONE",
instanceDef.deployment.timezone,
path
.resolve(instanceDef.deployment.value.projectPath, ".env")
.toString()
)
) + "\n";

expected +=
scripts.remote(
instanceDef.deployment.host.value,
scripts.createEnvVarFileDockerGeneric(instanceDef)
) +
"\n" +
scripts.remote(
instanceDef.deployment.host.value,
"cd " +
path.resolve(instanceDef.deployment.value.projectPath).toString() +
" && docker compose -p " +
instanceDef.name +
" -f docker-compose.yml -f docker-compose-2.yml " +
" --env-file=env-file-1 --env-file=env-file-2 --env-file=/var/docker-volumes/artifacts/run/docker/cambodia1.env" +
" build --pull proxy openmrs mysql" +
"\n"
) +
scripts.remote(
instanceDef.deployment.host.value,
"cd " +
path.resolve(instanceDef.deployment.value.projectPath).toString() +
" && docker compose -p " +
instanceDef.name +
" -f docker-compose.yml -f docker-compose-2.yml " +
" --env-file=env-file-1 --env-file=env-file-2 --env-file=/var/docker-volumes/artifacts/run/docker/cambodia1.env" +
" pull proxy openmrs mysql" +
"\n"
) +
scripts.remote(
instanceDef.deployment.host.value,
"sudo chown -R root:root " +
path
.resolve(instanceDef.deployment.hostDir, instanceDef.name)
.toString()
);
let generated = dockerCompose.hostPreparation.getDeploymentScript(
instanceDef
);
expect(generated).toEqual(expected);
});
});
20 changes: 17 additions & 3 deletions node-scripts/src/instance-event/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ module.exports = {
} else if (deployment.hostDir === "") {
throw new Error("The 'host dir' is not specified.");
}

// validating the actual config based on its type
module.exports
.getConfigValidatorsMap()
Expand Down Expand Up @@ -248,6 +247,18 @@ module.exports = {
);
}
},
validateDockerComposeProjectDirDeploymentConfigValue: function(value) {
if (
JSON.stringify(Object.keys(value).sort()) >=
JSON.stringify(
Object.keys(new model.DockerComposeGenericDeployment()).sort()
)
) {
throw new Error(
"The Docker compose deployment value should be provided as an instance of 'DockerComposeProjectDirDeployment'."
);
}
},
validateFileTLSDeploymentConfigValue: function(value) {
if (
JSON.stringify(Object.keys(value).sort()) !==
Expand Down Expand Up @@ -306,8 +317,9 @@ module.exports = {
);
}
} else if (element.type === "sqlDocker") {
// Since we just check the number of keys we can loosen the check to just if the keys are more than the model
if (
JSON.stringify(Object.keys(element.value).sort()) !==
JSON.stringify(Object.keys(element.value).sort()) >=
JSON.stringify(Object.keys(new model.SqlDocker()).sort())
) {
throw new Error(
Expand Down Expand Up @@ -369,7 +381,9 @@ module.exports = {
dockerComposeMaven:
module.exports.validateDockerComposeMavenDeploymentConfigValue,
dockerComposeGenericMaven:
module.exports.validateDockerComposeGenericMavenDeploymentConfigValue
module.exports.validateDockerComposeGenericMavenDeploymentConfigValue,
dockerComposeProjectDir:
module.exports.validateDockerComposeProjectDirDeploymentConfigValue
};
}
};
Loading