From f1167354a16f051f9c4762b17e12f0c36e96ee52 Mon Sep 17 00:00:00 2001 From: Leonardo Scalabrini Date: Tue, 3 Mar 2026 14:18:10 -0300 Subject: [PATCH 1/3] feat: Added build capi infra --- .../pipeline/qainfra/Jenkinsfile.capi.e2e | 174 ++++++++++++++++++ .../pipeline/scripts/build_capi_qa_infra.sh | 13 ++ 2 files changed, 187 insertions(+) create mode 100644 validation/pipeline/qainfra/Jenkinsfile.capi.e2e create mode 100644 validation/pipeline/scripts/build_capi_qa_infra.sh diff --git a/validation/pipeline/qainfra/Jenkinsfile.capi.e2e b/validation/pipeline/qainfra/Jenkinsfile.capi.e2e new file mode 100644 index 0000000000..dd26a67dd2 --- /dev/null +++ b/validation/pipeline/qainfra/Jenkinsfile.capi.e2e @@ -0,0 +1,174 @@ +#!groovy +library('qa-jenkins-library') +node("harvester-vpn-1") { + def workPath = "/root/go/src/github.com/rancher/tests/validation/" + def rancherRepo = "https://github.com/rancher/tests" + def jobName = "${JOB_NAME}" + if (jobName.contains('/')) { + jobNames = jobName.split('/') + jobName = jobNames[jobNames.size() - 1] + } + def buildTestContainer = "${jobName}${env.BUILD_NUMBER}-buildtest" + def cleanupTestContainer = "${jobName}${env.BUILD_NUMBER}-cleanuptest" + def imageName = "rancher-recurring-runs-validation-${jobName}${env.BUILD_NUMBER}" + def validationVolume = "RecurringRunsSharedVolume-${jobName}${env.BUILD_NUMBER}" + def envFile = ".env" + def branch = "main" + def qaInfraBranch = "main" + def qaInfraRepo = "https://github.com/rancher/qa-infra-automation" + def config = env.CONFIG + def ansibleConfig = env.ANSIBLE_CONFIG + def terraformConfig = env.TERRAFORM_CONFIG + def filename = "config.yaml" + def ansibleVarsFilename = "vars.yaml" + def terraformVarsfilename = "cluster.tfvars" + def capiConfig = env.CAPI_CONFIG + def capiAnsibleConfig = env.CAPI_ANSIBLE_CONFIG + def capiConfigFile = "capiconfig.yaml" + def harvesterConfig = "" + def harvesterConfigfilename = "local.yaml" + + if ("${env.BRANCH}" != "null" && "${env.BRANCH}" != "") { + branch = "${env.BRANCH}" + } + + if ("${env.REPO}" != "null" && "${env.REPO}" != "") { + rancherRepo = "${env.REPO}" + } + + if ("${env.QA_INFRA_REPO_BRANCH}" != "null" && "${env.QA_INFRA_REPO_BRANCH}" != "") { + qaInfraBranch = "${env.QA_INFRA_REPO_BRANCH}" + } + + if ("${env.QA_INFRA_REPO_URL}" != "null" && "${env.QA_INFRA_REPO_URL}" != "") { + qaInfraRepo = "${env.QA_INFRA_REPO_URL}" + } + + wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm', 'defaultFg': 2, 'defaultBg':1]) { + withFolderProperties { + paramsMap = [] + params.each { + if (it.value && it.value.trim() != "") { + paramsMap << "$it.key=$it.value" + } + } + withCredentials([ string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'AWS_ACCESS_KEY_ID'), + string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'AWS_SECRET_ACCESS_KEY'), + string(credentialsId: 'AWS_ACCESS_KEY_ID', variable: 'RANCHER_EKS_ACCESS_KEY'), + string(credentialsId: 'AWS_SECRET_ACCESS_KEY', variable: 'RANCHER_EKS_SECRET_KEY'), + string(credentialsId: 'AWS_SSH_PEM_KEY', variable: 'AWS_SSH_PEM_KEY'), + string(credentialsId: 'RANCHER_SSH_KEY', variable: 'RANCHER_SSH_KEY'), + string(credentialsId: 'RANCHER_REGISTRY_USER_NAME', variable: 'RANCHER_REGISTRY_USER_NAME'), + string(credentialsId: 'RANCHER_REGISTRY_PASSWORD', variable: 'RANCHER_REGISTRY_PASSWORD'), + string(credentialsId: 'ADMIN_PASSWORD', variable: 'ADMIN_PASSWORD'), + string(credentialsId: 'USER_PASSWORD', variable: 'USER_PASSWORD'), + string(credentialsId: 'RANCHER_VALID_TLS_CERT', variable: 'RANCHER_VALID_TLS_CERT'), + string(credentialsId: 'RANCHER_VALID_TLS_KEY', variable: 'RANCHER_VALID_TLS_KEY'), + string(credentialsId: 'RANCHER_BYO_TLS_CERT', variable: 'RANCHER_BYO_TLS_CERT'), + string(credentialsId: 'RANCHER_BYO_TLS_KEY', variable: 'RANCHER_BYO_TLS_KEY'), + string(credentialsId: 'QASE_AUTOMATION_TOKEN', variable: 'QASE_AUTOMATION_TOKEN')]) { + + withEnv(paramsMap) { + stage('Checkout') { + deleteDir() + dir("./tests") { + echo "cloning rancher tests" + checkout([ + $class: 'GitSCM', + branches: [[name: "*/${branch}"]], + extensions: scm.extensions + [[$class: 'CleanCheckout']], + userRemoteConfigs: [[url: rancherRepo]] + ]) + } + dir('./qa-infra-automation') { + echo "cloning qa-infra-automation repo" + checkout([ + $class: 'GitSCM', + branches: [[name: "*/${qaInfraBranch}"]], + extensions: scm.extensions + [[$class: 'CleanCheckout']], + userRemoteConfigs: [[url: qaInfraRepo]] + ]) + } + } + dir ("./") { + stage('Configure and Build') { + terraformConfig = terraformConfig.replace('${AWS_SECRET_ACCESS_KEY}', env.AWS_SECRET_ACCESS_KEY) + terraformConfig = terraformConfig.replace('${AWS_ACCESS_KEY_ID}', env.AWS_ACCESS_KEY_ID) + terraformConfig = terraformConfig.replace('${AWS_REGION}', env.AWS_REGION) + terraformConfig = terraformConfig.replace('${AWS_VPC}', env.AWS_VPC) + terraformConfig = terraformConfig.replace('${AWS_SECURITY_GROUPS}', env.AWS_SECURITY_GROUPS) + ansibleConfig = ansibleConfig.replace('${ADMIN_PASSWORD}', env.ADMIN_PASSWORD) + + + if (env.AWS_SSH_PEM_KEY && env.AWS_SSH_KEY_NAME) { + dir("./tests/.ssh") { + def decoded = new String(AWS_SSH_PEM_KEY.decodeBase64()) + writeFile file: AWS_SSH_KEY_NAME, text: decoded + sh "chmod 600 ${env.AWS_SSH_KEY_NAME}" + } + } + + dir("./tests/validation") { + writeFile file: filename, text: "" + } + + dir("./qa-infra-automation") { + dir ("./ansible") { + writeFile file: ansibleVarsFilename, text: ansibleConfig + } + dir ("./tofu/aws/modules/cluster_nodes") { + writeFile file: terraformVarsfilename, text: terraformConfig + } + dir ("./ansible/rancher/downstream/capi") { + writeFile file: ansibleVarsFilename, text: capiAnsibleConfig + writeFile file: capiConfigFile, text: capiConfig + } + } + + dir ("./") { + sh "./tests/validation/configure.sh" + sh "docker build . -f ./tests/validation/Dockerfile.e2e -t ${imageName}" + sh "docker volume create --name ${validationVolume}" + } + } + stage('Setup') { + def envText = readFile("${envFile}") + writeFile file: "${envFile}", text: envText+"BUILD_DOWNSTREAM_CLUSTER=false" + } + stage("Build Environment") { + try { + sh "docker run -v ${validationVolume}:/root --name ${buildTestContainer} -t --env-file ${envFile} " + + "${imageName} sh -c \"${workPath}pipeline/scripts/setup_environment.sh && chmod +x ${workPath}pipeline/scripts/build_capi_qa_infra.sh && ${workPath}pipeline/scripts/build_capi_qa_infra.sh\"" + } catch(err) { + container.remove([[name: buildTestContainer, image: imageName]]) + sh "docker volume rm -f ${validationVolume}" + error "Build Environment had failures." + } + } + + stage('Cleanup Rancher Environment') { + if ("${env.CLEANUP_RANCHER}" == "True" || "${env.CLEANUP_RANCHER}" == "true") { + try { + sh "docker run --volumes-from ${buildTestContainer} --name ${cleanupTestContainer} -t --env-file ${envFile} " + + "${imageName} sh -c \"${workPath}pipeline/scripts/rancher_cleanup.sh" + } catch(err) { + container.remove([[name: buildTestContainer, image: imageName], [name: cleanupTestContainer, image: imageName]]) + sh "docker volume rm -f ${validationVolume}" + error "Cleanup had failures." + } + } + } + stage('Clean Up Images and Volume') { + echo 'Cleaning test images and volume.' + container.remove([[name: buildTestContainer, image: imageName]]) + if ("${env.CLEANUP_RANCHER}" == "True" || "${env.CLEANUP_RANCHER}" == "true") { + container.remove([[name: cleanupTestContainer, image: imageName]]) + } + sh "docker volume rm -f ${validationVolume}" + } + } // dir + } // withEnv + } // creds + } // folder properties + } // wrap +} // node diff --git a/validation/pipeline/scripts/build_capi_qa_infra.sh b/validation/pipeline/scripts/build_capi_qa_infra.sh new file mode 100644 index 0000000000..3b1037ab82 --- /dev/null +++ b/validation/pipeline/scripts/build_capi_qa_infra.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -ex + +echo "Create capi cluster" + +: "${QAINFRA_SCRIPT_PATH:=/root/go/src/github.com/rancher/qa-infra-automation}" +: "${CAPI_PLAYBOOK_PATH:=ansible/rancher/downstream/capi}" +: "${CAPI_PLAYBOOK_FILE:=capi-playbook.yml}" +: "${CAPI_VARS_FILE:=vars.yaml}" + +cd "$QAINFRA_SCRIPT_PATH/$CAPI_PLAYBOOK_PATH" + +ansible-playbook "$CAPI_PLAYBOOK_FILE" -e "@$CAPI_VARS_FILE" From 4072fa0b4398d878663ffc386587d95a51e20062 Mon Sep 17 00:00:00 2001 From: Leonardo Scalabrini Date: Tue, 3 Mar 2026 15:36:25 -0300 Subject: [PATCH 2/3] feat: Added capi cluster config --- validation/pipeline/qainfra/Jenkinsfile.capi.e2e | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/validation/pipeline/qainfra/Jenkinsfile.capi.e2e b/validation/pipeline/qainfra/Jenkinsfile.capi.e2e index dd26a67dd2..838fcc0ed1 100644 --- a/validation/pipeline/qainfra/Jenkinsfile.capi.e2e +++ b/validation/pipeline/qainfra/Jenkinsfile.capi.e2e @@ -23,9 +23,10 @@ node("harvester-vpn-1") { def ansibleVarsFilename = "vars.yaml" def terraformVarsfilename = "cluster.tfvars" def capiConfig = env.CAPI_CONFIG + def capiClusterConfig = env.CAPI_CLUSTER_CONFIG def capiAnsibleConfig = env.CAPI_ANSIBLE_CONFIG def capiConfigFile = "capiconfig.yaml" - def harvesterConfig = "" + def capiClusterConfigFile = "capiclusterconfig.yaml" def harvesterConfigfilename = "local.yaml" if ("${env.BRANCH}" != "null" && "${env.BRANCH}" != "") { @@ -66,7 +67,8 @@ node("harvester-vpn-1") { string(credentialsId: 'RANCHER_VALID_TLS_KEY', variable: 'RANCHER_VALID_TLS_KEY'), string(credentialsId: 'RANCHER_BYO_TLS_CERT', variable: 'RANCHER_BYO_TLS_CERT'), string(credentialsId: 'RANCHER_BYO_TLS_KEY', variable: 'RANCHER_BYO_TLS_KEY'), - string(credentialsId: 'QASE_AUTOMATION_TOKEN', variable: 'QASE_AUTOMATION_TOKEN')]) { + string(credentialsId: 'QASE_AUTOMATION_TOKEN', variable: 'QASE_AUTOMATION_TOKEN'), + string(credentialsId: 'AWS_B64ENCODED_CREDENTIALS', variable: 'AWS_B64ENCODED_CREDENTIALS')]) { withEnv(paramsMap) { stage('Checkout') { @@ -98,6 +100,10 @@ node("harvester-vpn-1") { terraformConfig = terraformConfig.replace('${AWS_VPC}', env.AWS_VPC) terraformConfig = terraformConfig.replace('${AWS_SECURITY_GROUPS}', env.AWS_SECURITY_GROUPS) ansibleConfig = ansibleConfig.replace('${ADMIN_PASSWORD}', env.ADMIN_PASSWORD) + capiConfig = capiConfig.replace('${AWS_B64ENCODED_CREDENTIALS}', env.AWS_B64ENCODED_CREDENTIALS) + capiConfig = capiConfig.replace('${AWS_ACCESS_KEY_ID}', env.AWS_ACCESS_KEY_ID) + capiConfig = capiConfig.replace('${AWS_SECRET_ACCESS_KEY}', env.AWS_SECRET_ACCESS_KEY) + capiClusterConfig = capiClusterConfig.replace('${AWS_SSH_KEY_NAME}', env.AWS_SSH_KEY_NAME) if (env.AWS_SSH_PEM_KEY && env.AWS_SSH_KEY_NAME) { @@ -122,6 +128,7 @@ node("harvester-vpn-1") { dir ("./ansible/rancher/downstream/capi") { writeFile file: ansibleVarsFilename, text: capiAnsibleConfig writeFile file: capiConfigFile, text: capiConfig + writeFile file: capiClusterConfigFile, text: capiClusterConfig } } From 1affa05e2c571b194e767a7b5adf3cb83210a986 Mon Sep 17 00:00:00 2001 From: Leonardo Scalabrini Date: Wed, 4 Mar 2026 14:33:34 -0300 Subject: [PATCH 3/3] feat: Added JENKINS_CAPI_SSH_KEY_NAME variable --- validation/pipeline/qainfra/Jenkinsfile.capi.e2e | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/validation/pipeline/qainfra/Jenkinsfile.capi.e2e b/validation/pipeline/qainfra/Jenkinsfile.capi.e2e index 838fcc0ed1..f86a579c4a 100644 --- a/validation/pipeline/qainfra/Jenkinsfile.capi.e2e +++ b/validation/pipeline/qainfra/Jenkinsfile.capi.e2e @@ -68,7 +68,8 @@ node("harvester-vpn-1") { string(credentialsId: 'RANCHER_BYO_TLS_CERT', variable: 'RANCHER_BYO_TLS_CERT'), string(credentialsId: 'RANCHER_BYO_TLS_KEY', variable: 'RANCHER_BYO_TLS_KEY'), string(credentialsId: 'QASE_AUTOMATION_TOKEN', variable: 'QASE_AUTOMATION_TOKEN'), - string(credentialsId: 'AWS_B64ENCODED_CREDENTIALS', variable: 'AWS_B64ENCODED_CREDENTIALS')]) { + string(credentialsId: 'AWS_B64ENCODED_CREDENTIALS', variable: 'AWS_B64ENCODED_CREDENTIALS'), + string(credentialsId: 'JENKINS_CAPI_SSH_KEY_NAME', variable: 'JENKINS_CAPI_SSH_KEY_NAME')]) { withEnv(paramsMap) { stage('Checkout') { @@ -103,7 +104,7 @@ node("harvester-vpn-1") { capiConfig = capiConfig.replace('${AWS_B64ENCODED_CREDENTIALS}', env.AWS_B64ENCODED_CREDENTIALS) capiConfig = capiConfig.replace('${AWS_ACCESS_KEY_ID}', env.AWS_ACCESS_KEY_ID) capiConfig = capiConfig.replace('${AWS_SECRET_ACCESS_KEY}', env.AWS_SECRET_ACCESS_KEY) - capiClusterConfig = capiClusterConfig.replace('${AWS_SSH_KEY_NAME}', env.AWS_SSH_KEY_NAME) + capiClusterConfig = capiClusterConfig.replace('${JENKINS_CAPI_SSH_KEY_NAME}', env.JENKINS_CAPI_SSH_KEY_NAME) if (env.AWS_SSH_PEM_KEY && env.AWS_SSH_KEY_NAME) {