From a72ce9b05aa25fbba018ae87e636356570ce11a8 Mon Sep 17 00:00:00 2001 From: Zelin Hao Date: Wed, 12 Apr 2023 11:56:17 -0700 Subject: [PATCH 1/4] Add packer build jenkins workflow Signed-off-by: Zelin Hao --- jenkins/packer/packer-build.jenkinsfile | 77 ++++++++++++ tests/jenkins/TestDockerBuild.groovy | 6 +- tests/jenkins/TestPackerBuild.groovy | 111 ++++++++++++++++++ .../packer/packer-build.jenkinsfile.txt | 24 ++++ 4 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 jenkins/packer/packer-build.jenkinsfile create mode 100644 tests/jenkins/TestPackerBuild.groovy create mode 100644 tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile.txt diff --git a/jenkins/packer/packer-build.jenkinsfile b/jenkins/packer/packer-build.jenkinsfile new file mode 100644 index 0000000000..41b364b79d --- /dev/null +++ b/jenkins/packer/packer-build.jenkinsfile @@ -0,0 +1,77 @@ +lib = library(identifier: 'jenkins@2.2.0', retriever: modernSCM([ + $class: 'GitSCMSource', + remote: 'https://github.com/opensearch-project/opensearch-build-libraries.git', +])) + +pipeline { + options { + timeout(time: 4, unit: 'HOURS') + } + agent { + docker { + label 'Jenkins-Agent-Ubuntu2004-X64-M52xlarge-Docker-Builder' + image 'opensearchstaging/ci-runner:ubuntu2004-x64-docker-buildx0.6.3-qemu5.0-awscli1.22-jdk11-v2' + alwaysPull true + } + } + parameters { + string( + name: 'PACKER_AGENT_JSON_NAME', + description: 'The JSON file name of type of Jenkins agent this job is building. e.g. jenkins-agent-al2-arm64.json. Files exist in https://github.com/opensearch-project/opensearch-ci/tree/main/packer', + trim: true + ) + } + stages { + stage('Parameters Check') { + steps { + script { + if (PACKER_AGENT_JSON_NAME.isEmpty()) { + currentBuild.result = 'ABORTED' + error("PACKER_AGENT_JSON_NAME parameter cannot be empty.") + } + print("Passing parameter checks.") + } + } + } + stage('packer-build') { + environment { + PACKER_BUILD_GIT_REPOSITORY_REFERENCE = "main" + PACKER_BUILD_GIT_REPOSITORY = "https://github.com/opensearch-project/opensearch-ci" + } + steps { + script { + print("Getting $PACKER_AGENT_JSON_NAME from $PACKER_BUILD_GIT_REPOSITORY repository with reference $PACKER_BUILD_GIT_REPOSITORY_REFERENCE") + checkout([$class: 'GitSCM', branches: [[name: PACKER_BUILD_GIT_REPOSITORY_REFERENCE ]], userRemoteConfigs: [[url: PACKER_BUILD_GIT_REPOSITORY ]]]) + def packer_jenkins_agent_json = readJSON file: "./packer/$PACKER_AGENT_JSON_NAME" + withCredentials([ + string(credentialsId: 'jenkins-agent-vpc-id', variable: 'vpc_id'), + string(credentialsId: 'jenkins-agent-subnet-id', variable: 'subnet_id'), + string(credentialsId: 'jenkins-agent-sg-id', variable: 'sg_id') + ]){ + packer_jenkins_agent_json["variables"]["build-vpc"] = vpc_id + packer_jenkins_agent_json["variables"]["build-subnet"] = subnet_id + packer_jenkins_agent_json["variables"]["build-secgrp"] = sg_id + } + def PACKER_AGENT_JSON_NAME_SUBSTITUTE = "substitute_" + "$PACKER_AGENT_JSON_NAME" + print("$PACKER_AGENT_JSON_NAME_SUBSTITUTE") + writeJSON file: "./packer/$PACKER_AGENT_JSON_NAME_SUBSTITUTE", json: packer_jenkins_agent_json, pretty: 2 + + // Start to build packer + withCredentials([string(credentialsId: 'jenkins-aws-account-public', variable: 'AWS_ACCOUNT_PUBLIC')]) { + withAWS(role: 'opensearch-packer', roleAccount: "${AWS_ACCOUNT_PUBLIC}", duration: 900, roleSessionName: 'jenkins-session', useNode: true) { + sh ("cd packer && packer build -color=false $PACKER_AGENT_JSON_NAME_SUBSTITUTE") + } + } + + } + } + post() { + always { + script { + postCleanup() + } + } + } + } + } +} diff --git a/tests/jenkins/TestDockerBuild.groovy b/tests/jenkins/TestDockerBuild.groovy index 9a02ca5c14..25a0504269 100644 --- a/tests/jenkins/TestDockerBuild.groovy +++ b/tests/jenkins/TestDockerBuild.groovy @@ -56,12 +56,12 @@ class TestDockerBuild extends BuildPipelineTest { assertJobStatusSuccess() - // Ensure the entire docker commanbd is executed in an external shell script exactelly once + // Ensure the entire docker command is executed in an external shell script exactly once def dockerLoginCommand = getCommands('docker').findAll { shCommand -> shCommand.contains('docker logout && echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin && eval $DOCKER_BUILD_SCRIPT_WITH_COMMANDS') } assertThat(dockerLoginCommand.size(), equalTo(1)) - + // Validate the docker-build.sh is called with correct predefined credential assertCallStack().contains("docker-build.sh(echo Account: jenkins-staging-dockerhub-credential)") @@ -79,5 +79,5 @@ class TestDockerBuild extends BuildPipelineTest { return shCurlCommands } - + } diff --git a/tests/jenkins/TestPackerBuild.groovy b/tests/jenkins/TestPackerBuild.groovy new file mode 100644 index 0000000000..9cdaf95576 --- /dev/null +++ b/tests/jenkins/TestPackerBuild.groovy @@ -0,0 +1,111 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + + +import jenkins.tests.BuildPipelineTest +import org.junit.Before +import org.junit.Test +import static com.lesfurets.jenkins.unit.MethodCall.callArgsToString +import static org.hamcrest.MatcherAssert.assertThat +import static org.hamcrest.CoreMatchers.hasItem +import static com.lesfurets.jenkins.unit.global.lib.GitSource.gitSource +import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library + + +class TestPackerBuild extends BuildPipelineTest { + + // Variables + String packerBuildGitRespository = 'https://github.com/opensearch-project/opensearch-ci' + String packerBuildGitRespositoryReference = 'main' + String packerAgentJsonName = 'jenkins-agent-al2-arm64.json' + + @Override + @Before + void setUp() { + + helper.registerSharedLibrary( + library().name('jenkins') + .defaultVersion('2.2.0') + .allowOverride(true) + .implicit(true) + .targetPath('vars') + .retriever(gitSource('https://github.com/opensearch-project/opensearch-build-libraries.git')) + .build() + ) + + super.setUp() + + binding.setVariable('PACKER_AGENT_JSON_NAME', packerAgentJsonName) + def sample_json = [ + "variables" : [ + "name-base" : "Jenkins-Agent-AL2-X64" , + "os-version" : "AL2" , + "build-region" : "us-east-1" , + "build-vpc" : "vpc-<>" , + "build-subnet" : "subnet-<>" , + "build-secgrp" : "sg-<>" , + "build-time" : "{{isotime \"2006-01-02T03-04-05Z\"}}" , + "aws_ami_region" : "us-east-1" + ] + ] + helper.registerAllowedMethod("readJSON", [Map.class], {c -> sample_json}) + def sample_json_output = [ + "variables" : [ + "name-base" : "Jenkins-Agent-AL2-X64" , + "os-version" : "AL2" , + "build-region" : "us-east-1" , + "build-vpc" : "vpc-123" , + "build-subnet" : "subnet-123" , + "build-secgrp" : "sg-123" , + "build-time" : "{{isotime \"2006-01-02T03-04-05Z\"}}" , + "aws_ami_region" : "us-east-1" + ] + ] + helper.registerAllowedMethod("writeJSON", [Map.class], {c -> sample_json_output}) + helper.registerAllowedMethod("checkout", [Map], {}) + helper.registerAllowedMethod("git", [Map]) + helper.registerAllowedMethod("withCredentials", [Map, Closure], { args, closure -> + closure.delegate = delegate + return helper.callClosure(closure) + }) + helper.registerAllowedMethod("withAWS", [Map, Closure], { args, closure -> + closure.delegate = delegate + return helper.callClosure(closure) + }) + helper.addShMock("cd packer && packer build -color=false substitute_jenkins-agent-al2-arm64.json") { script -> + return [stdout: "", exitValue: 0] + } + } + + @Test + void PackerBuildRegression() { + super.testPipeline('jenkins/packer/packer-build.jenkinsfile', + 'tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile') + + def gitCheckoutCommands = getCommands('checkout', 'GitSCM').findAll { + shCommand -> shCommand.contains('git') + } + assertThat(gitCheckoutCommands, hasItem("{\$class=GitSCM, branches=[{name=main}], userRemoteConfigs=[{url=https://github.com/opensearch-project/opensearch-ci}]}".toString())) + + def aws = getCommands('withAWS', 'packer') + assertThat(aws, hasItem('{role=opensearch-packer, roleAccount=AWS_ACCOUNT_PUBLIC, duration=900, roleSessionName=jenkins-session, useNode=true}, groovy.lang.Closure')) + + def packerCommands = getCommands('sh', 'packer') + assertThat(packerCommands, hasItem('cd packer && packer build -color=false substitute_jenkins-agent-al2-arm64.json')) + + } + + def getCommands(method, text) { + def shCommands = helper.callStack.findAll { call -> + call.methodName == method + }.collect { call -> + callArgsToString(call) + }.findAll { command -> + command.contains(text) + } + return shCommands + } + +} diff --git a/tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile.txt b/tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile.txt new file mode 100644 index 0000000000..8375809f4b --- /dev/null +++ b/tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile.txt @@ -0,0 +1,24 @@ + packer-build.run() + packer-build.modernSCM({$class=GitSCMSource, remote=https://github.com/opensearch-project/opensearch-build-libraries.git}) + packer-build.library({identifier=jenkins@2.2.0, retriever=null}) + packer-build.pipeline(groovy.lang.Closure) + packer-build.timeout({time=4, unit=HOURS}) + packer-build.echo(Executing on agent [docker:[alwaysPull:true, args:, containerPerStageRoot:false, label:Jenkins-Agent-Ubuntu2004-X64-M52xlarge-Docker-Builder, image:opensearchstaging/ci-runner:ubuntu2004-x64-docker-buildx0.6.3-qemu5.0-awscli1.22-jdk11-v2, reuseNode:false, stages:[:]]]) + packer-build.stage(Parameters Check, groovy.lang.Closure) + packer-build.script(groovy.lang.Closure) + packer-build.stage(packer-build, groovy.lang.Closure) + packer-build.script(groovy.lang.Closure) + packer-build.checkout({$class=GitSCM, branches=[{name=main}], userRemoteConfigs=[{url=https://github.com/opensearch-project/opensearch-ci}]}) + packer-build.readJSON({file=./packer/jenkins-agent-al2-arm64.json}) + packer-build.string({credentialsId=jenkins-agent-vpc-id, variable=vpc_id}) + packer-build.string({credentialsId=jenkins-agent-subnet-id, variable=subnet_id}) + packer-build.string({credentialsId=jenkins-agent-sg-id, variable=sg_id}) + packer-build.withCredentials([vpc_id, subnet_id, sg_id], groovy.lang.Closure) + packer-build.writeJSON({file=./packer/substitute_jenkins-agent-al2-arm64.json, json={variables={name-base=Jenkins-Agent-AL2-X64, os-version=AL2, build-region=us-east-1, build-vpc=vpc_id, build-subnet=subnet_id, build-secgrp=sg_id, build-time={{isotime "2006-01-02T03-04-05Z"}}, aws_ami_region=us-east-1}}, pretty=2}) + packer-build.string({credentialsId=jenkins-aws-account-public, variable=AWS_ACCOUNT_PUBLIC}) + packer-build.withCredentials([AWS_ACCOUNT_PUBLIC], groovy.lang.Closure) + packer-build.withAWS({role=opensearch-packer, roleAccount=AWS_ACCOUNT_PUBLIC, duration=900, roleSessionName=jenkins-session, useNode=true}, groovy.lang.Closure) + packer-build.sh(cd packer && packer build -color=false substitute_jenkins-agent-al2-arm64.json) + packer-build.script(groovy.lang.Closure) + packer-build.postCleanup() + postCleanup.cleanWs({disableDeferredWipeout=true, deleteDirs=true}) From 227897677de90360efe10a51a8a6df82845ed2a0 Mon Sep 17 00:00:00 2001 From: Zelin Hao Date: Wed, 12 Apr 2023 12:05:50 -0700 Subject: [PATCH 2/4] Add more AWS duration Signed-off-by: Zelin Hao --- jenkins/packer/packer-build.jenkinsfile | 2 +- tests/jenkins/TestPackerBuild.groovy | 2 +- .../packer/packer-build.jenkinsfile.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jenkins/packer/packer-build.jenkinsfile b/jenkins/packer/packer-build.jenkinsfile index 41b364b79d..c0136f2635 100644 --- a/jenkins/packer/packer-build.jenkinsfile +++ b/jenkins/packer/packer-build.jenkinsfile @@ -58,7 +58,7 @@ pipeline { // Start to build packer withCredentials([string(credentialsId: 'jenkins-aws-account-public', variable: 'AWS_ACCOUNT_PUBLIC')]) { - withAWS(role: 'opensearch-packer', roleAccount: "${AWS_ACCOUNT_PUBLIC}", duration: 900, roleSessionName: 'jenkins-session', useNode: true) { + withAWS(role: 'opensearch-packer', roleAccount: "${AWS_ACCOUNT_PUBLIC}", duration: 3600, roleSessionName: 'jenkins-session', useNode: true) { sh ("cd packer && packer build -color=false $PACKER_AGENT_JSON_NAME_SUBSTITUTE") } } diff --git a/tests/jenkins/TestPackerBuild.groovy b/tests/jenkins/TestPackerBuild.groovy index 9cdaf95576..1fa4915468 100644 --- a/tests/jenkins/TestPackerBuild.groovy +++ b/tests/jenkins/TestPackerBuild.groovy @@ -90,7 +90,7 @@ class TestPackerBuild extends BuildPipelineTest { assertThat(gitCheckoutCommands, hasItem("{\$class=GitSCM, branches=[{name=main}], userRemoteConfigs=[{url=https://github.com/opensearch-project/opensearch-ci}]}".toString())) def aws = getCommands('withAWS', 'packer') - assertThat(aws, hasItem('{role=opensearch-packer, roleAccount=AWS_ACCOUNT_PUBLIC, duration=900, roleSessionName=jenkins-session, useNode=true}, groovy.lang.Closure')) + assertThat(aws, hasItem('{role=opensearch-packer, roleAccount=AWS_ACCOUNT_PUBLIC, duration=3600, roleSessionName=jenkins-session, useNode=true}, groovy.lang.Closure')) def packerCommands = getCommands('sh', 'packer') assertThat(packerCommands, hasItem('cd packer && packer build -color=false substitute_jenkins-agent-al2-arm64.json')) diff --git a/tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile.txt b/tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile.txt index 8375809f4b..bfec2cddca 100644 --- a/tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile.txt +++ b/tests/jenkins/jenkinsjob-regression-files/packer/packer-build.jenkinsfile.txt @@ -17,7 +17,7 @@ packer-build.writeJSON({file=./packer/substitute_jenkins-agent-al2-arm64.json, json={variables={name-base=Jenkins-Agent-AL2-X64, os-version=AL2, build-region=us-east-1, build-vpc=vpc_id, build-subnet=subnet_id, build-secgrp=sg_id, build-time={{isotime "2006-01-02T03-04-05Z"}}, aws_ami_region=us-east-1}}, pretty=2}) packer-build.string({credentialsId=jenkins-aws-account-public, variable=AWS_ACCOUNT_PUBLIC}) packer-build.withCredentials([AWS_ACCOUNT_PUBLIC], groovy.lang.Closure) - packer-build.withAWS({role=opensearch-packer, roleAccount=AWS_ACCOUNT_PUBLIC, duration=900, roleSessionName=jenkins-session, useNode=true}, groovy.lang.Closure) + packer-build.withAWS({role=opensearch-packer, roleAccount=AWS_ACCOUNT_PUBLIC, duration=3600, roleSessionName=jenkins-session, useNode=true}, groovy.lang.Closure) packer-build.sh(cd packer && packer build -color=false substitute_jenkins-agent-al2-arm64.json) packer-build.script(groovy.lang.Closure) packer-build.postCleanup() From b253c2d18cf54043ec2858f7f42a3f4215ae8236 Mon Sep 17 00:00:00 2001 From: Zelin Hao Date: Wed, 12 Apr 2023 12:27:24 -0700 Subject: [PATCH 3/4] Add build description Signed-off-by: Zelin Hao --- jenkins/packer/packer-build.jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/jenkins/packer/packer-build.jenkinsfile b/jenkins/packer/packer-build.jenkinsfile index c0136f2635..cd9e1bc11b 100644 --- a/jenkins/packer/packer-build.jenkinsfile +++ b/jenkins/packer/packer-build.jenkinsfile @@ -25,6 +25,7 @@ pipeline { stage('Parameters Check') { steps { script { + currentBuild.description = "$PACKER_AGENT_JSON_NAME" if (PACKER_AGENT_JSON_NAME.isEmpty()) { currentBuild.result = 'ABORTED' error("PACKER_AGENT_JSON_NAME parameter cannot be empty.") From 454fa042321b405f11ec67bcc6405d4662705225 Mon Sep 17 00:00:00 2001 From: Zelin Hao Date: Wed, 12 Apr 2023 12:34:02 -0700 Subject: [PATCH 4/4] Update names Signed-off-by: Zelin Hao --- jenkins/packer/packer-build.jenkinsfile | 22 +++++++++++----------- tests/jenkins/TestPackerBuild.groovy | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/jenkins/packer/packer-build.jenkinsfile b/jenkins/packer/packer-build.jenkinsfile index cd9e1bc11b..fb6ea601f6 100644 --- a/jenkins/packer/packer-build.jenkinsfile +++ b/jenkins/packer/packer-build.jenkinsfile @@ -16,8 +16,8 @@ pipeline { } parameters { string( - name: 'PACKER_AGENT_JSON_NAME', - description: 'The JSON file name of type of Jenkins agent this job is building. e.g. jenkins-agent-al2-arm64.json. Files exist in https://github.com/opensearch-project/opensearch-ci/tree/main/packer', + name: 'PACKER_TEMPLATE_NAME', + description: 'The packer template file name of Jenkins agent. e.g. jenkins-agent-al2-arm64.json. Files exist in https://github.com/opensearch-project/opensearch-ci/tree/main/packer', trim: true ) } @@ -25,10 +25,10 @@ pipeline { stage('Parameters Check') { steps { script { - currentBuild.description = "$PACKER_AGENT_JSON_NAME" - if (PACKER_AGENT_JSON_NAME.isEmpty()) { + currentBuild.description = "$PACKER_TEMPLATE_NAME" + if (PACKER_TEMPLATE_NAME.isEmpty()) { currentBuild.result = 'ABORTED' - error("PACKER_AGENT_JSON_NAME parameter cannot be empty.") + error("PACKER_TEMPLATE_NAME parameter cannot be empty.") } print("Passing parameter checks.") } @@ -41,9 +41,9 @@ pipeline { } steps { script { - print("Getting $PACKER_AGENT_JSON_NAME from $PACKER_BUILD_GIT_REPOSITORY repository with reference $PACKER_BUILD_GIT_REPOSITORY_REFERENCE") + print("Getting $PACKER_TEMPLATE_NAME from $PACKER_BUILD_GIT_REPOSITORY repository with reference $PACKER_BUILD_GIT_REPOSITORY_REFERENCE") checkout([$class: 'GitSCM', branches: [[name: PACKER_BUILD_GIT_REPOSITORY_REFERENCE ]], userRemoteConfigs: [[url: PACKER_BUILD_GIT_REPOSITORY ]]]) - def packer_jenkins_agent_json = readJSON file: "./packer/$PACKER_AGENT_JSON_NAME" + def packer_jenkins_agent_json = readJSON file: "./packer/$PACKER_TEMPLATE_NAME" withCredentials([ string(credentialsId: 'jenkins-agent-vpc-id', variable: 'vpc_id'), string(credentialsId: 'jenkins-agent-subnet-id', variable: 'subnet_id'), @@ -53,14 +53,14 @@ pipeline { packer_jenkins_agent_json["variables"]["build-subnet"] = subnet_id packer_jenkins_agent_json["variables"]["build-secgrp"] = sg_id } - def PACKER_AGENT_JSON_NAME_SUBSTITUTE = "substitute_" + "$PACKER_AGENT_JSON_NAME" - print("$PACKER_AGENT_JSON_NAME_SUBSTITUTE") - writeJSON file: "./packer/$PACKER_AGENT_JSON_NAME_SUBSTITUTE", json: packer_jenkins_agent_json, pretty: 2 + def PACKER_TEMPLATE_NAME_SUBSTITUTE = "substitute_" + "$PACKER_TEMPLATE_NAME" + print("$PACKER_TEMPLATE_NAME_SUBSTITUTE") + writeJSON file: "./packer/$PACKER_TEMPLATE_NAME_SUBSTITUTE", json: packer_jenkins_agent_json, pretty: 2 // Start to build packer withCredentials([string(credentialsId: 'jenkins-aws-account-public', variable: 'AWS_ACCOUNT_PUBLIC')]) { withAWS(role: 'opensearch-packer', roleAccount: "${AWS_ACCOUNT_PUBLIC}", duration: 3600, roleSessionName: 'jenkins-session', useNode: true) { - sh ("cd packer && packer build -color=false $PACKER_AGENT_JSON_NAME_SUBSTITUTE") + sh ("cd packer && packer build -color=false $PACKER_TEMPLATE_NAME_SUBSTITUTE") } } diff --git a/tests/jenkins/TestPackerBuild.groovy b/tests/jenkins/TestPackerBuild.groovy index 1fa4915468..965fd29f3a 100644 --- a/tests/jenkins/TestPackerBuild.groovy +++ b/tests/jenkins/TestPackerBuild.groovy @@ -19,7 +19,7 @@ class TestPackerBuild extends BuildPipelineTest { // Variables String packerBuildGitRespository = 'https://github.com/opensearch-project/opensearch-ci' String packerBuildGitRespositoryReference = 'main' - String packerAgentJsonName = 'jenkins-agent-al2-arm64.json' + String packerTemplateName = 'jenkins-agent-al2-arm64.json' @Override @Before @@ -37,7 +37,7 @@ class TestPackerBuild extends BuildPipelineTest { super.setUp() - binding.setVariable('PACKER_AGENT_JSON_NAME', packerAgentJsonName) + binding.setVariable('PACKER_TEMPLATE_NAME', packerTemplateName) def sample_json = [ "variables" : [ "name-base" : "Jenkins-Agent-AL2-X64" ,