diff --git a/ceph-dev-pipeline/build/Jenkinsfile b/ceph-dev-pipeline/build/Jenkinsfile index af8076f64..94788b341 100644 --- a/ceph-dev-pipeline/build/Jenkinsfile +++ b/ceph-dev-pipeline/build/Jenkinsfile @@ -141,33 +141,384 @@ def get_ceph_release_repo_text(base_url) { return text.toString() } +// Stage 1 (source distribution): trigger the ceph-source-dist job and record its number/URL OR reuse SETUP_BUILD_ID. +def doSourceDistribution() { + 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}" +} + + +// 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 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 4 (copy artifacts): copy artifacts from the setup job, verify SHA1, set VERSION/build description, and extract the source tarball. +def doCopyArtifactsStage() { + 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, + ) + sh 'sudo journalctl --show-cursor -n 0 --no-pager | tail -n1 | cut -d\" \" -f3 > $WORKSPACE/cursor' + def sha1_trimmed = env.SHA1.trim().toLowerCase() + def sha1_props = readProperties file: "${env.WORKSPACE}/dist/sha1" + def 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: "${env.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 to be able to define + // ceph-releases.git or chacra.ceph.com as parameters for ceph-dev-pipeline. + def props = readProperties file: "${env.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 5 (check for built packages): check chacra for an existing build (and skip compilation if found, unless FORCE) and set up the Pulp client if needed. +def doCheckForBuiltPackagesStage() { + 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: "${env.HOME}/.local/bin/chacractl exists binaries/${chacra_endpoint}", + returnStatus: true, + ) + 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["${env.DIST}_${env.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' + } + } +} + +// Stage 6 (builder container): log into container registries and pull/build/push the ceph-build container image for this matrix cell. +def doBuilderContainerStage() { + 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}.${env.ARCH}.${env.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 ${env.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} + """ +} + +// 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() { + def os = get_os_info(env.DIST) + sh "./scripts/update_shaman.sh started ceph ${os.name} ${os.version_name} ${env.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}.${env.ARCH}.${env.FLAVOR}" + def bwc_command_base = "python3 src/script/build-with-container.py --image-repo=${env.CEPH_BUILDER_IMAGE} --tag=${ceph_builder_tag} -d ${env.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_${env.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 ../../ + """ + } +} + +// Stage 7 (build) post-always: archive the sccache log and remove .qa symlinks Jenkins gets stuck recursing into. +def doBuildPostAlways() { + 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, + ) + } +} + +// Stage 8 (upload packages): build the ceph-release rpm (for rpm distros) and upload the packages to chacra and optionally Pulp. +def doUploadPackagesStage() { + 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}.${env.ARCH}.${env.FLAVOR}" + def bwc_command_base = "python3 src/script/build-with-container.py --image-repo=${env.CEPH_BUILDER_IMAGE} --tag=${ceph_builder_tag} -d ${env.DIST} --image-variant=packages --ceph-version ${env.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 ${env.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 [ "${env.THROWAWAY}" != "true" ]; then ./scripts/chacra_upload.sh; fi + """ + + sh """#!/bin/bash + if [ "${env.THROWAWAY}" != "true" ] && [ "${env.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=${env.PULP_UPLOAD}" + fi + """ +} + +// Stage 9 (container): build the Ceph container image via scripts/build_container. +def doContainerStage() { + 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) + def 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 + """ +} + +// 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}" - } + script { doSourceDistribution() } } } stage("parallel build") { @@ -225,6 +576,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 +591,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( @@ -252,72 +605,7 @@ 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, - ) - } - 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} - ''' + script { doCopyArtifactsStage() } } } stage("check for built packages") { @@ -330,32 +618,7 @@ pipeline { SHAMAN_API_KEY = credentials('shaman-api-key') } 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, - ) - 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' - } - } - } + script { doCheckForBuiltPackagesStage() } } } stage("builder container") { @@ -367,34 +630,7 @@ pipeline { expression { return build_matrix["${DIST}_${ARCH}"] == true } } 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} - """ - } + script { doBuilderContainerStage() } } } stage("build") { @@ -406,138 +642,16 @@ pipeline { expression { return build_matrix["${DIST}_${ARCH}"] == true } } 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 ../../ - """ - } - } + script { doBuildStage() } } 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, - ) - } - } + script { doBuildPostAlways() } } 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}" } } } @@ -551,77 +665,19 @@ pipeline { expression { return build_matrix["${DIST}_${ARCH}"] == true } } 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 - """ - } + script { doUploadPackagesStage() } } 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}" } } } @@ -634,21 +690,7 @@ pipeline { CONTAINER_REPO_CREDS = credentials('quay-ceph-io-ceph-ci') } 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 - """ - } + script { doContainerStage() } } } stage("registry upload") { @@ -659,20 +701,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() } } } }