diff --git a/ceph-dev-pipeline/build/Jenkinsfile b/ceph-dev-pipeline/build/Jenkinsfile index af8076f64..8188792ea 100644 --- a/ceph-dev-pipeline/build/Jenkinsfile +++ b/ceph-dev-pipeline/build/Jenkinsfile @@ -37,7 +37,7 @@ def get_os_info(dist) { os.pkg_type = "deb" } else if ( ubuntu_releases.keySet().contains(dist) ) { os.name = "ubuntu" - os.version = ubuntu_releases[env.DIST] + os.version = ubuntu_releases[dist] os.pkg_type = "deb" } // We need to set matcher to null right after using it to avoid a java.io.NotSerializableException @@ -141,32 +141,412 @@ def get_ceph_release_repo_text(base_url) { return text.toString() } +// Stage 1 (source distribution): trigger the source-dist setup job (or reuse setupBuildId) and return its number/URL. +def doSourceDistribution(Map args) { + def buildId = args.setupBuildId + if ( !buildId ) { + def setup_build = build( + job: args.setupJob, + parameters: [ + string(name: "BRANCH", value: args.branch), + // Below are just for ceph-source-dist + string(name: "SHA1", value: args.sha1), + string(name: "CEPH_REPO", value: args.cephRepo), + string(name: "CEPH_BUILD_BRANCH", value: args.cephBuildBranch), + // Below are only for actual releases + string(name: 'RELEASE_TYPE', value: args.releaseType ?: ''), + string(name: 'RELEASE_BUILD', value: args.releaseBuild ?: ''), + string(name: 'VERSION', value: args.version ?: '') + ] + ) + buildId = setup_build.getNumber() + } + println "SETUP_BUILD_ID=${buildId}" + def buildUrl = new URI([args.jenkinsUrl, "job", args.setupJob, buildId].join("/")).normalize() + println "${buildUrl}" + return [setupBuildId: buildId, setupBuildUrl: buildUrl] +} + +// Stage 4 (copy artifacts): copy artifacts from the setup job, verify sha1, compute version/build description, and extract the source tarball. Returns the resolved sha1/version and any extra env props from dist/other_envvars for the caller to thread into env. +def doCopyArtifactsStage(Map args) { + def artifact_filter = "dist/sha1,dist/version,dist/other_envvars,dist/ceph-*.tar.bz2" + def os = get_os_info(args.dist) + if ( args.ciCompile && os.pkg_type == "deb" ) { + artifact_filter += ",dist/ceph_*.diff.gz,dist/ceph_*.dsc" + } + println artifact_filter + copyArtifacts( + projectName: args.setupJob, + selector: specific(buildNumber: args.setupBuildId), + filter: artifact_filter, + ) + sh "sudo journalctl --show-cursor -n 0 --no-pager | tail -n1 | cut -d' ' -f3 > ${args.workspace}/cursor" + def sha1_input = args.sha1 + def sha1_trimmed = sha1_input?.trim()?.toLowerCase() + def sha1_props = readProperties file: "${args.workspace}/dist/sha1" + def sha1_from_artifact = sha1_props.SHA1.trim().toLowerCase() + def sha1 = sha1_input + if ( sha1_input && sha1_from_artifact != sha1_trimmed ) { + error message: "SHA1 from artifact (${sha1_from_artifact}) does not match parameter value (${sha1_trimmed})" + } else if ( ! sha1_input ) { + sha1 = sha1_from_artifact + } + println "SHA1=${sha1_trimmed}" + def version = readFile(file: "${args.workspace}/dist/version").trim() + // In a release build, dist/other_envvars contains CEPH_REPO and chacra_url + // as written during ceph-source-dist but we don't want to define + // ceph-releases.git or chacra.ceph.com as parameters for ceph-dev-pipeline. + def extra_env = readProperties file: "${args.workspace}/dist/other_envvars" + // Apply prop overrides on top of inputs for the UI fields rendered below. + def branch = extra_env.BRANCH ?: args.branch + def ceph_repo = extra_env.CEPH_REPO ?: args.cephRepo + def effective_sha1 = extra_env.SHA1 ?: sha1 + def branch_ui_value = branch + def sha1_ui_value = effective_sha1 + if (ceph_repo?.find(/https?:\/\/github.com\//)) { + // If this is a release build, link to ceph-release.git's $BRANCH-release branch + def suffix = (args.releaseBuild?.trim() == "true") ? "-release" : "" + + def branch_url = "${ceph_repo}/tree/${branch}${suffix}" + branch_ui_value = "${branch}${suffix}" + def commit_url = "${ceph_repo}/commit/${effective_sha1}" + sha1_ui_value = "${effective_sha1}" + } + def shaman_url = "https://shaman.ceph.com/builds/ceph/${branch}/${effective_sha1}" + def build_description = """\ + BRANCH=${branch_ui_value}
+ SHA1=${sha1_ui_value}
+ VERSION=${version}
+ DISTROS=${args.distros}
+ ARCHS=${args.archs}
+ FLAVORS=${args.flavors}
+ SETUP_BUILD_ID=${args.setupBuildId}
+ shaman builds for this branch+commit + """.stripIndent() + buildDescription build_description + sh "sha256sum dist/*" + sh "cat dist/sha1 dist/version" + sh """#!/bin/bash + set -ex + cd dist + mkdir ceph + tar --strip-components=1 -C ceph -xjf ceph-${version}.tar.bz2 ceph-${version}/{container,ceph.spec,ceph.spec.in,debian,Dockerfile.build,do_cmake.sh,install-deps.sh,run-make-check.sh,make-debs.sh,make-dist,make-srpm.sh,src/script} + """ + return [sha1: effective_sha1, version: version, extraEnv: extra_env] +} + +// Stage 5 (check for built packages): check chacra for an existing build (and disable build_matrix entry if found, unless force) and set up the Pulp client if needed. +def doCheckForBuiltPackagesStage(Map args) { + sh './scripts/setup_chacractl.sh' + def chacra_url = sh( + script: '''grep url ~/.chacractl | cut -d'"' -f2''', + returnStdout: true, + ).trim() + def os = get_os_info(args.dist) + def chacra_endpoint = "ceph/${args.branch}/${args.sha1}/${os.name}/${os.version_name}/${args.arch}/flavors/${args.flavor}/" + def chacractl_rc = sh( + script: "${args.home}/.local/bin/chacractl exists binaries/${chacra_endpoint}", + returnStatus: true, + ) + if ( chacractl_rc == 0 && args.force != "true" ) { + println("Skipping compilation since chacra already has artifacts. To override, use THROWAWAY=true (to skip this check) or FORCE=true (to re-upload artifacts).") + build_matrix["${args.dist}_${args.arch}"] = false + } + + // Set up Pulp client + if ( args.pulpUpload == "true" ) { + withCredentials([ + usernamePassword(credentialsId: 'pulp-auth', usernameVariable: 'PULP_USERNAME', passwordVariable: 'PULP_PASSWORD') + ]) { + sh './scripts/setup_pulp.sh' + } + } +} + +// Stage 6 (builder container): log into container registries and pull/build/push the ceph-build container image for this matrix cell. Returns the image name. +def doBuilderContainerStage(Map args) { + def cephBuilderImage = "${args.containerRepoHostname}/${args.containerRepoOrganization}/ceph-build" + withEnv([ + "CONTAINER_REPO_CREDS_USR=${args.containerRepoCredsUsr}", + "CONTAINER_REPO_CREDS_PSW=${args.containerRepoCredsPsw}", + "CONTAINER_REPO_HOSTNAME=${args.containerRepoHostname}", + "CONTAINER_REPO_ORGANIZATION=${args.containerRepoOrganization}", + "DOCKER_HUB_CREDS_USR=${args.dockerHubCredsUsr}", + "DOCKER_HUB_CREDS_PSW=${args.dockerHubCredsPsw}", + ]) { + sh '''#!/bin/bash + set -ex + podman login -u ${CONTAINER_REPO_CREDS_USR} -p ${CONTAINER_REPO_CREDS_PSW} ${CONTAINER_REPO_HOSTNAME}/${CONTAINER_REPO_ORGANIZATION} + podman login -u ${DOCKER_HUB_CREDS_USR} -p ${DOCKER_HUB_CREDS_PSW} docker.io + ''' + } + def ceph_builder_tag_short = "${args.branch}.${args.dist}.${args.arch}.${args.flavor}" + def ceph_builder_tag = "${args.sha1[0..6]}.${ceph_builder_tag_short}" + sh """#!/bin/bash -ex + podman pull ${cephBuilderImage}:${ceph_builder_tag} || \ + podman pull ${cephBuilderImage}:${ceph_builder_tag_short} || \ + true + """ + def withCrimson = !(args.branch in ['tentacle', 'squid', 'reef']) + sh """#!/bin/bash + set -ex + echo > .env + echo "WITH_CRIMSON=${withCrimson}" >> .env + cd dist/ceph + python3 src/script/build-with-container.py --env-file=${args.workspace}/.env --image-repo=${cephBuilderImage} --tag=${ceph_builder_tag} --image-variant=packages -d ${args.dist} -e build-container + podman tag ${cephBuilderImage}:${ceph_builder_tag} ${cephBuilderImage}:${ceph_builder_tag_short} + """ + sh """#!/bin/bash -ex + podman push ${cephBuilderImage}:${ceph_builder_tag_short} + podman push ${cephBuilderImage}:${ceph_builder_tag} + """ + return cephBuilderImage +} + +// Stage 7 (build): run the actual package build via build-with-container.py: assemble cmake/sccache/dwz flags per distro+flavor, then extract cephadm. +def doBuildStage(Map args) { + def os = get_os_info(args.dist) + sh "./scripts/update_shaman.sh started ceph ${os.name} ${os.version_name} ${args.arch}" + def ceph_builder_tag = "${args.sha1[0..6]}.${args.branch}.${args.dist}.${args.arch}.${args.flavor}" + def bwc_command_base = "python3 src/script/build-with-container.py --image-repo=${args.cephBuilderImage} --tag=${ceph_builder_tag} -d ${args.dist} --image-variant=packages --ceph-version ${args.version}" + def bwc_command = bwc_command_base + def bwc_cmd_sccache_flags = "" + if ( args.dwz == "false" ) { + sh """#!/bin/bash + echo "DWZ=${args.dwz}" >> .env + """ + bwc_cmd_sccache_flags = "--env-file=${args.workspace}/.env"; + } + if ( args.sccache == "true" ) { + sh """#!/bin/bash + echo "SCCACHE=${args.sccache}" >> .env + echo "SCCACHE_CONF=/ceph/sccache.conf" >> .env + echo "SCCACHE_ERROR_LOG=/ceph/sccache_log.txt" >> .env + echo "SCCACHE_LOG=debug" >> .env + echo "AWS_ACCESS_KEY_ID=${args.sccacheBucketCredsUsr}" >> .env + echo "AWS_SECRET_ACCESS_KEY=${args.sccacheBucketCredsPsw}" >> .env + echo "CEPH_BUILD_NORMALIZE_PATHS=true" >> .env + """ + // TODO: un-hardcode this + writeFile( + file: "dist/ceph/sccache.conf", + text: """\ + [cache.s3] + bucket = "ceph-sccache" + endpoint = "s3.us-south.cloud-object-storage.appdomain.cloud" + use_ssl = true + key_prefix = "" + server_side_encryption = false + no_credentials = false + region = "auto" + """ + ) + bwc_cmd_sccache_flags = "--env-file=${args.workspace}/.env"; + } + def ceph_extra_cmake_args = ""; + def deb_build_profiles = ""; + switch (args.flavor) { + case "default": + ceph_extra_cmake_args += " -DALLOCATOR=tcmalloc" + ceph_extra_cmake_args += " -DWITH_SYSTEM_BOOST=OFF -DWITH_BOOST_VALGRIND=ON" + if (os.version_name == "focal") { + ceph_extra_cmake_args += " -DWITH_STATIC_LIBSTDCXX=ON" + } + break + case "debug": + ceph_extra_cmake_args += " -DCMAKE_BUILD_TYPE=Debug" + break + default: + println "FLAVOR=${args.flavor} is invalid" + assert false + } + bwc_command = "${bwc_command} ${bwc_cmd_sccache_flags}" + if ( os.pkg_type == "deb" ) { + def sccache_flag = "-DWITH_SCCACHE=ON" + if ( args.sccache == "true" && ! ceph_extra_cmake_args.contains(sccache_flag) ) { + ceph_extra_cmake_args += " ${sccache_flag}" + } + if ( deb_build_profiles ) { + sh """#!/bin/bash + echo "DEB_BUILD_PROFILES=${deb_build_profiles}" >> .env + """ + } + bwc_command = "${bwc_command} -e debs" + } else if ( args.dist =~ /^(centos|rhel|rocky|fedora).*/ ) { + def rpmbuild_args = "" + if ( args.sccache == "true" ) rpmbuild_args += " -R--with=sccache" + if ( args.dwz == "false" ) rpmbuild_args += " -R--without=dwz" + if ( args.flavor == "default" ) rpmbuild_args += " -R--with=tcmalloc" + bwc_command = "${bwc_command}${rpmbuild_args} -e rpm" + } else if ( args.dist =~ /suse|sles/ ) { + throw new Exception("bwc not implemented for ${args.dist}") + } else if ( args.dist =~ /windows/ ) { + throw new Exception("bwc not implemented for ${args.dist}") + } else { + throw new Exception("DIST '${args.dist}' is invalid!") + } + sh """#!/bin/bash + echo "CEPH_EXTRA_CMAKE_ARGS=${ceph_extra_cmake_args}" >> .env + """ + sh """#!/bin/bash -ex + cd dist/ceph + ln ../ceph-${args.version}.tar.bz2 . + ${bwc_command} + """ + if ( os.pkg_type == "deb" ) { + sh """#!/bin/bash -ex + cd dist/ceph + ${bwc_command_base} -e custom -- "dpkg-deb --fsys-tarfile /ceph/debs/*/pool/main/c/ceph/cephadm_${args.version}*.deb | tar -x -f - --strip-components=3 ./usr/sbin/cephadm" + ln ./cephadm ../../ + """ + } else if ( args.dist =~ /^(centos|rhel|rocky|fedora).*/ ) { + sh """#!/bin/bash -ex + cd dist/ceph + ${bwc_command_base} -e custom -- "rpm2cpio /ceph/rpmbuild/RPMS/noarch/cephadm-*.rpm | cpio -i --to-stdout *sbin/cephadm > cephadm" + ln ./cephadm ../../ + """ + } +} + +// Stage 7 (build) post-always: archive the sccache log and remove .qa symlinks Jenkins gets stuck recursing into. +def doBuildPostAlways(Map args) { + if (fileExists('dist/ceph/sccache_log.txt')) { + sh """ + if [ -f "${args.workspace}/dist/ceph/sccache_log.txt" ]; then + ln dist/ceph/sccache_log.txt sccache_log_${args.dist}_${args.arch}_${args.flavor}.txt + fi + """ + // The below is to work around an issue where Jenkins would recurse into + // dist/ceph/qa and get stuck trying to follow the .qa symlinks. This was + // discovered by seeing many messages about "too many levels of symbolic links" + // in the system journal. + sh "find ${args.workspace}/dist/ceph/ -name .qa -exec rm {} \\;" + archiveArtifacts( + artifacts: 'sccache_log*.txt', + allowEmptyArchive: true, + fingerprint: true, + ) + } +} + +// Stage 8 (upload packages): build the ceph-release rpm (for rpm distros) and upload the packages to chacra and optionally Pulp. +def doUploadPackagesStage(Map args) { + def chacra_url = sh( + script: '''grep url ~/.chacractl | cut -d'"' -f2''', + returnStdout: true, + ).trim() + def os = get_os_info(args.dist) + // Push packages to chacra.ceph.com under the 'test' ref if ceph-release-pipeline's TEST=true. + // Local override only; we don't propagate this back to env since no later stage reads it. + def sha1 = args.test?.toBoolean() ? 'test' : args.sha1 + if ( os.pkg_type == "rpm" ) { + sh """#!/bin/bash + set -ex + cd ./dist/ceph + mkdir -p ./rpmbuild/SRPMS/ + ln ceph-*.src.rpm ./rpmbuild/SRPMS/ + """ + def spec_text = get_ceph_release_spec_text("${chacra_url}r/ceph/${args.branch}/${sha1}/${os.name}/${os.version_name}/flavors/${args.flavor}/") + writeFile( + file: "dist/ceph/rpmbuild/SPECS/ceph-release.spec", + text: spec_text, + ) + def repo_text = get_ceph_release_repo_text("${chacra_url}/r/ceph/${args.branch}/${sha1}/${os.name}/${os.version_name}/flavors/${args.flavor}") + writeFile( + file: "dist/ceph/rpmbuild/SOURCES/ceph.repo", + text: repo_text, + ) + def ceph_builder_tag = "${sha1[0..6]}.${args.branch}.${args.dist}.${args.arch}.${args.flavor}" + def bwc_command_base = "python3 src/script/build-with-container.py --image-repo=${args.cephBuilderImage} --tag=${ceph_builder_tag} -d ${args.dist} --image-variant=packages --ceph-version ${args.version}" + def bwc_command = "${bwc_command_base} -e custom -- rpmbuild -bb --define \\'_topdir /ceph/rpmbuild\\' /ceph/rpmbuild/SPECS/ceph-release.spec" + sh """#!/bin/bash + set -ex + cd ${args.workspace}/dist/ceph + ${bwc_command} + """ + } + sh """#!/bin/bash + export CHACRA_URL="${chacra_url}" + export OS_NAME="${os.name}" + export OS_VERSION="${os.version}" + export OS_VERSION_NAME="${os.version_name}" + export OS_PKG_TYPE="${os.pkg_type}" + if [ "${args.throwaway}" != "true" ]; then ./scripts/chacra_upload.sh; fi + """ + + sh """#!/bin/bash + if [ "${args.throwaway}" != "true" ] && [ "${args.pulpUpload}" == "true" ]; then + export CEPH_VERSION="${args.version}" + export OS_NAME="${os.name}" + export OS_VERSION="${os.version}" + export OS_VERSION_NAME="${os.version_name}" + export OS_PKG_TYPE="${os.pkg_type}" + export SHA1="${sha1}" + export FLAVOR="${args.flavor}" + + ./scripts/pulp_upload.sh + else + echo "Skipping pulp upload because PULP_UPLOAD=${args.pulpUpload}" + fi + """ +} + +// Stage 9 (container): build the Ceph container image via scripts/build_container. +def doContainerStage(Map args) { + def os = get_os_info(args.dist) + def cephver = args.version.trim() + withEnv([ + "CONTAINER_REPO_USERNAME=${args.containerRepoCredsUsr}", + "CONTAINER_REPO_PASSWORD=${args.containerRepoCredsPsw}", + ]) { + sh """#!/bin/bash + export DISTRO=${os.name} + export RELEASE=${os.version} + export cephver=${cephver} + if [ "${args.pulpRegistryUpload}" == "true" ]; then + export REMOVE_LOCAL_IMAGES=false + fi + ./scripts/build_container + """ + } +} + +// Stage 10 (registry upload): mirror the just-built dev container image from Quay to the Pulp container registry. +def doRegistryUploadStage() { + withCredentials([ + usernamePassword( + credentialsId: 'pulp-auth', + usernameVariable: 'PULP_USERNAME', + passwordVariable: 'PULP_PASSWORD' + ) + ]) { + sh """#!/bin/bash + set -ex + ./scripts/pulp_container_push.sh + """ + } +} + pipeline { agent any stages { stage("source distribution") { steps { script { - if ( ! env.SETUP_BUILD_ID ) { - def setup_build = build( - job: env.SETUP_JOB, - parameters: [ - string(name: "BRANCH", value: env.BRANCH), - // Below are just for ceph-source-dist - string(name: "SHA1", value: env.SHA1), - string(name: "CEPH_REPO", value: env.CEPH_REPO), - string(name: "CEPH_BUILD_BRANCH", value: env.CEPH_BUILD_BRANCH), - // Below are only for actual releases - string(name: 'RELEASE_TYPE', value: env.RELEASE_TYPE ?: ''), - string(name: 'RELEASE_BUILD', value: env.RELEASE_BUILD ?: ''), - string(name: 'VERSION', value: env.VERSION ?: '') - ] - ) - env.SETUP_BUILD_ID = setup_build.getNumber() - } - println "SETUP_BUILD_ID=${env.SETUP_BUILD_ID}" - env.SETUP_BUILD_URL = new URI([env.JENKINS_URL, "job", env.SETUP_JOB, env.SETUP_BUILD_ID].join("/")).normalize() - println "${env.SETUP_BUILD_URL}" + def out = doSourceDistribution( + setupBuildId: env.SETUP_BUILD_ID, + setupJob: env.SETUP_JOB, + branch: env.BRANCH, + sha1: env.SHA1, + cephRepo: env.CEPH_REPO, + cephBuildBranch: env.CEPH_BUILD_BRANCH, + releaseType: env.RELEASE_TYPE, + releaseBuild: env.RELEASE_BUILD, + version: env.VERSION, + jenkinsUrl: env.JENKINS_URL, + ) + env.SETUP_BUILD_ID = out.setupBuildId + env.SETUP_BUILD_URL = out.setupBuildUrl } } } @@ -225,6 +605,7 @@ pipeline { } } stages { + // Stage 2 (node): seed build_matrix for this cell, log the assigned node, and install the container runtime. Kept inline (no helper) so it can read the matrix-axis bindings DIST/ARCH/FLAVOR directly. stage("node") { steps { script { @@ -239,6 +620,7 @@ pipeline { sh "cat /etc/os-release" } } + // Stage 3 (checkout ceph-build): clone the ceph-build repo into the workspace. Kept inline because it's a single declarative `checkout` step with no script-block logic. stage("checkout ceph-build") { steps { checkout scmGit( @@ -253,71 +635,25 @@ pipeline { stage("copy artifacts") { steps { script { - def artifact_filter = "dist/sha1,dist/version,dist/other_envvars,dist/ceph-*.tar.bz2" - def os = get_os_info(env.DIST) - if ( env.CI_COMPILE && os.pkg_type == "deb" ) { - artifact_filter += ",dist/ceph_*.diff.gz,dist/ceph_*.dsc" - } - println artifact_filter - copyArtifacts( - projectName: env.SETUP_JOB, - selector: specific(buildNumber: env.SETUP_BUILD_ID), - filter: artifact_filter, + def out = doCopyArtifactsStage( + setupJob: env.SETUP_JOB, + setupBuildId: env.SETUP_BUILD_ID, + setupBuildUrl: env.SETUP_BUILD_URL, + ciCompile: env.CI_COMPILE, + dist: env.DIST, + workspace: env.WORKSPACE, + sha1: env.SHA1, + cephRepo: env.CEPH_REPO, + releaseBuild: env.RELEASE_BUILD, + branch: env.BRANCH, + distros: env.DISTROS, + archs: env.ARCHS, + flavors: env.FLAVORS, ) + env.SHA1 = out.sha1 + env.VERSION = out.version + out.extraEnv.each { k, v -> env."${k}" = v } } - sh 'sudo journalctl --show-cursor -n 0 --no-pager | tail -n1 | cut -d\" \" -f3 > $WORKSPACE/cursor' - script { - def sha1_trimmed = env.SHA1.trim().toLowerCase() - def sha1_props = readProperties file: "${WORKSPACE}/dist/sha1" - sha1_from_artifact = sha1_props.SHA1.trim().toLowerCase() - if ( env.SHA1 && sha1_from_artifact != sha1_trimmed ) { - error message: "SHA1 from artifact (${sha1_from_artifact}) does not match parameter value (${sha1_trimmed})" - } else if ( ! env.SHA1 ) { - env.SHA1 = sha1_from_artifact - } - println "SHA1=${sha1_trimmed}" - env.VERSION = readFile(file: "${WORKSPACE}/dist/version").trim() - script { - // In a release build, dist/other_envvars contains CEPH_REPO, and chacra_url - // as written during ceph-source-dist but we don't to be able to define - // ceph-releases.git or chacra.ceph.com as parameters for ceph-dev-pipeline. - def props = readProperties file: "${WORKSPACE}/dist/other_envvars" - for (def key in props.keySet()) { - env."${key}" = props[key] - } - } - def branch_ui_value = env.BRANCH - def sha1_ui_value = env.SHA1 - if (env.CEPH_REPO?.find(/https?:\/\/github.com\//)) { - // If this is a release build, link to ceph-release.git's $BRANCH-release branch - def suffix = (env.RELEASE_BUILD?.trim() == "true") ? "-release" : "" - - def branch_url = "${env.CEPH_REPO}/tree/${env.BRANCH}${suffix}" - branch_ui_value = "${env.BRANCH}${suffix}" - def commit_url = "${env.CEPH_REPO}/commit/${env.SHA1}" - sha1_ui_value = "${env.SHA1}" - } - def shaman_url = "https://shaman.ceph.com/builds/ceph/${env.BRANCH}/${env.SHA1}" - def build_description = """\ - BRANCH=${branch_ui_value}
- SHA1=${sha1_ui_value}
- VERSION=${env.VERSION}
- DISTROS=${env.DISTROS}
- ARCHS=${env.ARCHS}
- FLAVORS=${env.FLAVORS}
- SETUP_BUILD_ID=${env.SETUP_BUILD_ID}
- shaman builds for this branch+commit - """.stripIndent() - buildDescription build_description - } - sh "sha256sum dist/*" - sh "cat dist/sha1 dist/version" - sh '''#!/bin/bash - set -ex - cd dist - mkdir ceph - tar --strip-components=1 -C ceph -xjf ceph-${VERSION}.tar.bz2 ceph-${VERSION}/{container,ceph.spec,ceph.spec.in,debian,Dockerfile.build,do_cmake.sh,install-deps.sh,run-make-check.sh,make-debs.sh,make-dist,make-srpm.sh,src/script} - ''' } } stage("check for built packages") { @@ -331,30 +667,16 @@ pipeline { } steps { script { - sh './scripts/setup_chacractl.sh' - def chacra_url = sh( - script: '''grep url ~/.chacractl | cut -d'"' -f2''', - returnStdout: true, - ).trim() - def os = get_os_info(env.DIST) - def chacra_endpoint = "ceph/${env.BRANCH}/${env.SHA1}/${os.name}/${os.version_name}/${env.ARCH}/flavors/${env.FLAVOR}/" - def chacractl_rc = sh( - script: "$HOME/.local/bin/chacractl exists binaries/${chacra_endpoint}", - returnStatus: true, + doCheckForBuiltPackagesStage( + dist: env.DIST, + branch: env.BRANCH, + sha1: env.SHA1, + arch: env.ARCH, + flavor: env.FLAVOR, + home: env.HOME, + force: env.FORCE, + pulpUpload: env.PULP_UPLOAD, ) - if ( chacractl_rc == 0 && env.FORCE != "true" ) { - println("Skipping compilation since chacra already has artifacts. To override, use THROWAWAY=true (to skip this check) or FORCE=true (to re-upload artifacts).") - build_matrix["${DIST}_${ARCH}"] = false - } - - // Set up Pulp client - if ( env.PULP_UPLOAD == "true" ) { - withCredentials([ - usernamePassword(credentialsId: 'pulp-auth', usernameVariable: 'PULP_USERNAME', passwordVariable: 'PULP_PASSWORD') - ]) { - sh './scripts/setup_pulp.sh' - } - } } } } @@ -368,32 +690,20 @@ pipeline { } steps { script { - env.CEPH_BUILDER_IMAGE = "${env.CONTAINER_REPO_HOSTNAME}/${env.CONTAINER_REPO_ORGANIZATION}/ceph-build" - sh '''#!/bin/bash - set -ex - podman login -u ${CONTAINER_REPO_CREDS_USR} -p ${CONTAINER_REPO_CREDS_PSW} ${CONTAINER_REPO_HOSTNAME}/${CONTAINER_REPO_ORGANIZATION} - podman login -u ${DOCKER_HUB_CREDS_USR} -p ${DOCKER_HUB_CREDS_PSW} docker.io - ''' - def ceph_builder_tag_short = "${env.BRANCH}.${env.DIST}.${ARCH}.${FLAVOR}" - def ceph_builder_tag = "${env.SHA1[0..6]}.${ceph_builder_tag_short}" - sh """#!/bin/bash -ex - podman pull ${env.CEPH_BUILDER_IMAGE}:${ceph_builder_tag} || \ - podman pull ${env.CEPH_BUILDER_IMAGE}:${ceph_builder_tag_short} || \ - true - """ - def withCrimson = !(env.BRANCH in ['tentacle', 'squid', 'reef']) - sh """#!/bin/bash - set -ex - echo > .env - echo "WITH_CRIMSON=${withCrimson}" >> .env - cd dist/ceph - python3 src/script/build-with-container.py --env-file=${env.WORKSPACE}/.env --image-repo=${env.CEPH_BUILDER_IMAGE} --tag=${ceph_builder_tag} --image-variant=packages -d ${DIST} -e build-container - podman tag ${env.CEPH_BUILDER_IMAGE}:${ceph_builder_tag} ${env.CEPH_BUILDER_IMAGE}:${ceph_builder_tag_short} - """ - sh """#!/bin/bash -ex - podman push ${env.CEPH_BUILDER_IMAGE}:${ceph_builder_tag_short} - podman push ${env.CEPH_BUILDER_IMAGE}:${ceph_builder_tag} - """ + env.CEPH_BUILDER_IMAGE = doBuilderContainerStage( + containerRepoHostname: env.CONTAINER_REPO_HOSTNAME, + containerRepoOrganization: env.CONTAINER_REPO_ORGANIZATION, + containerRepoCredsUsr: env.CONTAINER_REPO_CREDS_USR, + containerRepoCredsPsw: env.CONTAINER_REPO_CREDS_PSW, + dockerHubCredsUsr: env.DOCKER_HUB_CREDS_USR, + dockerHubCredsPsw: env.DOCKER_HUB_CREDS_PSW, + branch: env.BRANCH, + dist: env.DIST, + arch: env.ARCH, + flavor: env.FLAVOR, + sha1: env.SHA1, + workspace: env.WORKSPACE, + ) } } } @@ -407,137 +717,37 @@ pipeline { } steps { script { - def os = get_os_info(env.DIST) - sh "./scripts/update_shaman.sh started ceph ${os.name} ${os.version_name} $ARCH" - env.AWS_ACCESS_KEY_ID = env.SCCACHE_BUCKET_CREDS_USR - env.AWS_SECRET_ACCESS_KEY = env.SCCACHE_BUCKET_CREDS_PSW - def ceph_builder_tag = "${env.SHA1[0..6]}.${env.BRANCH}.${env.DIST}.${ARCH}.${FLAVOR}" - def bwc_command_base = "python3 src/script/build-with-container.py --image-repo=${env.CEPH_BUILDER_IMAGE} --tag=${ceph_builder_tag} -d ${DIST} --image-variant=packages --ceph-version ${env.VERSION}" - def bwc_command = bwc_command_base - def bwc_cmd_sccache_flags = "" - if ( env.DWZ == "false" ) { - sh '''#!/bin/bash - echo "DWZ=$DWZ" >> .env - ''' - bwc_cmd_sccache_flags = "--env-file=${env.WORKSPACE}/.env"; - } - if ( env.SCCACHE == "true" ) { - sh '''#!/bin/bash - echo "SCCACHE=$SCCACHE" >> .env - echo "SCCACHE_CONF=/ceph/sccache.conf" >> .env - echo "SCCACHE_ERROR_LOG=/ceph/sccache_log.txt" >> .env - echo "SCCACHE_LOG=debug" >> .env - echo "AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" >> .env - echo "AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" >> .env - echo "CEPH_BUILD_NORMALIZE_PATHS=true" >> .env - ''' - // TODO: un-hardcode this - writeFile( - file: "dist/ceph/sccache.conf", - text: """\ - [cache.s3] - bucket = "ceph-sccache" - endpoint = "s3.us-south.cloud-object-storage.appdomain.cloud" - use_ssl = true - key_prefix = "" - server_side_encryption = false - no_credentials = false - region = "auto" - """ - ) - bwc_cmd_sccache_flags = "--env-file=${env.WORKSPACE}/.env"; - } - def ceph_extra_cmake_args = ""; - def deb_build_profiles = ""; - switch (env.FLAVOR) { - case "default": - ceph_extra_cmake_args += " -DALLOCATOR=tcmalloc" - ceph_extra_cmake_args += " -DWITH_SYSTEM_BOOST=OFF -DWITH_BOOST_VALGRIND=ON" - if (os.version_name == "focal") { - ceph_extra_cmake_args += " -DWITH_STATIC_LIBSTDCXX=ON" - } - break - case "debug": - ceph_extra_cmake_args += " -DCMAKE_BUILD_TYPE=Debug" - break - default: - println "FLAVOR=${env.FLAVOR} is invalid" - assert false - } - bwc_command = "${bwc_command} ${bwc_cmd_sccache_flags}" - if ( os.pkg_type == "deb" ) { - def sccache_flag = "-DWITH_SCCACHE=ON" - if ( env.SCCACHE == "true" && ! ceph_extra_cmake_args.contains(sccache_flag) ) { - ceph_extra_cmake_args += " ${sccache_flag}" - } - if ( deb_build_profiles ) { - sh """#!/bin/bash - echo "DEB_BUILD_PROFILES=${deb_build_profiles}" >> .env - """ - } - bwc_command = "${bwc_command} -e debs" - } else if ( env.DIST =~ /^(centos|rhel|rocky|fedora).*/ ) { - def rpmbuild_args = "" - if ( env.SCCACHE == "true" ) rpmbuild_args += " -R--with=sccache" - if ( env.DWZ == "false" ) rpmbuild_args += " -R--without=dwz" - if ( env.FLAVOR == "default" ) rpmbuild_args += " -R--with=tcmalloc" - bwc_command = "${bwc_command}${rpmbuild_args} -e rpm" - } else if ( env.DIST =~ /suse|sles/ ) { - throw new Exception("bwc not implemented for ${env.DIST}") - } else if ( env.DIST =~ /windows/ ) { - throw new Exception("bwc not implemented for ${env.DIST}") - } else { - throw new Exception("DIST '${env.DIST}' is invalid!") - } - sh """#!/bin/bash - echo "CEPH_EXTRA_CMAKE_ARGS=${ceph_extra_cmake_args}" >> .env - """ - sh """#!/bin/bash -ex - cd dist/ceph - ln ../ceph-${env.VERSION}.tar.bz2 . - ${bwc_command} - """ - if ( os.pkg_type == "deb" ) { - sh """#!/bin/bash -ex - cd dist/ceph - ${bwc_command_base} -e custom -- "dpkg-deb --fsys-tarfile /ceph/debs/*/pool/main/c/ceph/cephadm_${VERSION}*.deb | tar -x -f - --strip-components=3 ./usr/sbin/cephadm" - ln ./cephadm ../../ - """ - } else if ( env.DIST =~ /^(centos|rhel|rocky|fedora).*/ ) { - sh """#!/bin/bash -ex - cd dist/ceph - ${bwc_command_base} -e custom -- "rpm2cpio /ceph/rpmbuild/RPMS/noarch/cephadm-*.rpm | cpio -i --to-stdout *sbin/cephadm > cephadm" - ln ./cephadm ../../ - """ - } + doBuildStage( + dist: env.DIST, + sccacheBucketCredsUsr: env.SCCACHE_BUCKET_CREDS_USR, + sccacheBucketCredsPsw: env.SCCACHE_BUCKET_CREDS_PSW, + sha1: env.SHA1, + branch: env.BRANCH, + arch: env.ARCH, + flavor: env.FLAVOR, + cephBuilderImage: env.CEPH_BUILDER_IMAGE, + version: env.VERSION, + dwz: env.DWZ, + sccache: env.SCCACHE, + workspace: env.WORKSPACE, + ) } } post { always { script { - if (fileExists('dist/ceph/sccache_log.txt')) { - sh """ - if [ -f "${env.WORKSPACE}/dist/ceph/sccache_log.txt" ]; then - ln dist/ceph/sccache_log.txt sccache_log_${env.DIST}_${env.ARCH}_${env.FLAVOR}.txt - fi - """ - // The below is to work around an issue where Jenkins would recurse into - // dist/ceph/qa and get stuck trying to follow the .qa symlinks. This was - // discovered by seeing many messages about "too many levels of symbolic links" - // in the system journal. - sh "find ${env.WORKSPACE}/dist/ceph/ -name .qa -exec rm {} \\;" - archiveArtifacts( - artifacts: 'sccache_log*.txt', - allowEmptyArchive: true, - fingerprint: true, - ) - } + doBuildPostAlways( + workspace: env.WORKSPACE, + dist: env.DIST, + arch: env.ARCH, + flavor: env.FLAVOR, + ) } } unsuccessful { script { def os = get_os_info(env.DIST) - sh "./scripts/update_shaman.sh failed ceph ${os.name} ${os.version_name} $ARCH" + sh "./scripts/update_shaman.sh failed ceph ${os.name} ${os.version_name} ${env.ARCH}" } } } @@ -552,76 +762,32 @@ pipeline { } steps { script { - def chacra_url = sh( - script: '''grep url ~/.chacractl | cut -d'"' -f2''', - returnStdout: true, - ).trim() - def os = get_os_info(env.DIST) - if ( os.pkg_type == "rpm" ) { - sh """#!/bin/bash - set -ex - cd ./dist/ceph - mkdir -p ./rpmbuild/SRPMS/ - ln ceph-*.src.rpm ./rpmbuild/SRPMS/ - """ - // Push packages to chacra.ceph.com under the 'test' ref if ceph-release-pipeline's TEST=true - env.SHA1 = env.TEST?.toBoolean() ? 'test' : env.SHA1 - def spec_text = get_ceph_release_spec_text("${chacra_url}r/ceph/${env.BRANCH}/${env.SHA1}/${os.name}/${os.version_name}/flavors/${env.FLAVOR}/") - writeFile( - file: "dist/ceph/rpmbuild/SPECS/ceph-release.spec", - text: spec_text, - ) - def repo_text = get_ceph_release_repo_text("${chacra_url}/r/ceph/${env.BRANCH}/${env.SHA1}/${os.name}/${os.version_name}/flavors/${env.FLAVOR}") - writeFile( - file: "dist/ceph/rpmbuild/SOURCES/ceph.repo", - text: repo_text, - ) - def ceph_builder_tag = "${env.SHA1[0..6]}.${env.BRANCH}.${env.DIST}.${ARCH}.${FLAVOR}" - def bwc_command_base = "python3 src/script/build-with-container.py --image-repo=${env.CEPH_BUILDER_IMAGE} --tag=${ceph_builder_tag} -d ${DIST} --image-variant=packages --ceph-version ${env.VERSION}" - bwc_command = "${bwc_command_base} -e custom -- rpmbuild -bb --define \\'_topdir /ceph/rpmbuild\\' /ceph/rpmbuild/SPECS/ceph-release.spec" - sh """#!/bin/bash - set -ex - cd $WORKSPACE/dist/ceph - ${bwc_command} - """ - } - sh """#!/bin/bash - export CHACRA_URL="${chacra_url}" - export OS_NAME="${os.name}" - export OS_VERSION="${os.version}" - export OS_VERSION_NAME="${os.version_name}" - export OS_PKG_TYPE="${os.pkg_type}" - if [ "$THROWAWAY" != "true" ]; then ./scripts/chacra_upload.sh; fi - """ - - sh """#!/bin/bash - if [ "$THROWAWAY" != "true" ] && [ "$PULP_UPLOAD" == "true" ]; then - export CEPH_VERSION="${env.VERSION}" - export OS_NAME="${os.name}" - export OS_VERSION="${os.version}" - export OS_VERSION_NAME="${os.version_name}" - export OS_PKG_TYPE="${os.pkg_type}" - export SHA1="${env.SHA1}" - export FLAVOR="${env.FLAVOR}" - - ./scripts/pulp_upload.sh - else - echo "Skipping pulp upload because PULP_UPLOAD=$PULP_UPLOAD" - fi - """ + doUploadPackagesStage( + dist: env.DIST, + test: env.TEST, + branch: env.BRANCH, + sha1: env.SHA1, + flavor: env.FLAVOR, + cephBuilderImage: env.CEPH_BUILDER_IMAGE, + arch: env.ARCH, + version: env.VERSION, + workspace: env.WORKSPACE, + throwaway: env.THROWAWAY, + pulpUpload: env.PULP_UPLOAD, + ) } } post { success { script { def os = get_os_info(env.DIST) - sh "./scripts/update_shaman.sh completed ceph ${os.name} ${os.version_name} $ARCH" + sh "./scripts/update_shaman.sh completed ceph ${os.name} ${os.version_name} ${env.ARCH}" } } unsuccessful { script { def os = get_os_info(env.DIST) - sh "./scripts/update_shaman.sh failed ceph ${os.name} ${os.version_name} $ARCH" + sh "./scripts/update_shaman.sh failed ceph ${os.name} ${os.version_name} ${env.ARCH}" } } } @@ -635,19 +801,13 @@ pipeline { } steps { script { - env.CONTAINER_REPO_USERNAME = env.CONTAINER_REPO_CREDS_USR - env.CONTAINER_REPO_PASSWORD = env.CONTAINER_REPO_CREDS_PSW - def os = get_os_info(env.DIST) - cephver = env.VERSION.trim() - sh """#!/bin/bash - export DISTRO=${os.name} - export RELEASE=${os.version} - export cephver=${cephver} - if [ "\$PULP_REGISTRY_UPLOAD" == "true" ]; then - export REMOVE_LOCAL_IMAGES=false - fi - ./scripts/build_container - """ + doContainerStage( + dist: env.DIST, + version: env.VERSION, + containerRepoCredsUsr: env.CONTAINER_REPO_CREDS_USR, + containerRepoCredsPsw: env.CONTAINER_REPO_CREDS_PSW, + pulpRegistryUpload: env.PULP_REGISTRY_UPLOAD, + ) } } } @@ -659,20 +819,7 @@ pipeline { } } steps { - script { - withCredentials([ - usernamePassword( - credentialsId: 'pulp-auth', - usernameVariable: 'PULP_USERNAME', - passwordVariable: 'PULP_PASSWORD' - ) - ]) { - sh """#!/bin/bash - set -ex - ./scripts/pulp_container_push.sh - """ - } - } + script { doRegistryUploadStage() } } } }