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

Docker Patch Library to support Docker re-release Automation #268

Merged
merged 6 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
33 changes: 33 additions & 0 deletions tests/jenkins/TestPatchDockerImage.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

import jenkins.tests.BuildPipelineTest
import org.junit.Before
import org.junit.Test


class TestPatchDockerImage extends BuildPipelineTest {

@Before
void setUp() {
this.registerLibTester(new PatchDockerImageLibTester(
"opensearch",
"latest",
"true"
)
)
super.setUp()
}

@Test
void testPatchDockerImage() {

super.testPipeline("tests/jenkins/jobs/PatchDockerImage_Jenkinsfile")
}
}
25 changes: 25 additions & 0 deletions tests/jenkins/jobs/PatchDockerImage_Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

pipeline {
agent none
stages {
stage('Patch docker image') {
steps {
script {
patchDockerImage(
product: "opensearch",
tag: "latest",
rerelease: "true"
)
}
}
}
}
}
41 changes: 41 additions & 0 deletions tests/jenkins/jobs/PatchDockerImage_Jenkinsfile.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
PatchDockerImage_Jenkinsfile.run()
PatchDockerImage_Jenkinsfile.pipeline(groovy.lang.Closure)
PatchDockerImage_Jenkinsfile.echo(Executing on agent [label:none])
PatchDockerImage_Jenkinsfile.stage(Patch docker image, groovy.lang.Closure)
PatchDockerImage_Jenkinsfile.script(groovy.lang.Closure)
PatchDockerImage_Jenkinsfile.patchDockerImage({product=opensearch, tag=latest, rerelease=true})
patchDockerImage.legacySCM(groovy.lang.Closure)
patchDockerImage.library({identifier=jenkins@main, retriever=null})
patchDockerImage.sh(
#!/bin/bash
set -e
set +x

docker pull opensearchproject/opensearch:latest
)
patchDockerImage.sh(docker inspect --format '{{ index .Config.Labels "org.label-schema.version"}}' opensearchproject/opensearch:latest > versionnumber)
patchDockerImage.sh(docker inspect --format '{{ index .Config.Labels "org.label-schema.build-date"}}' opensearchproject/opensearch:latest > time)
patchDockerImage.sh(docker inspect --format '{{ index .Config.Labels "org.label-schema.description"}}' opensearchproject/opensearch:latest > number)
patchDockerImage.readFile(versionnumber)
patchDockerImage.readFile(time)
patchDockerImage.readFile(number)
patchDockerImage.readYaml({file=manifests/1.3.0/opensearch-1.3.0.yml})
InputManifest.asBoolean()
patchDockerImage.echo(Trigger docker-build)
patchDockerImage.string({name=DOCKER_BUILD_GIT_REPOSITORY, value=https://github.com/opensearch-project/opensearch-build})
patchDockerImage.string({name=DOCKER_BUILD_GIT_REPOSITORY_REFERENCE, value=main})
patchDockerImage.string({name=DOCKER_BUILD_SCRIPT_WITH_COMMANDS, value=id && pwd && cd docker/release && curl -sSL https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/1.3.0/1880/linux/x64/tar/dist/opensearch/opensearch-1.3.0-linux-x64.tar.gz -o opensearch-x64.tgz && curl -sSL https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/1.3.0/1880/linux/arm64/tar/dist/opensearch/opensearch-1.3.0-linux-arm64.tar.gz -o opensearch-arm64.tgz && bash build-image-multi-arch.sh -v 1.3.0 -f ./dockerfiles/opensearch.al2.dockerfile -p opensearch -a 'x64,arm64' -r opensearchstaging/opensearch -t 'opensearch-x64.tgz,opensearch-arm64.tgz' -n 1880})
patchDockerImage.build({job=docker-build, parameters=[null, null, null]})
patchDockerImage.echo(Trigger docker-copy with tag build date )
patchDockerImage.string({name=SOURCE_IMAGE_REGISTRY, value=opensearchstaging})
patchDockerImage.string({name=SOURCE_IMAGE, value=opensearch:1.3.0})
patchDockerImage.string({name=DESTINATION_IMAGE_REGISTRY, value=opensearchstaging})
patchDockerImage.string({name=DESTINATION_IMAGE, value=opensearch:1.3.0.1880.20230619})
patchDockerImage.build({job=docker-copy, parameters=[null, null, null, null]})
patchDockerImage.echo(Trigger docker-scan for opensearch version 1.3.0)
patchDockerImage.string({name=IMAGE_FULL_NAME, value=opensearchstaging/opensearch:1.3.0})
patchDockerImage.build({job=docker-scan, parameters=[null]})
patchDockerImage.echo(Trigger docker-promote)
patchDockerImage.string({name=SOURCE_IMAGES, value=opensearch:1.3.0.1880.20230619})
patchDockerImage.string({name=RELEASE_VERSION, value=1.3.0})
patchDockerImage.build({job=docker-promote, parameters=[null, null]})
52 changes: 52 additions & 0 deletions tests/jenkins/lib-testers/PatchDockerImageLibtester.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
import static org.hamcrest.CoreMatchers.notNullValue
import static org.hamcrest.MatcherAssert.assertThat
import org.yaml.snakeyaml.Yaml



class PatchDockerImageLibTester extends LibFunctionTester {

private String product
private String tag
private boolean rerelease

public PatchDockerImageLibTester(product, tag, rerelease){
this.product = product
this.tag = tag
this.rerelease = rerelease
}

void configure(helper, binding) {
def inputManifest = "tests/data/opensearch-1.3.0.yml"

helper.addReadFileMock('versionnumber', '1.3.0')
helper.addReadFileMock('time', '2023-06-19T19:12:59Z')
helper.addReadFileMock('number', '1880')
helper.registerAllowedMethod('readYaml', [Map.class], { args ->
return new Yaml().load((inputManifest as File).text)
})
helper.registerAllowedMethod("git", [Map])
}

void parameterInvariantsAssertions(call) {
assertThat(call.args.product.first(), notNullValue())
assertThat(call.args.tag.first(), notNullValue())
}

boolean expectedParametersMatcher(call) {
return call.args.product.first().toString().equals(this.product)
&& call.args.tag.first().toString().equals(this.tag)
}

String libFunctionName() {
return 'patchDockerImage'
}
}
111 changes: 111 additions & 0 deletions vars/patchDockerImage.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

peterzhuamazon marked this conversation as resolved.
Show resolved Hide resolved
void call(Map args = [:]) {
def lib = library(identifier: 'jenkins@main', retriever: legacySCM(scm))
peterzhuamazon marked this conversation as resolved.
Show resolved Hide resolved
String docker_image = "opensearchproject/${args.product}:${args.tag}"

sh"""
#!/bin/bash
Copy link
Member

Choose a reason for hiding this comment

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

Use this:

    sh """#!/bin/bash

Your original implementation will not force bash and will default back to sh.

set -e
set +x

docker pull ${docker_image}
"""
sh """docker inspect --format '{{ index .Config.Labels "org.label-schema.version"}}' ${docker_image} > versionnumber"""
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
sh """docker inspect --format '{{ index .Config.Labels "org.label-schema.version"}}' ${docker_image} > versionnumber"""
sh """docker inspect --format '{{ index .Config.Labels "org.label-schema.version"}}' ${docker_image} > versionNumber"""

Copy link
Member

Choose a reason for hiding this comment

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

Use sh("") if you are trying to do one liner unless you have other reasons.


sh """docker inspect --format '{{ index .Config.Labels "org.label-schema.build-date"}}' ${docker_image} > time"""

sh """docker inspect --format '{{ index .Config.Labels "org.label-schema.description"}}' ${docker_image} > number"""
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to combine these shell commands into above sh""" block.
Also avoid using time as variable name. Can mess up actual clock sometimes.

Copy link
Collaborator Author

@Divyaasm Divyaasm Aug 1, 2023

Choose a reason for hiding this comment

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

Yeah but having all these statements in a single block isn't storing the output value in a variable. That's technically resulting an error. I'll change time variable name. Thanks

Copy link
Member

@gaiksaya gaiksaya Aug 1, 2023

Choose a reason for hiding this comment

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

That doesn't sound right! This might be the culprit https://github.com/opensearch-project/opensearch-build-libraries/pull/268/files#diff-d42288632ebcbc435313fa808e87e49f58461165639396b6ec30cbb928596336R15-R17

I believe by default the shell is zsh and here we are running bash. Also those lines apply only to one command docker pull ${docker_image}. Try removing those and put it under default shell

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
sh """docker inspect --format '{{ index .Config.Labels "org.label-schema.description"}}' ${docker_image} > number"""
sh """docker inspect --format '{{ index .Config.Labels "org.label-schema.description"}}' ${docker_image} > buildNumber"""

Copy link
Member

Choose a reason for hiding this comment

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

Why are we keep doing one liners here?


version = readFile('versionnumber').trim()
build_time = readFile('time').trim()
build_number = readFile('number').trim()

def inputManifest = lib.jenkins.InputManifest.new(readYaml(file: "manifests/${version}/${args.product}-${version}.yml"))

artifactUrlX64 = "https://ci.opensearch.org/ci/dbc/distribution-build-${args.product}/${version}/${build_number}/linux/x64/tar/dist/${args.product}/${args.product}-${version}-linux-x64.tar.gz"

artifactUrlARM64 = "https://ci.opensearch.org/ci/dbc/distribution-build-${args.product}/${version}/${build_number}/linux/arm64/tar/dist/${args.product}/${args.product}-${version}-linux-arm64.tar.gz"

/*slice the time to get date value*/
Copy link
Member

Choose a reason for hiding this comment

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

Use //

build_date = build_time[0..3] + build_time[5..6] + build_time[8..9]
peterzhuamazon marked this conversation as resolved.
Show resolved Hide resolved

def build_qualifier = inputManifest.build.qualifier
peterzhuamazon marked this conversation as resolved.
Show resolved Hide resolved

if (build_qualifier != null && build_qualifier != 'null') {
build_qualifier = "-" + build_qualifier
}
else {
build_qualifier = ''
}

if (artifactUrlX64 == null || artifactUrlARM64 == null) {
echo 'Skipping docker build, one of x64 or arm64 artifacts was not built.'
} else {
Copy link
Member

Choose a reason for hiding this comment

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

Please format the document for proper alignment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure Sayali

echo 'Trigger docker-build'
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
echo 'Trigger docker-build'
echo 'Triggering docker-build'

dockerBuild: {
build job: 'docker-build',
parameters: [
string(name: 'DOCKER_BUILD_GIT_REPOSITORY', value: 'https://github.com/opensearch-project/opensearch-build'),
string(name: 'DOCKER_BUILD_GIT_REPOSITORY_REFERENCE', value: 'main'),
string(name: 'DOCKER_BUILD_SCRIPT_WITH_COMMANDS', value: [
'id',
'pwd',
'cd docker/release',
"curl -sSL ${artifactUrlX64} -o ${args.product}-x64.tgz",
"curl -sSL ${artifactUrlARM64} -o ${args.product}-arm64.tgz",
[
'bash',
'build-image-multi-arch.sh',
"-v ${inputManifest.build.version}${build_qualifier}",
"-f ./dockerfiles/${args.product}.al2.dockerfile",
"-p ${args.product}",
"-a 'x64,arm64'",
"-r opensearchstaging/${args.product}",
"-t '${args.product}-x64.tgz,${args.product}-arm64.tgz'",
"-n ${build_number}"
].join(' ')
].join(' && ')),
]
}

echo 'Trigger docker-copy with tag build date '
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
echo 'Trigger docker-copy with tag build date '
echo 'Triggering docker-copy with tag build date '

if (args.rerelease) {
dockerCopy: {
build job: 'docker-copy',
parameters: [
string(name: 'SOURCE_IMAGE_REGISTRY', value: 'opensearchstaging'),
string(name: 'SOURCE_IMAGE', value: "${args.product}:${inputManifest.build.version}${build_qualifier}"),
string(name: 'DESTINATION_IMAGE_REGISTRY', value: 'opensearchstaging'),
string(name: 'DESTINATION_IMAGE', value: "${args.product}:${inputManifest.build.version}${build_qualifier}.${build_number}.${build_date}")
]
}
}

echo "Trigger docker-scan for ${args.product} version ${inputManifest.build.version}${build_qualifier}"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
echo "Trigger docker-scan for ${args.product} version ${inputManifest.build.version}${build_qualifier}"
echo "Triggering docker-scan for ${args.product} version ${inputManifest.build.version}${build_qualifier}"

dockerScan: {
build job: 'docker-scan',
parameters: [
string(name: 'IMAGE_FULL_NAME', value: "opensearchstaging/${args.product}:${inputManifest.build.version}${build_qualifier}")
]
}

echo 'Trigger docker-promote'
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
echo 'Trigger docker-promote'
echo 'Triggering docker-promote'

if(args.rerelease){
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to do few more tests before pushing to Prod? For example we do not want to push to prod if high CVEs are detected in above docker scan. @bbarani @peterzhuamazon

Also @Divyaasm please add https://github.com/opensearch-project/opensearch-build/blob/main/jenkins/opensearch/distribution-build.jenkinsfile#L440 wait:true for each job that is being triggered. I think default is true by default but better to mention it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Think we have ignored CVE's presence in this implementation promote the image when Docker-Scan and Docker-Validation(enhancement) are successful . The idea is to re-run the Job every week to align with Base OS Image. @bbarani Correct me if I'm wrong.

Copy link
Member

@bbarani bbarani Aug 1, 2023

Choose a reason for hiding this comment

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

I don't think we can do anything about any CVE at this point in time if it didn't get remediated as part of yum update as the fix needs to come from base OS team. My recommendation is to move forward with available fixes and patch the Docker images on regular basis.

dockerPromote: {
build job: 'docker-promote',
parameters: [
string(name: 'SOURCE_IMAGES', value: "${args.product}:${inputManifest.build.version}${build_qualifier}.${build_number}.${build_date}"),
string(name: 'RELEASE_VERSION', value: "${version}")
]
}
}
}
}
Loading