Remove unused legacy files, rewrite README for the actual system

~65 files carried over unmodified from the original org-wide library
(GKE/EKS-specific pipeline entry points, real Maven/Gradle/Node/Python/
PHP/Rust build stages entangled with AWS ECR/S3, GCP GAR/GCS, JFrog,
Sonar, a hardcoded internal security-scan endpoint, GitHub-specific
multi-branch scripting, BU/team org validation, and their supporting
pod templates/Helm value templates) — none directly usable without a
full rewrite regardless (same effort as what's already built for the
5 supported languages), so removed rather than kept as unused
reference. Also drops the Gradle wrapper (build.gradle, gradlew) — its
test suite was already removed in an earlier cleanup this session, so
nothing was left to build/test with it.

README.md rewrote entirely — it was still describing the old system
(eksCICD entry point, GKE/EKS, JFrog, S3, buTeamMapping) and even
referenced buildObjHelper.groovy, a file this same commit removes.
Only the live path remains: 7 stage files, 1 utility, 3 vars files,
the 5 language fallback Dockerfiles + Jenkinsfile template, and the
dind pod template + build-tools Dockerfile.
This commit is contained in:
Mukul Sharma
2026-09-03 14:49:05 +05:30
parent 4b908150e4
commit 63eef9014b
75 changed files with 62 additions and 12981 deletions
@@ -1,68 +0,0 @@
package com.homelab.stages
import com.homelab.stages.deployJar
def run(Map config){
// get required variables from config
def automation_repo_name = config.run_automation.repo_name
def branch = config.run_automation.branch
def deployObj = new deployJar()
//deploy service(farmiso) on specified machine
deployObj.run(config)
checkoutAutomationRepo(automation_repo_name, branch)
runAutomationSuite(automation_repo_name)
}
def checkoutAutomationRepo(String automation_repo_name, String branch){
try{
stage('Checkout automation repo'){
sh "rm -rf ${automation_repo_name}; git clone git@github.com:Homelab/${automation_repo_name}.git -b ${branch}"
echo "automation repo cloned"
}
}
catch( Exception e) {
env.msg = "Error cloning automation repo. Please check console output for more details."
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
def runAutomationSuite(String automation_repo_name){
try{
stage('Run Automation Suite'){
dir("$automation_repo_name"){
run_cmd = "mvn test" //specific to Farmiso as of now.
sh "$run_cmd"
}
}
}
catch( Exception e) {
env.msg = "Error running automation suite. Please check console output for more details."
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
finally{
//publish HTML test report
dir("$automation_repo_name"){
archiveArtifacts artifacts: "test-output/*.*"
publishHTML (target: [
allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: true,
reportDir: 'test-output',
reportFiles: 'index.html',
reportName: "Farmiso-Test-Automation-Report"
])
}
}
}
-412
View File
@@ -1,412 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.buTeamMapping
import com.homelab.utilities.constructTemplate
import com.homelab.utilities.getDockerParams
import com.homelab.utilities.addSSHKey
import com.homelab.utilities.gitActions
import com.homelab.utilities.constructParam
import com.homelab.utilities.dockerUtilities
def buildDckr(Map config) {
env.GOPRIVATE = 'github.com/Homelab'
def buTeamMappingObj = new buTeamMapping()
def constructObj = new constructTemplate()
def dockerParamObj = new getDockerParams()
def addSshKeyObj = new addSSHKey()
def dockerUtilObj = new dockerUtilities()
def team = buTeamMappingObj.get_team_initials(config.team)
def modules = config.modules ?: ['module_less']
def repoName = config.repo_name
def dockerRepository = "${env.cicd_environment}/${team}/${repoName.toLowerCase()}"
def tag = dockerParamObj.getTag(repoName)
def dockerBindings = [:]
def version = config.dockerBuildVersion.split('-')[-1]
def constructParamObj = new constructParam()
def repoType = config.repo_type ?: 'microservice'
boolean skipSonarAndQualityGate = constructParamObj.skipSonarCheckForGo(config)
echo "skipSonarAndQualityGate: ${skipSonarAndQualityGate}"
String goVersion = config.goVersion ?: version
boolean shouldDeployArgo = (config.deployArgo ?: false).toBoolean()
boolean isConfigOnlyChange = false
// Ensure goVersion is in x.x.x format
echo "goVersion: ${goVersion}"
if (goVersion.split('\\.').size() == 2) {
goVersion += '.0'
}
if (env.INFRA_ENV == 'toolchain') {
tag = dockerParamObj.getTag(repoName)
boolean allImagesExist = true
for (module in modules) {
def moduleName = (module instanceof LinkedHashMap) ? module.keySet()[0] : module
def modulePath = (moduleName == 'module_less') ? dockerRepository : "${dockerRepository}/${moduleName}"
//TODO: building everything if one is missing -> create list of modules unbuild will only build those
if (!dockerUtilObj.imageExists(env.registry, modulePath, tag)) {
log.info("Toolchain: Image missing for ${moduleName} at ${modulePath}:${tag}. Proceeding with build.")
allImagesExist = false
break
}
}
if (allImagesExist) {
log.info("Toolchain: All images found in registry for tag ${tag}. Skipping build step.")
return [tag, shouldDeployArgo]
}
}
stage(stageName('Check Config Changes and Get Latest Image Tag')) {
(isConfigOnlyChange, shouldDeployArgo) = is_config_only_change_and_should_deploy_argo(repoName, shouldDeployArgo)
log.info("Is just application config change? $isConfigOnlyChange")
def param = new constructParam()
if (env.CHANGE_ID && repoType == 'microservice') {
def shouldValidateConfig = param.ValidateCacConfigForRepo(false, repoName)
if (shouldValidateConfig) {
log.info('************ Validate Config for CAC application.yml files ************')
dir("$repoName") {
writeFile file: 'validate_configs.py', text: libraryResource('com/homelab/validate_configs_v2.py')
sh 'python3 validate_configs.py'
}
} else {
log.info('************ Skipping Validation of CAC Config ************')
}
} else {
log.info("Skipping Validation of CAC Config for ${repoType} repo type")
log.info('************ Skipping Validation of CAC Config ************')
}
if (isConfigOnlyChange) {
log.info('Skipping the build, since it is just application config change')
log.info('Getting latest image tag from GAR')
def firstModule = modules[0]
def firstModuleName = (firstModule instanceof LinkedHashMap) ? firstModule.keySet()[0] : firstModule
def moduleDockerRepository = (firstModuleName == 'module_less') ? dockerRepository : "${dockerRepository}/${firstModuleName}"
try {
def latest_image = sh(
script: "gcloud container images list-tags ${env.registry}/${moduleDockerRepository} --format='value(tags)' | sed '/^\$/d' | awk -F'-' '{print \$NF}' | sort | tail -1",
returnStdout: true
).trim()
echo "latest_image: ${latest_image}"
if (latest_image == '') {
log.info("No existing images found for ${env.registry}/${moduleDockerRepository}. Using generated tag: ${tag}")
} else {
tag = sh(
script: "gcloud container images list-tags ${env.registry}/${moduleDockerRepository} --format='value(tags)' | tr ',' '\n' | grep ${latest_image}",
returnStdout: true
).trim()
}
} catch (Exception e) {
env.msg = 'Error getting latest docker image from GAR'
env.error_msg_to_db = env.msg
log.error("${env.msg}\n${e.toString()}")
currentBuild.result = env.FAILURE
throw e
}
return [tag, shouldDeployArgo]
}
log.info('Proceeding with the build')
}
stage(stageName('Scanning Sonar and Quality Gate')) {
dir(repoName) {
sonar_scan(repoName, skipSonarAndQualityGate, goVersion)
}
}
if (currentBuild.result == 'UNSTABLE')
{ return [tag, false] }
if (repoType != 'microservice') {
log.info("Skipping Docker build for ${repoType} repo type")
return [tag, shouldDeployArgo]
}
stage(stageName('Building docker images')) {
try {
sh(script: 'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
} catch (Exception e) {
env.msg = "[Failure] Can't login to gcloud docker registry."
env.error_msg_to_db = env.msg
log.error("${env.msg}. Error: ${e.toString()}")
currentBuild.result = env.FAILURE
throw e
}
dockerBindings['version'] = (version == 'go') ? '1.24.4' : version
dockerBindings['base_dir'] = config.base_dir ?: false
dockerBindings['build_registry'] = env.buildRegistry
dockerBindings['go_proxy'] = env.goProxyUrl
dockerBindings['repo_name'] = repoName
if (config.containsKey('copy_file')) {
String recursive = config.copy_file.recursive ? ' -r' : ''
dir(repoName) {
dir('copied_files') {
sh(script: "gsutil cp${recursive} ${config.copy_file.path} .")
}
}
dockerBindings['copy_file'] = true
dockerBindings['copy_target'] = config.copy_file.target ?: '/app/'
dockerBindings['base_dir'] = config.base_dir ?: false
} else {
dockerBindings['copy_file'] = false
}
try {
dir(repoName) {
addSshKeyObj.create()
if (!fileExists('Dockerfile')) {
def moduleBuilds = [:]
for (m in modules) {
def moduleRef = m
def moduleName = (moduleRef instanceof LinkedHashMap) ? moduleRef.keySet()[0] : moduleRef
moduleBuilds["build-${moduleName}"] = {
def localBindings = dockerBindings.clone()
localBindings['module_property'] = (moduleRef instanceof LinkedHashMap) ? moduleRef[moduleName] : [:]
localBindings['kafka'] = (localBindings['module_property'].kafka) ? '-kafka' : ''
localBindings['module'] = moduleName
constructObj.renderTemplate(localBindings, 'go-Dockerfile', "Dockerfile-${moduleName}")
sh "cat Dockerfile-${moduleName}"
def moduleDockerRepository = (moduleRef == 'module_less') ? dockerRepository : "${dockerRepository}/${moduleName}"
sh(script: 'tar -cf only-mods.tar $(git ls-files "go.mod" "go.sum" "**/go.mod" "**/go.sum" 2>/dev/null || find . -name go.mod -o -name go.sum)')
sh(script: "set +x && docker build --tag ${env.registry}/${moduleDockerRepository}:${tag} -f Dockerfile-${moduleName} .")
if (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') {
dockerUtilObj.retryDockerPush("docker push ${env.registry}/${moduleDockerRepository}:${tag}")
} else {
log.info("Skipping Docker Push - ${env.cicd_environment} env")
}
sh(script: "rm -rf Dockerfile-${moduleName}")
}
}
parallel moduleBuilds
} else {
sh 'cat Dockerfile'
def moduleDockerRepository = dockerRepository // default for repo root
if (modules && modules[0] != 'module_less') {
def firstModule = modules[0]
def firstModuleName = (firstModule instanceof LinkedHashMap) ? firstModule.keySet()[0] : firstModule
moduleDockerRepository = dockerRepository + '/' + firstModuleName
}
def pushOrNot = (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') ? '--push' : ''
if (!pushOrNot) {
log.info("Skipping Docker Push - ${env.cicd_environment} env")
}
sh(script: "docker build --tag ${env.registry}/${moduleDockerRepository}:${tag} ${pushOrNot} .")
}
}
} catch (Exception e) {
env.msg = 'Error in building DockerFile Or Pushing To ECR'
env.error_msg_to_db = env.msg
log.error("${env.msg}. Error: ${e.toString()}")
currentBuild.result = env.FAILURE
throw e
}
return [tag, shouldDeployArgo]
}
}
def is_config_only_change_and_should_deploy_argo(String repoName, boolean deployArgo) {
if (env.INFRA_ENV == 'toolchain') {
return [false, deployArgo]
}
def gitObj = new gitActions()
def configFiles = []
boolean shouldDeployArgoResult = deployArgo
boolean isConfigOnlyChange = false
def changedFiles = env.CHANGE_ID ?
gitObj.fetchDiffFilesForPullRequest(repoName, env.CHANGE_TARGET) :
gitObj.fetchDiffFilesForPushRequest(repoName)
if (!changedFiles) {
return [isConfigOnlyChange, shouldDeployArgoResult]
}
for (file in changedFiles.split('\n')) {
if (!file.startsWith('configs/')) {
isConfigOnlyChange = false
return [isConfigOnlyChange, shouldDeployArgoResult]
}
isConfigOnlyChange = true
configFiles << file
}
if (configFiles && deployArgo && isConfigOnlyChange) {
def hasEnvironmentConfig = configFiles.any { it.contains(env.cicd_environment) }
if (!hasEnvironmentConfig) {
shouldDeployArgoResult = false
echo "Config changes don't contain environment: ${env.cicd_environment}"
}
}
return [isConfigOnlyChange, shouldDeployArgoResult]
}
/**
* Function to execute sonar scan
* @param repoName: repository name
* @param skipSonarAndQualityGate: boolean parameter to skip sonar scan
* @param goVersion: Go version string
*/
def sonar_scan(String repoName, boolean skipSonarAndQualityGate, String goVersion) {
if (skipSonarAndQualityGate) {
log.info('Sonar scan is skipped. Marking this stage as passed.')
return
}
stage(stageName('Running sonar scan')) {
try {
withSonarQubeEnv(env.sonarEnv) {
echo "env.sonarEnv: ${env.sonarEnv}"
echo "env.BRANCH_NAME: ${env.BRANCH_NAME}"
def exclusions = ""
if (!fileExists('sonar-project.properties')) {
exclusions = " -Dsonar.exclusions=**/*_test.go,**/mock_*.go,**/mock.go,**/*.pb.go,**/*.proto,**/model.go"
}else{
exclusions = " -Dproject.settings=`pwd`/sonar-project.properties"
}
def scannerCommand = "sonar-scanner -Dsonar.projectKey=${repoName} -Dsonar.go.coverage.reportPaths=./cov.out -Dsonar.branch.name=${env.BRANCH_NAME} -Dsonar.ws.timeout=120 ${exclusions}"
echo "env.SONAR_HOST_URL: ${env.SONAR_HOST_URL}"
env.PATH = "/usr/local/sonar-scanner/sonar-scanner-5.0.1.3006-linux/bin:${env.PATH}"
def response = sh(
script: "curl -s -w '\n%{http_code}' -u ${env.SONAR_AUTH_TOKEN}: ${env.SONAR_HOST_URL}/api/navigation/component?component=${repoName}",
returnStdout: true
).trim()
def responseLines = response.split('\n')
def statusCode = responseLines[-1]
def responseBody = responseLines[0..-2].join('\n')
log.info("SonarQube API Response Code: ${statusCode}")
log.info("SonarQube API Response Body: ${responseBody}")
def projectExists = (statusCode == '200')
if (!projectExists && env.CHANGE_ID) {
log.info("Project ${repoName} does not exist. Creating it via a bootstrap scan on the target branch.")
def targetBranch = env.CHANGE_TARGET ?: 'develop'
echo "targetBranch: ${targetBranch}"
sh "sonar-scanner \
-Dsonar.projectKey=${repoName} \
-Dsonar.projectName=${repoName} \
-Dsonar.branch.name=${targetBranch} \
-Dsonar.sources=. \
-Dsonar.scm.disabled=true \
-Dsonar.ws.timeout=120"
log.info("Bootstrap complete. Project created.")
}else{
echo "Project ${repoName} already exists. Skipping bootstrap scan."
}
if (env.CHANGE_ID) {
echo "env.CHANGE_ID: ${env.CHANGE_ID}"
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
sh "git fetch origin ${env.CHANGE_TARGET}:refs/remotes/origin/${env.CHANGE_TARGET}"
}
scannerCommand = "sonar-scanner -Dsonar.projectKey=${repoName} -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${repoName} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.go.coverage.reportPaths=./cov.out -Dsonar.ws.timeout=120${exclusions}"
echo "scannerCommand: ${scannerCommand}"
}
downloadGoFromJFrog(goVersion)
sh(script: "GOPROXY=${env.goProxyUrl},direct && go mod tidy")
int testExitCode = sh(script: 'go test -short -coverprofile=./cov.out ./...', returnStatus: true)
if (testExitCode != 0) {
error('Go tests failed.')
}
echo "scannerCommand: ${scannerCommand}"
sh(script: scannerCommand)
}
} catch (Exception e) {
log.error("Error in running sonar scan: ${e}")
currentBuild.result = env.FAILURE
throw e
}
}
stage(stageName('Quality Gate')) {
try {
if (!env.CHANGE_ID || env.cicd_environment == 'int') {
log.info('Skipping quality gate check on Branches/Pre-Prod. Marking this stage as passed.')
} else {
timeout(time: 600, unit: 'SECONDS') {
def qg = waitForQualityGate()
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
if (qg.status != 'OK') {
log.warning("Quality gate failed: ${qg.status}")
error "Stopping pipeline due to quality gate failure."
}
}
}
}
}catch (Exception e) {
echo "Error in quality gate: ${e.message}"
unstable('Quality Gate Failed !')
throw e
}
}
}
/**
* Function to download Go binary from JFrog
* @param goVersion: Go version string
*/
def downloadGoFromJFrog(String goVersion) {
try {
echo "env.cicd_environment: ${env.cicd_environment}"
def jfrogUrl = (env.cicd_environment == 'prd' || env.cicd_environment == 'int') ?
'https://jfrog-prd.homelabgcp.in' :
'https://jfrog-dev.homelabgcp.in'
def repo = 'devops-tools-local'
def goTarball = "go${goVersion}.linux-amd64.tar.gz"
def jfrogPath = "${jfrogUrl}/artifactory/${repo}/go/${goTarball}"
def jfrogUser = ''
def jfrogPass = ''
def credentialId = (env.cicd_environment == 'prd' || env.cicd_environment == 'int') ?
'jfrog-prd-credentials' : 'jfrog-stg-credentials'
echo "Using credential ID: ${credentialId}"
withCredentials([usernamePassword(credentialsId: credentialId,
usernameVariable: 'JFROG_USER',
passwordVariable: 'JFROG_PASS')]) {
jfrogUser = env.JFROG_USER
jfrogPass = env.JFROG_PASS
log.info("Attempting to download Go ${goVersion} from JFrog: ${jfrogPath}")
def downloadStatus = sh(script: """
curl -u "${env.JFROG_USER}:${env.JFROG_PASS}" \
-fLO "${jfrogPath}" \
--fail --silent --show-error
""", returnStatus: true)
if (downloadStatus == 0 && fileExists(goTarball)) {
log.info("Successfully downloaded Go ${goVersion} from JFrog")
} else {
echo("WARN: Go ${goVersion} not found in JFrog. Falling back to go.dev...")
sh(script: "curl -LO https://go.dev/dl/${goTarball}")
log.info("Uploading downloaded Go ${goVersion} to JFrog for future use")
sh(script: """
curl -u "${env.JFROG_USER}:${env.JFROG_PASS}" \
-T "${goTarball}" \
"${jfrogPath}" \
--fail --silent --show-error || echo "Upload to JFrog failed, but continuing..."
""")
}
}
sh(script: "tar -xvzf ${goTarball} -C /usr/local", returnStdout: true)
sh(script: "rm -Rf ${goTarball}")
env.PATH = "/usr/local/go/bin:${env.PATH}"
// Verify installation
sh(script: "go version")
} catch (Exception e) {
echo("ERROR: Failed to download Go from JFrog: ${e.message}")
// Final fallback
sh(script: "curl -LO https://go.dev/dl/go${goVersion}.linux-amd64.tar.gz")
sh(script: "tar -xvzf go${goVersion}.linux-amd64.tar.gz -C /usr/local", returnStdout: true)
sh(script: "rm -Rf go${goVersion}.linux-amd64.tar.gz")
env.PATH = "/usr/local/go/bin:${env.PATH}"
}
}
-542
View File
@@ -1,542 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.buTeamMapping
import com.homelab.utilities.constructTemplate
import com.homelab.utilities.getDockerParams
import com.homelab.stages.checkOut
/*
Function to define the flow of entire build, this function will call different stages related to maven build
*/
def run(Map config) {
// get required variables from config
def checkoutObj = new checkOut()
def repo_name = config.repo_name
def args = config.build_args ?: ''
def skip_test = config.skip_test ?: false
def skip_sonar = config.skip_sonar ?: false
def push_to_jfrog = config.push_to_jfrog ?: false
def push_to_s3 = config.push_to_s3 ?: false
def branch_name = "${env.BRANCH_NAME}"
if (branch_name == 'gcp-main' || branch_name == 'gcp-master') {
push_to_jfrog = config.containsKey('push_to_jfrog') ? config.push_to_jfrog : false
}
def version = getVersion("${repo_name}")
if (env.hot_fix) {
skip_test = true
skip_sonar = true
push_to_jfrog = false
}
// call the stages
checkS3(repo_name, branch_name, version, push_to_s3)
build(repo_name, skip_test, args)
sonar_scan(repo_name, skip_sonar)
if (!env.CHANGE_ID) {
pushArtifactToJFrog(repo_name, push_to_jfrog)
pushArtifactToS3(repo_name, branch_name, push_to_s3)
}
else {
log.info('Artifact Push is disabled for Pull Requests')
}
}
/*
Function to check if the artifact exist in s3 or not
input argument
*/
def checkS3(String repo_name, String branch_name, String version, boolean push_to_s3) {
stage(stageName('Checking if artifact already exists')) {
if (env.CLOUD_PROVIDER == 'AWS') {
if (env.hot_fix) {
env.TAG = "v${version}-HOT"
}
else {
if (("${branch_name}" == 'master' || "${branch_name}" == 'main' || push_to_s3) && !env.CHANGE_ID) {
env.TAG = "v${version}"
log.info('########################## Checking if Artifact Already Exists. ###########################')
artifact_exists = sh(returnStdout: true, script: "aws s3 ls \"s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/\" 2>/dev/null || echo ''").trim()
log.info("${artifact_exists}")
if ( artifact_exists ) {
env.msg = "CI for this\n version - ${version}\n branch - ${branch_name}\n TAG - ${TAG}\nis already done. Please proceed with CD."
log.error(env.msg)
currentBuild.result = 'FAILURE'
throw new Exception(env.msg)
}
else {
log.info("Proceeding with building artifact for TAG - ${TAG}.")
}
}
else {
log.info('Skipping - Building artifact')
}
}
}
else if (env.CLOUD_PROVIDER == 'GCP') {
if (env.hot_fix) {
env.TAG = "v${version}-HOT"
}
else {
if (("${branch_name}" == 'master' || "${branch_name}" == 'main' || "${branch_name}" == 'gcp-main' || "${branch_name}" == 'gcp-master' || push_to_s3) && !env.CHANGE_ID) {
env.TAG = "v${version}"
log.info('########################## Checking if Artifact Already Exists. ###########################')
artifact_exists = sh(returnStdout: true, script: "gsutil ls \"gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/\" 2>/dev/null || echo ''").trim()
log.info("${artifact_exists}")
if ( artifact_exists ) {
env.msg = "CI for this\n version - ${version}\n branch - ${branch_name}\n TAG - ${TAG}\nis already done. Please proceed with CD."
log.error(env.msg)
currentBuild.result = 'FAILURE'
throw new Exception(env.msg)
}
else {
log.info("Proceeding with building artifact for TAG - ${TAG}.")
}
}
else {
log.info('Skipping - Building artifact.')
}
}
}
}
}
/*
Function to build the maven package
input arguments:
repo_name: repository name for changing dirctory
skip_test: boolen value to skip unit tests
skip_sonar: boolen value to skip sonar quality gate
args: string parameter to provide additional arguments to build cmd, example: '-U'
*/
def build(String repo_name, boolean skip_test, String args) {
try {
if (env.CLOUD_PROVIDER == 'AWS') {
stage(stageName('Building gradle package')) {
String build_cmd = 'gradle clean build'
dir("$repo_name") {
sh(script:"cp ~/.m2/settings.xml .;${build_cmd} ${args}")
}
}
}
else if (env.CLOUD_PROVIDER == 'GCP') {
stage(stageName('Building gradle package')) {
String build_cmd = 'gradle clean build'
dir("$repo_name") {
sh(script:"gradle -v;cp ~/.m2/settings.xml .;${build_cmd} ${args}")
}
}
}
}
catch ( Exception e) {
env.msg = "Error Building the maven package. Please check console output for more details - ${e}"
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
/*
Fuction to execute sonar scan
Input Arguments:
repo_name: repository name
skip_sonar: boolena parameter to skip sonar scan
*/
def sonar_scan(String repo_name, boolean skip_sonar) {
try {
stage(stageName('Running sonar scan')) {
if (!skip_sonar) {
dir("$repo_name") {
withSonarQubeEnv(env.sonarEnv) {
if (env.CHANGE_ID) {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: "gradle sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script: "gradle sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET}")
}
}
else {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: "gradle sonar:sonar -Dsonar.branch.name=${env.BRANCH_NAME}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script: "gradle sonar:sonar -Dsonar.branch.name=${env.BRANCH_NAME}")
}
}
}
}
}
else {
log.info('Skipping - Sonar Scan')
}
}
// if (!skip_sonar) {
// stage('Quality Gate') {
// timeout(time: 300, unit: 'SECONDS') {
// def qg = waitForQualityGate()
// catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
// if (qg.status != 'OK') {
// error "stage failed due to quality gate failure: ${qg.status}"
// }
// }
// }
// }
// }
}
catch (Exception e) {
dir("$repo_name") {
withSonarQubeEnv(env.sonarEnv) {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: 'gradle sonar:sonar')
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script: 'gradle sonar:sonar')
}
}
}
}
}
/*
Function to get the version from build.gradle
input arguments:
repo_name: String parameter to change the directory where build.gradle is located
*/
def getVersion(String repo_name) {
try {
dir("$repo_name") {
return sh(returnStdout: true, script: "grep version build.gradle | head -1 | cut -d \"'\" -f2").trim()
}
}
catch ( Exception e) {
env.msg = 'Error while getting the version from build.gradle . Please check console output for more details.'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
/*
Function to get the modules from build.gradle
input arguments:
repo_name: String parameter to change the directory where build.gradle is located
*/
def getModules(String repo_name) {
try {
dir("$repo_name") {
modules = sh(returnStdout: true, script: 'xq -r .project.modules.module[] build.gradle 2>/dev/null || xq -r .project.modules.module build.gradle 2>/dev/null || echo empty').trim()
if (modules == 'empty' || modules == 'null') {
modules = 'module_less'
}
modules = modules.split('\n') as List
return modules
}
}
catch ( Exception e) {
env.msg = 'Error getting the modules from build.gradle . Please check console output for more details.'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
/*
Function to push artifacts to jfrog artifactory
input arguments:
repo_name: repository name
push_to_jfrog: boolen argument to push_to_jfrog
*/
def pushArtifactToJFrog(String repo_name, boolean push_to_jfrog) {
try {
stage(stageName('Deploying to JFrog')) {
if (env.CLOUD_PROVIDER == 'AWS') {
branch_name = 'repo'
if (branch_name == 'master' || branch_name == 'main' || push_to_jfrog) {
dir("${repo_name}") {
profiles = sh(returnStdout:true, script: 'xq -r .project.profiles build.gradle ').trim()
block_dist = sh(returnStdout:true, script: 'xq -r .project.distributionManagement build.gradle ').trim()
// Check for profiles tag in the build.gradle
if (profiles != 'null') {
// Check if profiles has distiributionManagement defined
profile_dist = sh(returnStdout:true, script: 'xq -r .project.profiles.profile[].distributionManagement build.gradle 2>/dev/null || xq -r .project.profiles.profile.distributionManagement build.gradle 2>/dev/null || echo null').trim()
if (profile_dist != 'null' ) {
publish_repo = (branch_name == 'master' || branch_name == 'main' || branch_name == 'gcp-main' || branch_name == 'gcp-master') ? 'useProdRepo' : 'useTestRepo'
log.info('########################### Pushing artifact to Jfrog. ###########################')
sh "gradle package deploy -DskipTests=true -D${publish_repo}=true"
}
else {
log.info('distributionManagement is not defined in the build.gradle . Skipping - Push to Jfrog Artifactory')
}
}
else if (block_dist != 'null') {
// Check if distributionManagement is defined without profiles
log.info('########################### Pushing artifact to Jfrog. ###########################')
sh 'gradle package deploy -DskipTests=true'
}
else {
log.info('distributionManagement is not defined in the build.gradle . Skipping - Push to Jfrog Artifactory')
}
}
}
else {
log.info('########################### Skipping - Push to Jfrog Artifactory. ###########################')
}
}
else if (env.CLOUD_PROVIDER == 'GCP') {
branch_name = 'repo'
if (branch_name == 'master' || branch_name == 'main' || push_to_jfrog) {
dir("${repo_name}") {
profiles = sh(returnStdout:true, script: 'xq -r .project.profiles build.gradle ').trim()
block_dist = sh(returnStdout:true, script: 'xq -r .project.distributionManagement build.gradle ').trim()
// Check for profiles tag in the build.gradle
if (profiles != 'null') {
// Check if profiles has distiributionManagement defined
profile_dist = sh(returnStdout:true, script: 'xq -r .project.profiles.profile[].distributionManagement build.gradle 2>/dev/null || xq -r .project.profiles.profile.distributionManagement build.gradle 2>/dev/null || echo null').trim()
if (profile_dist != 'null' ) {
publish_repo = (branch_name == 'master' || branch_name == 'main' || branch_name == 'gcp-main' || branch_name == 'gcp-master') ? 'useProdRepo' : 'useTestRepo'
log.info('########################### Pushing artifact to Jfrog. ###########################')
sh "gradle package deploy -DskipTests=true -D${publish_repo}=true"
echo 'execute gradle dependency'
sh 'gradle dependency:list > dependency_tree.txt'
echo ' uploading gradle dependency'
sh 'ls -ltr'
echo 'lets run copy command'
try {
sh "gsutil cp dependency_tree.txt 'gs://${env.objBucket}/common-dependencies/${repo_name}/'"
}
catch ( Exception e ) {
echo "Skipping - copying txt file to GCS - ${e}"
}
echo 'uploading gradle dependency'
}
else {
log.info('distributionManagement is not defined in the build.gradle . Skipping - Push to Jfrog Artifactory')
}
}
else if (block_dist != 'null') {
// Check if distributionManagement is defined without profiles
log.info('########################### Pushing artifact to Jfrog. ###########################')
sh 'gradle package deploy -DskipTests=true'
}
else {
log.info('distributionManagement is not defined in the build.gradle . Skipping - Push to Jfrog Artifactory')
}
}
}
else {
log.info('########################### Skipping - Push to Jfrog Artifactory. ###########################')
}
}
}
}
catch ( Exception e ) {
env.msg = 'Error in pushing artifacts to jfrog . Please check console output for more details.'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
/*
Function to push artifacts to s3
input arguments:
repo_name: repository name
push_to_s3: boolen argument to push to s3
*/
def pushArtifactToS3(String repo_name, String branch_name, boolean push_to_s3) {
try {
stage(stageName('Pushing artifacts to object storage')) {
if (env.CLOUD_PROVIDER == 'AWS') {
if ("${branch_name}" == 'master' || "${branch_name}" == 'main' || push_to_s3) {
def modules = getModules("${repo_name}")
log.info('}########################### Pushing artifacts to S3. ###########################')
j = 0
for (module in modules) {
j += 1
sh """
echo "${j}. ${module}"
if [ -f ${repo_name}/${module}/target/*.jar ]
then
ls -al ${repo_name}/${module}/target/*.jar
echo "Uploading artifacts to - ${repo_name}/${branch_name}/${TAG}"
aws s3 cp ${repo_name}/${module}/target/*.jar "s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/"
echo "Listing ${TAG} artifacts -"
aws s3 ls "s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/" || echo Nothing to display here.
elif [ -f ${repo_name}/target/*.jar ] && [ ${module} = 'module_less' ]
then
ls -al ${repo_name}/target/*.jar
echo "Uploading artifacts to - ${repo_name}/${branch_name}/${TAG}"
aws s3 cp ${repo_name}/target/*.jar "s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/"
echo "Uploading Archived Code to - ${repo_name}/${branch_name}/${TAG}"
echo "Listing ${TAG} artifacts -"
aws s3 ls "s3://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/" || echo Nothing to display here.
else
echo "No jar file found."
fi
"""
}
log.info("TAG for CD - ${TAG}")
}
else {
log.info("Skipping - Artifact push. As it is not supported for ${env.BRANCH_NAME}")
}
}
else if (env.CLOUD_PROVIDER == 'GCP') {
if ("${branch_name}" == 'master' || "${branch_name}" == 'main' || "${branch_name}" == 'gcp-main' || branch_name == 'gcp-master' || push_to_s3) {
def modules = getModules("${repo_name}")
log.info('}########################### Pushing artifacts to S3. ###########################')
j = 0
for (module in modules) {
j += 1
sh """
echo "${j}. ${module}"
if [ -f ${repo_name}/${module}/target/*.jar ]
then
ls -al ${repo_name}/${module}/target/*.jar
echo "Uploading artifacts to - ${repo_name}/${branch_name}/${TAG}"
gsutil cp ${repo_name}/${module}/target/*.jar "gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/"
echo "Listing ${TAG} artifacts -"
gsutil ls "gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/" || echo Nothing to display here.
elif [ -f ${repo_name}/target/*.jar ] && [ ${module} = 'module_less' ]
then
ls -al ${repo_name}/target/*.jar
echo "Uploading artifacts to - ${repo_name}/${branch_name}/${TAG}"
gsutil cp ${repo_name}/target/*.jar "gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/"
echo "Uploading Archived Code to - ${repo_name}/${branch_name}/${TAG}"
echo "Listing ${TAG} artifacts -"
gsutil ls "gs://${env.objBucket}/${repo_name}/${branch_name}/${TAG}/${module}/" || echo Nothing to display here.
else
echo "No jar file found."
fi
"""
}
log.info("TAG for CD - ${TAG}")
}
else {
log.info("Skipping - Artifact push. As it is not supported for ${env.BRANCH_NAME}")
}
}
}
}
catch ( Exception e ) {
env.msg = "Error in pushing artifacts to s3 bucket. Please check console output for more details - ${e}"
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
/*
Fuction for java version
*/
def getDockerBuildVersion(String java_version) {
switch (java_version) {
case 'gradle': return '8-jdk-slim-secure-multiarch_v3.0'
}
}
/*
Fuction to build maven docker repo
*/
def buildDckr(Map config) {
def btObj = new buTeamMapping()
def dparam_obj = new getDockerParams()
def constructObj = new constructTemplate()
def team = btObj.get_team_initials(config.team)
def repo_name = config.repo_name
def tag = dparam_obj.getTag(repo_name)
def skip_test = config.skip_test ?: false
def modules = getModules("${repo_name}")
def excludedModules = config.excludedModules ?: []
def deployArgo = config.deployArgo ?: false
def repoType = config.repo_type ?: 'microservice'
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
env.JAVA_HOME = '/usr/lib/jvm/java-8-openjdk-amd64/'
env.PATH = "/opt/gradle/gradle-5.6.1/bin:${env.PATH}"
def docker_bindings = [
'repo_name': repo_name,
'buildRegistry': env.buildRegistry
]
if (config.containsKey('copy_file')) {
// if (env.CLOUD_PROVIDER == "AWS"){
// def recursive = config.copy_file.recursive ? ' --recursive' : ''
// }
// else if (env.CLOUD_PROVIDER == "GCP"){
// def recursive = config.copy_file.recursive ? ' -r' : ''
// }
def recursive = config.copy_file.recursive ? ' --recursive' : ''
dir(repo_name) {
dir('copied_files') {
sh(script:"aws s3 cp${recursive} ${config.copy_file.path} .")
}
}
docker_bindings['copy_file'] = true
docker_bindings['copy_target'] = config.copy_file.target ?: '/opt/target'
}
else {
docker_bindings['copy_file'] = false
}
if (modules != 'module_less') {
excludedModules.each { modules.removeElement(it) }
}
else {
modules = ['module_less']
}
docker_bindings['arch'] = config.arch
def java_version = config.dockerBuildVersion
dockerBuildVersion = getDockerBuildVersion(java_version)
docker_bindings['dockerBuildVersion'] = dockerBuildVersion
run(config)
if (docker_bindings.copy_file) {
dir(repo_name) {
dir('copied_files') {
if (env.CLOUD_PROVIDER == 'AWS') {
// delete any old data
sh(script:'rm -rf *')
sh(script:"aws s3 cp${docker_bindings.recursive} ${docker_bindings.copy_file_path} .")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
// delete any old data
docker_bindings['recursive'] = '-r'
sh(script:'rm -rf *')
sh(script:"gsutil cp ${docker_bindings.recursive} ${docker_bindings.copy_file_path}* .")
}
}
}
}
stage(stageName('Building docker images')) {
// Login to docker
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
}
dir(repo_name) {
for (module in modules) {
docker_bindings['module'] = module
constructObj.renderTemplate(docker_bindings,'java-Dockerfile','Dockerfile-' + module)
def module_repo = (module == 'module_less') ? docker_repo : docker_repo + '/' + module
if ( module == 'module_less') {
sh(script: 'mkdir target;cp build/libs/*jar target')
}
else {
sh(script: "mkdir -p ${module}/target;cp build/libs/*jar ${module}/target")
}
if (env.cicd_environment != 'ftr' && repoType == 'microservice') {
sh(script: "ls target; docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module} . && docker push ${env.registry}/${module_repo}:${tag}")
}
else {
log.info("Skipping Docker Build - ${env.cicd_environment} env")
log.info("Skipping Docker Build - ${repoType} repo type")
}
//Remove dockerfile
sh(script: "rm -rf Dockerfile-${module}")
}
}
return [tag , deployArgo]
}
}
File diff suppressed because it is too large Load Diff
-568
View File
@@ -1,568 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.buTeamMapping
import com.homelab.utilities.constructTemplate
import com.homelab.utilities.getDockerParams
import com.homelab.utilities.addSSHKey
import com.homelab.utilities.dockerUtilities
import com.homelab.utilities.getYamlParameter
def removePackageLock() {
sh(script: 'rm -rf package-lock.json')
}
def buildNode(def build_cmd) {
try {
if (fileExists('package-lock.json')) {
sh(script: 'npm ci')
}
else {
sh(script: 'npm install')
}
sh(script: build_cmd)
}
catch ( Exception e ) {
env.msg = 'Error in building node packages . Please check console output for more details.'
env.error_msg_to_db = 'Error Building Node Packages'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
def getArtifactId(String repo_name) {
dir("$repo_name") {
if (fileExists('package.json')) {
return sh(returnStdout: true, script: 'jq -r .name package.json').trim()
}
}
}
def getAwsSecret(def secret_name, def destination_file, def team, def bu) {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws secretsmanager get-secret-value --secret-id ${secret_name} --query SecretString --output text > ${destination_file}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
getVaultSecret("vault kv get -format=json homelab/${env.cicd_environment}/${bu}/${team}/${secret_name} | jq -r .data.data > ${destination_file}")
}
}
def getNpmRc(def secret_name, def team, def bu) {
def npmrc_file = secret_name + '-npmrc-' + env.cicd_environment
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws secretsmanager get-secret-value --secret-id ${npmrc_file} --query SecretString --output text| jq -r .HOMELAB_NPMRC_SECRET > .npmrc")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
getVaultSecret("vault kv get -format=json homelab/${env.cicd_environment}/${bu}/${team}/${npmrc_file} | jq -r .data.data.HOMELAB_NPMRC_SECRET > .npmrc")
}
}
def getPemFile(def secret_name, def team, def bu) {
def pem_secret_name = secret_name + '-secrets-' + env.cicd_environment
if (env.BUILD_ENV == 'stage') {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws secretsmanager get-secret-value --secret-id ${pem_secret_name} --query SecretString --output text| jq -r .public_secret_dev > 1_public_secret_dev.pem")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
getVaultSecret("vault kv get -format=json homelab/${env.cicd_environment}/${bu}/${team}/${pem_secret_name} | jq -r .data.data.public_secret_dev > 1_public_secret_dev.pem")
}
sh(script:"cat 1_public_secret_dev.pem | sed -e 's/-----BEGIN PUBLIC KEY-----/& \\n/' -e 's/-----END PUBLIC KEY-----/\\n-----END PUBLIC KEY-----/g' > public_secret_dev.pem")
}
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws secretsmanager get-secret-value --secret-id ${pem_secret_name} --query SecretString --output text| jq -r .public_secret_prod > 1_public_secret_prod.pem")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
getVaultSecret("vault kv get -format=json homelab/${env.cicd_environment}/${bu}/${team}/${pem_secret_name} | jq -r .data.data.public_secret_prod > 1_public_secret_prod.pem")
}
sh(script:"cat 1_public_secret_prod.pem | sed -e 's/-----BEGIN PUBLIC KEY-----/& \\n/' -e 's/-----END PUBLIC KEY-----/\\n-----END PUBLIC KEY-----/g' > public_secret_prod.pem")
}
def getEnvFile(def secret_name, def team, def bu, boolean useCacPath = false) {
def env_file = secret_name + '-env-' + env.cicd_environment
def gcp_env_file = secret_name
def destination_file = '.env'
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws secretsmanager get-secret-value --secret-id ${env_file} | jq --raw-output '.SecretString' | jq '.' | jq -r 'to_entries|map(\"\\(.key)=\\(.value|tostring)\")|.[]' > .env")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
def vault_path = useCacPath
? "homelab/${env.cicd_environment}-cac/${bu}/${team}/${gcp_env_file}-client"
: "homelab/${env.cicd_environment}/${bu}/${team}/${gcp_env_file}"
getVaultSecret("vault kv get -format=json ${vault_path} | jq -r '.data.data | to_entries|map(\"\\(.key)=\\(.value|tostring)\")|.[]' > .env")
}
}
/**
* Read appConfigEnabled from deployment yaml(s) in repo (deployments/<name>.yaml).
* Uses config.deployment_order for deployment names, or repo_name if not set.
* Aligns with deploy/Helm which reads appConfigEnabled from the same files.
*/
def isAppConfigEnabledFromDeployments(String repo_name, Map config) {
def deploymentNames = (config.deployment_order instanceof List && !config.deployment_order.isEmpty())
? config.deployment_order
: [repo_name]
def yamlObj = new getYamlParameter()
for (def deployment in deploymentNames) {
try {
def depYaml = yamlObj.getParam(repo_name, "deployments/${deployment}.yaml")
def enabled = depYaml?.appConfigEnabled
if (enabled == true || enabled?.toString()?.equalsIgnoreCase('true')) {
return true
}
} catch (Exception e) {
log.debug("No appConfigEnabled in ${repo_name}/deployments/${deployment}.yaml or file missing: ${e.message}")
continue
}
}
return false
}
def getManifestJson(def secret_name, def team, def bu) {
def manifest_file = secret_name + '-manifest-' + env.cicd_environment
def destination_file = 'public/manifest.json'
getAwsSecret(manifest_file, destination_file, team, bu)
}
def generateExcludePattern(String excludeS3Files) {
def files = excludeS3Files.split(/\s*,\s*/) // Split the string by comma and trim whitespace
return '|' + files.join('|') // Join file names with '|' as an "or" operator in regex
}
def shouldSkipPm2Metrics(Map config) {
return config.skip_pm2_metrics?.toString()?.toBoolean() ?: false
}
/*
Fuction to build maven docker repo
*/
def getCommitSHA(String repo_name) {
dir(repo_name) {
return sh(returnStdout: true, script: 'git log -1 --format=%H').trim()
}
}
def buildDckr(Map config) {
// // Block all Node.js builds - throwing exception
// throw new Exception("Node.js builds are currently blocked, As a precautionary measure. Due to some packages that got hacked.")
def btObj = new buTeamMapping()
def constructObj = new constructTemplate()
def dparam_obj = new getDockerParams()
def addSSHKey = new addSSHKey()
def dockerUtilObj = new dockerUtilities()
def team = btObj.get_team_initials(config.team)
def bu = btObj.get_bu_initials(config.bu)
def repo_name = config.repo_name
// CAC: read appConfigEnabled from deployment folder (deployments/<name>.yaml), same source as deploy/Helm
def useCacPath = isAppConfigEnabledFromDeployments(repo_name, config)
def build_cmd = config.build_cmd ?: 'npm run build'
// Resolve secret_name from deployment YAML app_name.
// For multi-deployment repos, env/secret files are kept in sync so the first valid app_name is used.
def secret_name = repo_name
def keep_package_lock = config.keep_package_lock != null ? config.keep_package_lock : true
def skip_npmrc = config.skip_npmrc != null ? config.skip_npmrc : true
if (config.secret_name) {
secret_name = config.secret_name
} else {
try {
def yamlObj = new getYamlParameter()
def deploymentsPath = "${repo_name}/deployments"
def yamlFilesOutput = sh(
script: "ls ${deploymentsPath}/*.yaml 2>/dev/null | xargs -r -n1 basename",
returnStdout: true
).trim()
if (yamlFilesOutput) {
def yamlFiles = yamlFilesOutput.split('\n').collect { it.trim() }.findAll { it }
for (yamlFile in yamlFiles) {
def appConfig = yamlObj.getParam(deploymentsPath, yamlFile)
def appName = appConfig?.app_name?.toString()?.trim()
if (appName) {
echo "Resolved secret_name to ${appName} from ${deploymentsPath}/${yamlFile}"
secret_name = appName
break
}
}
}
if (secret_name == repo_name) {
echo "No app_name found in deployment yamls; using repo_name: ${repo_name}"
}
} catch (Exception e) {
echo "Error reading deployment yaml: ${e.getMessage()}; using repo_name: ${repo_name}"
}
}
def require_mainfest = config.require_mainfest ?: false
def pbac_enabled = config.pbac_enabled ?: false
def pbac_scope_name = config.pbac_scope_name ?: ''
def npm_install_arg = config.npm_install_arg ?: ''
if (!npm_install_arg) {
if (fileExists("${repo_name}/pnpm-lock.yaml") || build_cmd.contains('pnpm')) {
npm_install_arg = 'npm install -g pnpm@10.33.0 && pnpm install --frozen-lockfile'
}
else if (!keep_package_lock || !fileExists("${repo_name}/package-lock.json")) {
npm_install_arg = 'npm install'
}
// else: package-lock.json exists + keep_package_lock=true → Dockerfile uses `npm ci`
}
def require_pemfiles = config.require_pemfiles ?: false
def deployArgo = config.deployArgo ?: false
def artifactId = getArtifactId("${repo_name}")
// def region = dparam_obj.getRegion(env.cicd_environment)
// def registry = dparam_obj.getRegistry(env.cicd_environment)
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
def push_to_s3 = config.push_to_s3 ?: false
def s3_path = config.s3_path ?: "homelab-${env.BUILD_ENV}-artifacts/${repo_name}/${env.BRANCH_NAME}"
if (env.INFRA_ENV == 'toolchain' && env.TOOLCHAIN_ENV) {
docker_repo = "${env.cicd_environment}/${env.TOOLCHAIN_ENV}/${team}/${repo_name.toLowerCase()}"
log.info("Toolchain: Overriding docker_repo to ${docker_repo}")
echo "docker_repo: ${docker_repo}"
if (config.s3_path && config.push_to_s3) {
echo" {env.cicd_environment} should be stg due ot ovveride"
s3_path = s3_path.replaceFirst("/${env.cicd_environment}/", "/${env.TOOLCHAIN_ENV}/")
log.info("TOOLCHAIN OVERRIDE:")
log.info(" Original S3 Path: ${config.s3_path}")
log.info(" New Toolchain S3 Path: ${s3_path}")
log.info(" Toolchain Env ID: ${env.TOOLCHAIN_ENV}")
} else if (!config.push_to_s3) {
log.info("Toolchain: push_to_s3 is false, skipping s3_path override as it wont be pushed")
} else if (!config.s3_path && config.push_to_s3) {
log.info("Toolchain: s3_path is not set but push_to_s3 is true, skipping s3_path override as it wont be pushed")
error("CRITICAL: 's3_path' is missing in config.yaml for the ${env.cicd_environment} environment. Toolchain builds require an s3_path.")
}
}
if (env.TOOLCHAIN_ENV) {
log.info("TOOLCHAIN_ENV: ${env.TOOLCHAIN_ENV}")
}else{
log.info("TOOLCHAIN_ENV: not set")
}
def local_path = config.local_path ?: 'build/'
def acl = config.acl ? ' --acl ' + config.acl : ''
def custom_pm2_metrics = config.custom_pm2_metrics ?: false
def skip_pm2_metrics = shouldSkipPm2Metrics(config)
def include_s3_files = ''
def exclude_s3_files = ''
if (!s3_path.endsWith('/')) {
s3_path += '/'
}
if (!local_path.endsWith('/')) {
local_path += '/'
}
if (env.CLOUD_PROVIDER == 'AWS') {
if (config.include_s3_files) {
include_s3_files = ' --exclude "*"'
def include_file_map = config.include_s3_files.split(',')
for (pattern in include_file_map) {
include_s3_files += ' --include "'+pattern+'"'
}
}
exclude_s3_files = config.exclude_s3_files ? ' --exclude "'+config.exclude_s3_files+'"' : ''
}
else if (env.CLOUD_PROVIDER == 'GCP') {
if (config.include_s3_files) {
def includeFileMap = config.include_s3_files.split(',')
def file_types = ''
def i = 0
includeFileMap.each { pattern ->
if ( i == 0 ) {
file_types = "${pattern.replaceAll('\\*.', '')}"
}
else {
file_types += "|${pattern.replaceAll('\\*.', '')}"
}
i++
}
if ( file_types == '*' ) {
include_s3_files = '^(?!.*\\.*$)'
}
else {
include_s3_files = "^(?!.*\\.(${file_types})\$)"
}
echo "include_s3_files is ${include_s3_files}"
}
else {
include_s3_files = '^(?!.*\\.*$)'
}
exclude_s3_files = config.exclude_s3_files != null && config.exclude_s3_files.trim()? generateExcludePattern(config.exclude_s3_files.trim()) : ''
}
def phantomjs = config.phantomjs ?: false
def version = config.dockerBuildVersion.split('-')[-1]
def tag = dparam_obj.getTag(repo_name)
// TODO: create value binding for dockerfile render
def skip_sonar = config.skip_sonar ?: false
if (env.hot_fix || env.INFRA_ENV == 'toolchain') {
skip_sonar = true
}
def testCMD = config.testCMD ?: 'test-report'
def scmType = 'branch'
def commit_sha = getCommitSHA(config.repo_name)
def docker_bindings = [
'buildRegistry': env.buildRegistry,
'version': version,
'build_cmd': build_cmd,
'push_to_s3': push_to_s3,
's3_path': s3_path,
'local_path': local_path,
'include_s3_files': include_s3_files,
'exclude_s3_files': exclude_s3_files,
'acl': acl,
'phantomjs': phantomjs,
'skip_sonar': skip_sonar,
'testCMD': testCMD,
'CLOUD_PROVIDER': env.CLOUD_PROVIDER,
'npm_install_arg': npm_install_arg
]
docker_bindings['arch'] = config.arch
docker_bindings['pbac_enabled'] = pbac_enabled
docker_bindings['pbac_scope_name'] = pbac_scope_name ?: ''
// Map BUILD_ENV to pbac format (stg/int/prd)
def pbac_env = env.cicd_environment
docker_bindings['pbac_env'] = pbac_env
docker_bindings['useCacPath'] = useCacPath
// Validate pbac configuration
if (pbac_enabled && !pbac_scope_name) {
error('pbac_scope_name is required when pbac_enabled is true in config.yaml')
}
stage(stageName('Creating build files')) {
dir(repo_name) {
if (!keep_package_lock) {
removePackageLock()
}
if (!skip_npmrc) {
getNpmRc(secret_name, team, bu)
}
getEnvFile(secret_name, team, bu, useCacPath)
if (require_pemfiles) {
getPemFile(secret_name, team, bu)
}
if (require_mainfest) {
getManifestJson(secret_name, team, bu)
}
def npm_registry = ''
if (fileExists('.npmrc')) {
npm_registry = sh(
returnStdout: true,
script: "grep '^@homelab:registry=' .npmrc | head -1 | cut -d'=' -f2 | tr -d '\\r\\n'"
).trim()
echo "Detected npm registry: ${npm_registry ?: 'default (none found)'}"
} else {
echo ".npmrc not found, skipping registry extraction"
}
docker_bindings['npm_registry'] = npm_registry
}
}
if (skip_sonar){
stage(stageName('Checking quality gate')){
log.info("Skipping the quality gate check as sonar scan is skipped or this is a hotfix ")
}
}
stage(stageName('Building docker images')) {
// Login to docker
try {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
}
}
catch (Exception e) {
env.msg = 'Error in Docker login'
env.error_msg_to_db = 'Error in Docker login'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
try {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws ecr describe-repositories --region ${env.region} --repository-names ${docker_repo} || aws ecr create-repository --region ${env.region} --repository-name ${docker_repo}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
echo 'Skipping - Registry Creation in GCP.'
}
}
catch (Exception e) {
env.msg = "Error in creating ECR repository ${docker_repo}"
env.error_msg_to_db = "Error in creating ECR repository ${docker_repo}"
currentBuild.result = 'FAILURE'
}
try {
dir(repo_name) {
addSSHKey.create()
withCredentials([usernamePassword(credentialsId: "svc-devops-homelab-token", usernameVariable: 'GIT_USER', passwordVariable: 'GIT_TOKEN')]) {
sh """
echo "GITHUB_TOKEN=${GIT_TOKEN}" >> .env
echo "GIT_COMMIT_SHA='${commit_sha}'" >> .env
"""
}
withCredentials([string(credentialsId: env.sonarToken, variable: 'TOKEN')]) {
sh """
echo "SONAR_HOST_URL='${env.sonarURL}'" >> .env
echo "SONAR_TOKEN='${TOKEN}'" >> .env
echo "SONAR_WS_TIMEOUT=120" >> .env
"""
if (env.CHANGE_ID) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
sh "git fetch origin ${env.CHANGE_TARGET}:refs/remotes/origin/${env.CHANGE_TARGET}"
}
sh """
echo "SONAR_CHANGE_ID='${env.CHANGE_ID}'" >> .env
echo "SONAR_CHANGE_BRANCH='${env.CHANGE_BRANCH}'" >> .env
echo "SONAR_CHANGE_TARGET='${env.CHANGE_TARGET}'" >> .env
"""
scmType = 'pr'
}
else {
sh """
echo "SONAR_BRANCH_NAME='${env.BRANCH_NAME}'" >> .env
"""
}
echo 'Make sure to update script section in package.json for Sonar Analysis to be successfull.'
docker_bindings['scmType'] = scmType
}
if (!fileExists('Dockerfile')) {
constructObj.renderTemplate(docker_bindings, 'node-Dockerfile', 'Dockerfile-' + artifactId)
sh "cat Dockerfile-${artifactId}"
if (push_to_s3) {
if (env.CLOUD_PROVIDER == 'AWS') {
sh """
echo 'FROM amazon/aws-cli:2.2.0 as push_env' >> Dockerfile-${artifactId}
echo 'COPY --from=build-env /usr/src/app /app' >> Dockerfile-${artifactId}
echo 'RUN ls -al && aws s3 cp /app/${local_path} s3://${s3_path}${include_s3_files}${exclude_s3_files} --recursive --cache-control max-age=31536000,public${acl}' >> Dockerfile-${artifactId}
"""
}
else if (env.CLOUD_PROVIDER == 'GCP' ) {
sh """
echo 'FROM asia-southeast1-docker.pkg.dev/homelab-devops-admin-0622/admin/devops/google-cloud-sdk:458.0.0-alpine as push_env' >> Dockerfile-${artifactId}
echo 'COPY --from=build-env /usr/src/app /app' >> Dockerfile-${artifactId}
# echo 'RUN ls -al /app && find /app/${local_path} -type f \\( -name "*.js" -o -name "*.map" \\) && find /app/${local_path} -type f \\( -name "*.js" -o -name "*.map" \\) | wc -l && gsutil -m cp -r /app/${local_path}* gs://${s3_path}' >> Dockerfile-${artifactId}
echo "RUN ls -al /app && gsutil -m rsync -r -x \'${include_s3_files} ${exclude_s3_files}\' /app/${local_path} gs://${s3_path}" >> Dockerfile-${artifactId}
echo "RUN if [ -f /app/${local_path}index.html ]; then gsutil cp /app/${local_path}index.html gs://${s3_path}; fi" >> Dockerfile-${artifactId}
"""
}
}
if (phantomjs) {
sh """
echo 'FROM build-env' >> Dockerfile-${artifactId}
echo 'RUN apt-get update && apt-get install -y libfontconfig' >> Dockerfile-${artifactId}
echo 'WORKDIR /usr/src/app' >> Dockerfile-${artifactId}
echo 'RUN npm install pm2 -g' >> Dockerfile-${artifactId}
echo 'RUN pm2 install pm2-metrics' >> Dockerfile-${artifactId}
if [ "${custom_pm2_metrics}" = "true" ]; then
echo 'RUN pm2 install pm2-prom-module' >> Dockerfile-${artifactId}
echo 'RUN pm2 set pm2-prom-module:port 9200' >> Dockerfile-${artifactId}
echo 'RUN pm2 restart pm2-prom-module' >> Dockerfile-${artifactId}
fi
echo 'RUN rm -rf /root/.ssh/id_rsa && apt-get remove -y git openssh-client bzip2' >> Dockerfile-${artifactId}
"""
}
else {
sh """
echo 'FROM ${env.buildRegistry}/build/node:${version}-alpine-secure-multiarch_v1.0' >> Dockerfile-${artifactId}
echo 'RUN npm install pm2 -g' >> Dockerfile-${artifactId}
if [ "${skip_pm2_metrics}" != "true" ]; then
echo 'RUN pm2 install pm2-metrics' >> Dockerfile-${artifactId}
fi
if [ "${custom_pm2_metrics}" = "true" ]; then
echo 'RUN pm2 install pm2-prom-module' >> Dockerfile-${artifactId}
echo 'RUN pm2 set pm2-prom-module:port 9200' >> Dockerfile-${artifactId}
echo 'RUN pm2 restart pm2-prom-module' >> Dockerfile-${artifactId}
fi
echo 'WORKDIR /app' >> Dockerfile-${artifactId}
echo 'COPY --from=build-env /usr/src/app /app' >> Dockerfile-${artifactId}
"""
}
if (docker_bindings['useCacPath']) {
sh "echo 'RUN truncate -s 0 .env' >> Dockerfile-${artifactId}"
}
sh "cat Dockerfile-${artifactId}"
def imageList = "${env.buildRegistry}/build/node:${version}-alpine-secure-multiarch_v1.0 " +
"asia-southeast1-docker.pkg.dev/homelab-devops-admin-0622/admin/devops/google-cloud-sdk:458.0.0-alpine " +
"${env.buildRegistry}/build/node:${version}-slim-secure-multiarch_v2.0"
sh """
max_attempts=5
images=\"$imageList\"
for image in \$images; do
attempt=1
until docker pull \"\$image\"; do
if [ \$attempt -eq \$max_attempts ]; then
echo \"Failed to pull \$image after \$attempt attempts.\"
exit 1
fi
echo \"Pull failed for \$image, retrying in 2 seconds... (Attempt \$attempt/\$max_attempts)\"
attempt=\$((attempt + 1))
sleep 2
done
done
"""
if (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') {
def docker_cmd = "export DOCKER_BUILDKIT=0;docker build --tag ${env.registry}/${docker_repo}:${tag} -f Dockerfile-${artifactId} . "
sh(script: docker_cmd)
dockerUtilObj.retryDockerPush("docker push ${env.registry}/${docker_repo}:${tag}")
}
else {
def docker_cmd = "export DOCKER_BUILDKIT=0;docker build --tag ${env.registry}/${docker_repo}:${tag} -f Dockerfile-${artifactId} ."
sh(script: docker_cmd)
}
//Remove dockerfile
sh(script: "rm -rf Dockerfile-${artifactId}")
}
else {
if (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') {
sh(script: "export DOCKER_BUILDKIT=0;docker build --tag ${env.registry}/${docker_repo}:${tag} . ")
dockerUtilObj.retryDockerPush("docker push ${env.registry}/${docker_repo}:${tag}")
}
else {
log.info("Skipping Docker Push - ${env.cicd_environment} env")
sh(script: "export DOCKER_BUILDKIT=0;docker build --tag ${env.registry}/${docker_repo}:${tag} .")
}
}
}
}
catch (Exception e) {
env.msg = 'Error in building DockerFile Or Pushing To ECR'
env.error_msg_to_db = env.msg
log.error(env.msg + '\n' + e.toString())
currentBuild.result = env.FAILURE
throw e
}
return [tag , deployArgo]
}
}
def getVaultSecret(String vault_cmd) {
log.info("Fetching secrets from Vault with vault-${env.cicd_environment}-token with CMD - ${vault_cmd}")
if (env.INFRA_ENV == 'toolchain' && env.TOOLCHAIN_ENV) {
boolean skipToolchainOverride = vault_cmd.contains("npmrc") || vault_cmd.contains("-secrets-")
if (!skipToolchainOverride) {
vault_cmd = vault_cmd.replace("homelab/${env.cicd_environment}-cac/", "homelab/toolchain/${env.TOOLCHAIN_ENV}/${env.cicd_environment}-cac/")
vault_cmd = vault_cmd.replace("homelab/${env.cicd_environment}/", "homelab/toolchain/${env.TOOLCHAIN_ENV}/${env.cicd_environment}/")
log.info("TOOLCHAIN OVERRIDE (Application Config):")
log.info(" New Toolchain Vault CMD: ${vault_cmd}")
} else {
log.info("TOOLCHAIN: Reading from standard (non-toolchain) Vault path for npmrc / pem secret.")
}
}
withCredentials([string(credentialsId: "${env.vaultToken}", variable: 'TOKEN')]) {
env.VAULT_ADDR = "${env.vaultURL}"
env.VAULT_TOKEN = "${TOKEN}"
sh(script:"${vault_cmd}")
env.VAULT_TOKEN = 'empty'
env.VAULT_ADDR = env.VAULT_TOKEN
}
}
@@ -1,42 +0,0 @@
package com.homelab.stages
def run(String build_tool){
try {
switch (build_tool) {
case 'maven':
return new buildMaven()
break;
case 'docker':
return new buildDocker()
break;
case ~/^maven-.*/:
return new buildMaven()
break;
case ~/^python-.*/:
return new buildPython()
break;
case ~/^node-.*/:
return new buildNode()
break;
case ~/^rust.*/:
return new buildRust()
break;
case ~/^go.*/:
return new buildGo()
break;
case 'gradle':
return new buildGradle()
break;
case 'php':
return new buildPhp()
default:
return defaultBuild()
}
}
catch (Exception e) {
env.msg = 'Error in selecting the build tool (check the spell) Error: ' + e.toString()
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
-104
View File
@@ -1,104 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.buTeamMapping
import com.homelab.utilities.constructTemplate
import com.homelab.utilities.getDockerParams
def buildDckr(Map config){
def btObj = new buTeamMapping()
def constructObj = new constructTemplate()
def dparam_obj = new getDockerParams()
def team = btObj.get_team_initials(config.team)
def repo_name = config.repo_name
def deployArgo = config.deployArgo ?: false
// def region = dparam_obj.getRegion(env.cicd_environment)
// def registry = dparam_obj.getRegistry(env.cicd_environment)
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
def tag = dparam_obj.getTag(repo_name)
def docker_bindings = [
"repo_name": repo_name,
'buildRegistry': env.buildRegistry
]
if (config.containsKey("copy_file")){
if (env.CLOUD_PROVIDER == 'AWS'){
def recursive = config.copy_file.recursive ? " --recursive" : ""
dir(repo_name){
dir('copied_files'){
sh(script:"aws s3 cp${recursive} ${config.copy_file.path} .")
}
}
} else if (env.CLOUD_PROVIDER == 'GCP'){
def recursive = config.copy_file.recursive ? " -r" : ""
dir(repo_name){
dir('copied_files'){
sh(script:"gsutil cp${recursive} ${config.copy_file.path} .")
}
}
}
docker_bindings["copy_file"] = true
docker_bindings["copy_target"] = config.copy_file.target ?: "/opt/target"
}
else{
docker_bindings["copy_file"] = false
}
stage(stageName('Building docker images')){
// Login to docker
try {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
}
}
catch(Exception e) {
env.msg = "Error in Docker login"
env.error_msg_to_db = "Error in Docker login"
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
try{
if (env.CLOUD_PROVIDER == "AWS"){
sh(script:"aws ecr describe-repositories --region ${env.region} --repository-names ${docker_repo} || aws ecr create-repository --region ${env.region} --repository-name ${docker_repo}")
}
else if (env.CLOUD_PROVIDER == 'GCP'){
echo "Skipping - Registry Creation in GCP."
}
}
catch(Exception e){
env.msg = "Error in creating ECR repository ${docker_repo}"
env.error_msg_to_db = "Error in creating ECR repository ${docker_repo}"
currentBuild.result = "FAILURE"
}
try {
dir(repo_name){
if(!fileExists("Dockerfile")){
constructObj.renderTemplate(docker_bindings,'php-Dockerfile','Dockerfile-php')
if (env.cicd_environment != 'ftr') {
sh(script: "docker build --tag ${env.registry}/${docker_repo}:${tag} -f Dockerfile-php . && docker push ${env.registry}/${docker_repo}:${tag}")
}
else {
log.info("Skipping Docker builds for PHP in ${env.cicd_environment} env")
}
//Remove dockerfile
sh(script: "rm -rf Dockerfile-php")
}
else {
sh(script: "docker build --tag ${env.registry}/${docker_repo}:${tag} . && docker push ${env.registry}/${docker_repo}:${tag}")
}
}
}
catch (Exception e) {
env.msg = "Error in building DockerFile Or Pushing To artifact registry"
env.error_msg_to_db = "Error in building DockerFile Or Pushing To image registry"
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
return [tag , deployArgo]
}
-221
View File
@@ -1,221 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.buTeamMapping
import com.homelab.utilities.constructTemplate
import com.homelab.utilities.getDockerParams
import com.homelab.utilities.addSSHKey
import com.homelab.utilities.dockerUtilities
/*
Function to get the version from pom.xml
input arguments:
repo_name: String parameter to change the directory where pom.xml is located
*/
// def getArtifactId(String repo_name){
// dir("$repo_name"){
// if (fileExists("package.json")) {
// return sh(returnStdout: true, script: 'jq -r .name package.json').trim()
// }
// }
// }
// def getAwsSecret(def secret_name, def destination_file){
// sh (script:"aws secretsmanager get-secret-value --secret-id ${secret_name} --query SecretString --output text > ${destination_file}")
// }
// def getCommitid(String repo_name){
// dir("$repo_name"){
// return sh(returnStdout: true, script: 'git log -1 --format=%h').trim()
// }
// }
// def getNpmRc(def secret_name){
// def npmrc_file = secret_name + "-npmrc"
// sh (script:"aws secretsmanager get-secret-value --secret-id ${npmrc_file} --query SecretString --output text| jq -r .HOMELAB_NPMRC_SECRET > .npmrc")
// }
// def getPemFile(def secret_name){
// def pem_secret_name = secret_name + "-secrets"
// if(env.BUILD_ENV == 'stage'){
// sh (script:"aws secretsmanager get-secret-value --secret-id ${pem_secret_name} --query SecretString --output text| jq -r .public_secret_dev > 1_public_secret_dev.pem")
// sh (script:"cat 1_public_secret_dev.pem | sed -e 's/-----BEGIN PUBLIC KEY-----/& \\n/' -e 's/-----END PUBLIC KEY-----/\\n-----END PUBLIC KEY-----/g' > public_secret_dev.pem")
// }
// sh (script:"aws secretsmanager get-secret-value --secret-id ${pem_secret_name} --query SecretString --output text| jq -r .public_secret_prod > 1_public_secret_prod.pem")
// sh (script:"cat 1_public_secret_prod.pem | sed -e 's/-----BEGIN PUBLIC KEY-----/& \\n/' -e 's/-----END PUBLIC KEY-----/\\n-----END PUBLIC KEY-----/g' > public_secret_prod.pem")
// }
// def getEnvFile(def secret_name){
// def env_file = secret_name + "-env"
// def destination_file = ".env"
// sh(script:"aws secretsmanager get-secret-value --secret-id ${env_file} | jq --raw-output '.SecretString' | jq '.' | jq -r 'to_entries|map(\"\\(.key)=\\(.value|tostring)\")|.[]' > .env")
// }
// def getManifestJson(def secret_name){
// def manifest_file = secret_name+"-manifest"
// def destination_file = "public/manifest.json"
// getAwsSecret(manifest_file,destination_file)
// }
/*
Fuction to build maven docker repo
*/
def buildDckr(Map config) {
def btObj = new buTeamMapping()
def constructObj = new constructTemplate()
def dparam_obj = new getDockerParams()
def addSSHKey = new addSSHKey()
def team = btObj.get_team_initials(config.team)
def repo_name = config.repo_name
def deployArgo = config.deployArgo ?: false
def modules_requirements_file = config.modules_requirements_file ?: 'requirements.txt'
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
def tag = dparam_obj.getTag(repo_name)
if (env.INFRA_ENV == 'toolchain') {
def dockerUtilObj = new dockerUtilities()
if (dockerUtilObj.imageExists(env.registry, docker_repo, tag)) {
log.info("Toolchain: Image found in registry for ${docker_repo}:${tag}. Skipping build step.")
return [tag, deployArgo]
} else {
log.info("Toolchain: Image missing for ${docker_repo}:${tag}. Proceeding with build.")
}
}
// TODO: create value binding for dockerfile render
def docker_bindings = [
'buildRegistry': env.buildRegistry,
'modules_requirements_file': modules_requirements_file,
'arch': config.arch,
'buildRegistry': env.buildRegistry
]
docker_bindings['arch'] = config.arch
// stage("Create build files"){
// dir(repo_name){
// getNpmRc(secret_name)
// getEnvFile(secret_name)
// if (require_pemfiles){getPemFile(secret_name)}
// if (require_mainfest){getManifestJson(secret_name)}
// }
// }
stage(stageName('Building docker images')) {
// Login to docker
try {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
}
}
catch (Exception e) {
env.msg = 'Error in Docker login'
env.error_msg_to_db = 'Error in Docker login'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
if (config.containsKey('copy_file')) {
def recursive = config.copy_file.recursive ? ' --recursive' : ''
docker_bindings['copy_file_path'] = config.copy_file.path
dir(repo_name) {
dir('copied_files') {
if (env.CLOUD_PROVIDER == 'AWS') {
// delete any old data
sh(script:'rm -rf *')
sh(script:"aws s3 cp${recursive} ${config.copy_file.path} .")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
// delete any old data
docker_bindings['recursive'] = '-r'
sh(script:'rm -rf *')
sh(script:"gsutil cp ${docker_bindings.recursive} ${docker_bindings.copy_file_path} .")
}
}
}
docker_bindings['copy_file'] = true
docker_bindings['copy_target'] = config.copy_file.target ?: '/app/'
}
else {
docker_bindings['copy_file'] = false
}
try {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws ecr describe-repositories --region ${env.region} --repository-names ${docker_repo} || aws ecr create-repository --region ${env.region} --repository-name ${docker_repo}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
echo 'Skipping - Registry Creation in GCP.'
}
}
catch (Exception e) {
env.msg = "Error in creating ECR repository ${docker_repo}"
env.error_msg_to_db = "Error in creating ECR repository ${docker_repo}"
currentBuild.result = env.FAILURE
}
try {
dir(repo_name) {
addSSHKey.create()
if (!fileExists('Dockerfile')) {
// print(config)
constructObj.renderTemplate(docker_bindings,config.dockerBuildVersion+'-Dockerfile','Dockerfile-'+repo_name)
sh "cat Dockerfile-${repo_name}"
// withCredentials([string(credentialsId: 'homelab-github-ssh-prv-key', variable: 'SSH_PRIVATE_KEY_S')]) {
// withCredentials(bindings: [sshUserPrivateKey(credentialsId: 'homelab-ssh-github-key', \
// keyFileVariable: 'SSH_PRIVATE_KEY', \
// passphraseVariable: '', \
// usernameVariable: '')]) {
//withCredentials([string(credentialsId: 'git_private_key', variable: 'gitkey')]) {
// sh """
// set +x
// docker build --tag ${env.registry}/${docker_repo}:${tag} --build-arg SSH_PRIVATE_KEY="\$(cat ~/.ssh/id_github_jenkins)" -f "Dockerfile-${repo_name}" . && docker push ${env.registry}/${docker_repo}:${tag}
// set -x
// """
if (env.CLOUD_PROVIDER == 'AWS') {
sh """
set +x
docker build --tag ${env.registry}/${docker_repo}:${tag} --build-arg SSH_PRIVATE_KEY="\$(cat ~/.ssh/id_github_jenkins)" -f "Dockerfile-${repo_name}" .
docker push ${env.registry}/${docker_repo}:${tag}
set -x
"""
}
else if (env.CLOUD_PROVIDER == 'GCP') {
if (env.cicd_environment != 'ftr' || env.INFRA_ENV == 'toolchain') {
sh """
set +x
docker build --tag ${env.registry}/${docker_repo}:${tag} --build-arg SSH_PRIVATE_KEY="\$(cat ~/.ssh/id_github_jenkins)" -f "Dockerfile-${repo_name}" .
docker push ${env.registry}/${docker_repo}:${tag}
set -x
"""
}
else {
log.info("Skipping Docker builds for Python in ${env.cicd_environment} env")
}
}
// }
// }
//Remove dockerfile
sh(script: "rm -rf Dockerfile-${repo_name}")
}
else {
sh "cat Dockerfile"
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} --push .")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh """
set +x
docker build --tag ${env.registry}/${docker_repo}:${tag} --build-arg SSH_PRIVATE_KEY="\$(cat ~/.ssh/id_github_jenkins)" -f "Dockerfile" .
docker push ${env.registry}/${docker_repo}:${tag}
set -x
"""
}
}
}
}
catch (Exception e) {
env.msg = "Error in building DockerFile Or Pushing To ECR. For Full Error Details - ${e}"
env.error_msg_to_db = 'Error in building DockerFile Or Pushing To ECR'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
return [tag , deployArgo]
}
}
-315
View File
@@ -1,315 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.buTeamMapping
import com.homelab.utilities.constructTemplate
import com.homelab.utilities.getDockerParams
import com.homelab.utilities.addSSHKey
def buildDckr(Map config) {
env.RUSTPRIVATE = 'github.com/Homelab'
def btObj = new buTeamMapping()
def constructObj = new constructTemplate()
def dparam_obj = new getDockerParams()
def addSSHKey = new addSSHKey()
def deployArgo = config.deployArgo ?: true
def team = btObj.get_team_initials(config.team)
def modules = config.modules ?: ['module_less']
def repo_name = config.repo_name
def docker_repo = "${env.cicd_environment}/${team}/${repo_name.toLowerCase()}"
def tag = dparam_obj.getTag(repo_name)
def buildx = config.containsKey('buildx') ? config.buildx : true
def docker_bindings = [:]
def skip_sonar = config.skip_sonar ?: false
def version = config.dockerBuildVersion.split('-')[-1]
def repoType = config.repo_type ?: 'microservice'
docker_bindings['version'] = version
docker_bindings['base_dir'] = config.base_dir ?: false
docker_bindings['buildRegistry'] = env.buildRegistry
docker_bindings['build_packages'] = getSystemPackages(config, 'build_packages')
docker_bindings['runtime_packages'] = getSystemPackages(config, 'runtime_packages')
stage('Build docker images') {
// Login to docker
try {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws ecr get-login-password --region ${env.region} | docker login --username AWS --password-stdin ${env.registry}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script:'gcloud auth configure-docker asia-southeast1-docker.pkg.dev --quiet')
}
}
catch (Exception e) {
env.msg = 'Error in Docker login'
env.error_msg_to_db = env.msg
log.error(env.msg + '. Error: ' + e.toString())
currentBuild.result = env.FAILURE
throw e
}
if (config.containsKey('copy_file')) {
def recursive = config.copy_file.recursive ? ' --recursive' : ''
dir(repo_name) {
dir('copied_files') {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws s3 cp${recursive} ${config.copy_file.path} .")
} else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script:"gsutil cp${recursive} ${config.copy_file.path} .")
}
}
}
docker_bindings['copy_file'] = true
docker_bindings['copy_target'] = config.copy_file.target ?: '/app/'
docker_bindings['base_dir'] = config.base_dir ?: false
}
else {
docker_bindings['copy_file'] = false
}
try {
dir(repo_name) {
sonar_scan(repo_name, skip_sonar, version )
if (repoType != 'microservice') {
log.info("Skipping Docker build for ${repoType} repo type")
return [tag, deployArgo]
}
addSSHKey.create()
if (!fileExists('Dockerfile')) {
for (module in modules) {
def module_name = (module instanceof LinkedHashMap) ? module.keySet()[0] : module
docker_bindings['module_property'] = (module instanceof LinkedHashMap) ? module[module_name] : [ : ]
docker_bindings['module'] = module_name
docker_bindings['binary_name'] = (module == 'module_less') ? repo_name : module_name
constructObj.renderTemplate(docker_bindings, 'rust-Dockerfile', 'Dockerfile-' + module_name)
sh "cat Dockerfile-${module_name}"
module_repo = (module == 'module_less') ? docker_repo : docker_repo + '/' + module_name
try {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script:"aws ecr describe-repositories --region ${env.region} --repository-names ${module_repo} || aws ecr create-repository --region ${env.region} --repository-name ${module_repo}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
echo 'Skipping - Registry Creation in GCP.'
}
}
catch (Exception e) {
env.msg = "Error in creating ECR repository ${module_repo}"
env.error_msg_to_db = "Error in creating ECR repository ${module_repo}"
currentBuild.result = 'FAILURE'
}
if (buildx) {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: "set +x && docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} --push .")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
if (env.cicd_environment != 'ftr') {
sh(script: "set +x && docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} . && docker push ${env.registry}/${module_repo}:${tag}")
}
else {
log.info("Skipping Docker Push - ${env.cicd_environment} env")
sh(script: "set +x && docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} .")
}
}
}
else {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: "set +x && docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} . && docker push ${env.registry}/${module_repo}:${tag}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
if (env.cicd_environment != 'ftr') {
sh(script: """
set +x
# Setup buildx for ARM64 builds
docker buildx rm mybuilder || true
docker buildx create --name mybuilder --driver docker-container --bootstrap
docker buildx use mybuilder
# Build for ARM64
docker buildx build --platform linux/arm64 --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} --push .
""")
}
else {
log.info("Skipping Docker Push - ${env.cicd_environment} env")
sh(script: "set +x && docker build --tag ${env.registry}/${module_repo}:${tag} -f Dockerfile-${module_name} .")
}
}
}
//Remove dockerfile
sh(script: "rm -rf Dockerfile-${module_name}")
}
}
else {
sh "cat Dockerfile"
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} --push .")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} --push .")
if (env.cicd_environment != 'ftr') {
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} --push .")
}
else {
log.info("Skipping Docker Push - ${env.cicd_environment} env")
sh(script: "docker buildx build --platform linux/arm64,linux/amd64 --tag ${env.registry}/${docker_repo}:${tag} .")
}
}
}
}
}
catch (Exception e) {
env.msg = 'Error in building DockerFile Or Pushing To ECR'
env.error_msg_to_db = env.msg
log.error(env.msg + '. Error: ' + e.toString())
currentBuild.result = env.FAILURE
throw e
}
return [tag, deployArgo]
}
}
// Services may need native libraries that are not part of a shared base image
// (for example, database client headers used by a crate's build script). The
// keys are language-neutral for future reuse; currently only the Rust builder
// consumes them. Restrict values to Debian package names so config data cannot
// alter the rendered Dockerfile instruction.
def getSystemPackages(Map config, String key) {
def configuredPackages = config[key]
if (configuredPackages == null) {
return []
}
if (!(configuredPackages instanceof List)) {
throw new IllegalArgumentException("${key} must be a YAML list of system package names")
}
def packages = configuredPackages.collect { packageName -> packageName?.toString()?.trim() }
if (packages.any { packageName -> !packageName || !(packageName ==~ /^[a-z0-9][a-z0-9+.-]*$/) }) {
throw new IllegalArgumentException("${key} contains an invalid system package name")
}
return packages.unique()
}
/*
Fuction to execute sonar scan
Input Arguments:
repo_name: repository name
skip_sonar: boolena parameter to skip sonar scan
*/
def sonar_scan(String repo_name, boolean skip_sonar , String version ) {
try {
stage('Run sonar scan') {
if (!skip_sonar) {
withSonarQubeEnv('sonarqube-test') {
if (env.CHANGE_ID) {
if (env.CLOUD_PROVIDER == 'AWS') {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
sh "git fetch origin ${env.CHANGE_TARGET}:refs/remotes/origin/${env.CHANGE_TARGET}"
}
sh(script: "mvn sonar:sonar -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
sh "git fetch origin ${env.CHANGE_TARGET}:refs/remotes/origin/${env.CHANGE_TARGET}"
}
sh(script: "curl -LO https://go.dev/dl/go${go_version}.linux-amd64.tar.gz")
sh(script: "tar -xvzf go${go_version}.linux-amd64.tar.gz -C /usr/local",returnStdout: true)
sh(script:"rm -Rf go${go_version}.linux-amd64.tar.gz")
// Set Go environment variables
env.PATH = "/usr/local/go/bin:${env.PATH}"
// Run Go mod tidy and tests
sh (script: "go mod tidy")
int testExitCode = sh(script: "go test -short -coverprofile=./cov.out ./...", returnStatus: true)
if (testExitCode != 0) {
sh(script: "echo Go tests failed, but the pipeline will continue.")
}
// Download and extract Sonar Scanner
sh(script: "curl -LO https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip")
sh(script: "unzip -o sonar-scanner-cli-5.0.1.3006-linux.zip -d /usr/local/sonar-scanner")
sh(script: "rm -Rf sonar-scanner-cli-5.0.1.3006-linux.zip")
env.PATH = "/usr/local/sonar-scanner/sonar-scanner-5.0.1.3006-linux/bin:${env.PATH}"
// Run Sonar Scanner
sh(script:"sonar-scanner -Dsonar.pullrequest.provider=GitHub -Dsonar.pullrequest.github.repository=Homelab/${repo_name} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.go.coverage.reportPaths=./cov.out ")
}
}
else {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: "mvn sonar:sonar -Dsonar.branch.name=${env.BRANCH_NAME}")
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script: "curl -LO https://go.dev/dl/go${go_version}.linux-amd64.tar.gz")
sh(script: "tar -xvzf go${go_version}.linux-amd64.tar.gz -C /usr/local",returnStdout: true)
sh(script:"rm -Rf go${go_version}.linux-amd64.tar.gz")
// Set Go environment variables
env.PATH = "/usr/local/go/bin:${env.PATH}"
// Run Go mod tidy and tests
sh (script: "go mod tidy")
int testExitCode = sh(script: "go test -short -coverprofile=./cov.out ./...", returnStatus: true)
if (testExitCode != 0) {
sh(script: "echo Go tests failed, but the pipeline will continue.")
}
// Download and extract Sonar Scanner
sh(script: "curl -LO https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-5.0.1.3006-linux.zip")
sh(script: "unzip -o sonar-scanner-cli-5.0.1.3006-linux.zip -d /usr/local/sonar-scanner")
sh(script: "rm -Rf sonar-scanner-cli-5.0.1.3006-linux.zip")
env.PATH = "/usr/local/sonar-scanner/sonar-scanner-5.0.1.3006-linux/bin:${env.PATH}"
// Run Sonar Scanner
sh(script:"sonar-scanner -Dsonar.go.coverage.reportPaths=./cov.out -Dproject.settings=`pwd`/sonar-project.properties -Dsonar.branch.name=${env.BRANCH_NAME}")
}
}
}
}
else {
log.info('Skipping - Sonar Scan')
}
}
stage("Quality Gate"){
if (skip_sonar){
log.info("Sonar scan is skipped. Marking this stage as passed.")
}
else if (!env.CHANGE_ID){
log.info("Skipping quality gate check on Branches. Marking this stage as passed.")
}
else{
timeout(time: 600, unit: 'SECONDS') {
def qg = waitForQualityGate()
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE'){
if (qg.status != 'OK') {
log.warn("Quality gate failed: ${qg.status}, but continuing pipeline execution.")
}
}
}
}
}
}
catch (Exception e) {
dir("$repo_name") {
withSonarQubeEnv('sonarqube-test') {
if (env.CLOUD_PROVIDER == 'AWS') {
sh(script: 'mvn sonar:sonar')
}
else if (env.CLOUD_PROVIDER == 'GCP') {
sh(script: "Quality Gate Failed !")
}
}
}
}
}
-906
View File
@@ -1,906 +0,0 @@
package com.homelab.stages
import com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition
import com.homelab.utilities.getYamlParameter
import com.homelab.utilities.buTeamMapping
import com.homelab.utilities.gitActions
import com.homelab.utilities.constructTemplate
import com.homelab.utilities.constructParam
import com.homelab.utilities.getDockerParams
import com.homelab.utilities.nodePoolSelection
def run(String repo_name, def deployment_order, def tag, def build_team, def dockerBuildVersion, String notify_channel) {
def userInput = ''
// def helm_repo_name = 'devops-helm-charts'
// def argo_repo_name = 'devops-argo-config'
def gitObj = new gitActions()
def constructParam = new constructParam()
def yamlObj = new getYamlParameter()
def branch_name = env.BRANCH_NAME
def branch_param_map = ['(master|main|gcp-main|gcp-master|farmiso-main)': ['branch':'main', 'envrn':'prd'],
'(develop|gcp-dev)':['branch':'develop', 'envrn':'stg']]
if (env.CHANGE_ID) {
branch_param_map = [
'(develop|gcp-dev)':['branch':'feature', 'envrn':'ftr'],
'(master|main|gcp-main|gcp-master|farmiso-main)':['branch':'pre-prod', 'envrn':'int']]
branch_name = env.CHANGE_TARGET
}
def branch_param = branch_param_map.collectEntries { key, value -> branch_name.matches(key) ? value : [ : ] }
if (branch_param == [:]) {
branch_param = ['branch':'feature', 'envrn':'ftr']
}
def helm_branch_name = branch_param.branch
def argo_branch_name = branch_param.branch
def envrn = branch_param.envrn
if (env.CHANGE_ID && env.CHANGE_BRANCH != "develop" && env.CHANGE_TARGET == "main" ) {
def allowedNonDevelopPrDeploymentToInt = constructParam.allowedNonDevelopPrDeploymentToIntRepos(repo_name)
if (!allowedNonDevelopPrDeploymentToInt) {
log.error("******** ONLY DEVELOP BRANCH PR ALLOWED FOR PRE-PROD ENV DEPLOYMENT ********")
return
}
}
log.info('Please provide apps to deploy')
timeout(unit: 'SECONDS', time: 300) {
userInput = wait_for_user_input(deployment_order)
}
// change deployment order according to user input
if (userInput == '') {
log.info('No Deployments selected. Running remaining steps.')
return
}
else if (!userInput.contains('All')) {
deployment_order = userInput.split(',') as List
}
commit_branch_name = env.CHANGE_ID ? env.CHANGE_BRANCH : env.BRANCH_NAME
def commit_id = gitObj.fetchLatestCommitId(repo_name, commit_branch_name)
env.COMMIT_ID = commit_id
env.SERVICES = deployment_order
//Show selected applications to deploy
log.info('Following services will be deployed:\n' + deployment_order.join('\n'))
// Clone the repo just once for all the deployments
gitObj.clone("${WORKSPACE}", "${env.helm_repo_name}", "${helm_branch_name}")
// Clone the repo just once for all the deployments
gitObj.clone("${WORKSPACE}", "${env.argo_repo_name}", "${argo_branch_name}")
for (deployment in deployment_order) {
try {
def isMultizoneEnabled = constructParam.isMultizoneEnabled(deployment)
log.info(" Multi-zone enabled for ${deployment} - ${isMultizoneEnabled}")
if (isMultizoneEnabled) {
def multizone = "Multi-zone enabled for this deployable ${deployment}. Please use Ringmaster for deployment."
currentBuild.result = env.FAILURE
throw new Exception(multizone)
}
def value_binding = yamlObj.getParam("${repo_name}/deployments", "${deployment}.yaml")
constructParam.perDeploymentVars(value_binding)
// if(envrn == 'prd') {
// stage("${deployment}: Downscale Pods in Preprod Env") {
// preprod_downscale(repo_name, deployment,notify_channel)
// }
// }
stage("${deployment}: Update Argo App") {
update_argo_repo(repo_name, deployment, argo_branch_name, envrn)
}
stage('Update Argo App of apps') {
refresh_app_of_apps(envrn)
}
stage("${deployment}: Update Helm Repo") {
update_helm_repo(repo_name, deployment, tag, build_team, helm_branch_name, envrn, dockerBuildVersion, notify_channel)
}
stage("${deployment}: Refresh & Sync App in argoCD") {
refresh_and_sync(repo_name, deployment, envrn)
}
}
catch (Exception e) {
log.error(e)
currentBuild.result = env.FAILURE
}
}
}
// def preprod_downscale(String repo_name, String deployment, String notify_channel){
// def yamlobj = new getYamlParameter()
// def deploy_values = yamlobj.getParam("${repo_name}/deployments","${deployment}.yaml")
// def app_name = deploy_values.app_name
// def bu = deploy_values.bu
// def slack_channel = notify_channel
// def as_enabled = deploy_values.environment.'int'.as_enabled
// log.info("########################### Invoking Jenkins Job to Downscale Pods in Preprod Environment. ###########################")
// build wait: false, job: 'downscale-preprod-eks', parameters:[string(name:'app_name', value:"${app_name}"),
// string(name:'bu',value:"${bu}"),
// string(name:'as_enabled',value:"${as_enabled}"),
// string(name:'slack_channel',value:"${slack_channel}")]
// }
def wait_for_user_input(def deployments) {
def userInput = ''
String choices = 'All,' + deployments.join(',')
int visibleItemCount = 1 + deployments.size()
def multiSelect = new ExtendedChoiceParameterDefinition('deployments', //name
'PT_CHECKBOX', // parameter type
choices, //values
'', //projectName
'', //propertyFile
'', //groovyScript
'', //groovyScriptFile
'', //bindings
'', //groovyClasspath
'', //propertyKey
'', //defaultValue
'', //defaultPropertyFile
'', //defaultGroovyScript
'', //defaultGroovyScriptFile
'', //defaultBindings
'', //defaultGroovyClasspath
'', //defaultPropertyKey
'', //descriptionPropertyValue
'', //descriptionPropertyFile
'', //descriptionGroovyScript
'', //descriptionGroovyScriptFile
'', //descriptionBindings
'', //descriptionGroovyClasspath
'', //descriptionPropertyKey
'', //javascriptFile
'', //javascript
false, //saveJSONParameterToFile
false, //quoteValue
visibleItemCount, //visibleItemCount
'Choose Deployments', //description
',') //multiSelectDelimiter
stage('wait for user input') {
try {
echo "Skipping User Input - ${env.skip_user_input}"
if (env.skip_user_input.toBoolean()) {
userInput = 'All'
}
else {
userInput = input message: 'Choose applications to deploy', ok: 'Deploy', parameters: [multiSelect]
}
return userInput
}
catch (Exception e) {
env.msg = 'Error in taking userInput' + e.toString()
env.error_msg_to_db = 'Error Taking User Input for Deployment of Applications'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
}
def update_helm_repo(String repo_name, String deployment, String tag, String build_team, String helm_branch_name, String envrn, def dockerBuildVersion, String notify_channel) {
def yamlobj = new getYamlParameter()
def btObj = new buTeamMapping()
def gitObj = new gitActions()
def templateObj = new constructTemplate()
def nodePoolSelection = new nodePoolSelection()
// def helm_repo_name = 'devops-helm-charts'
def value_yaml_file = get_value_yaml_file(dockerBuildVersion)
def value_binding1 = yamlobj.getParam("${repo_name}/deployments", "${deployment}.yaml")
if (value_binding1.containsKey('cron')) {
if (value_binding1['cron']) {
value_yaml_file = 'cron-values.yaml'
}
}
def env_norm = ['prd':'prod', 'int':'pre-prod', 'stg':'stg', 'ftr':'feature']
def pr_num = ''
def commit_status = 0
try {
// Get values from deployments/deployment.yaml
isfeatureDeployment = (envrn == 'ftr') ? true : false
value_binding1 = yamlobj.getParam("${repo_name}/deployments", "${deployment}.yaml")
def memory_request = value_binding1.environment[env.cicd_environment].memory_request
def cpu_request = value_binding1.environment[env.cicd_environment].cpu_request
def priority_v2 = value_binding1.priority_v2
def commit_id = env.COMMIT_ID
if ( env.CLOUD_PROVIDER == 'GCP' && !value_binding1.containsKey('cron') ) {
nodeSelectorValue = nodePoolSelection.run(memory_request, cpu_request.toString(),priority_v2)
echo "Node Selector Value is ${nodeSelectorValue}"
value_binding1['nodeSelectorValue'] = nodeSelectorValue
}
def xms = ''
def xmx = ''
if (!value_binding1.containsKey('cron')) {
if (dockerBuildVersion.contains('maven') || dockerBuildVersion.contains('gradle') || dockerBuildVersion.contains('go')) {
value_binding1['activeProcessorCount'] = calculate_active_processors(cpu_request.toString())
}
if (dockerBuildVersion.contains('maven') || dockerBuildVersion.contains('gradle')) {
def memory_limit = value_binding1.environment[env.cicd_environment].memory_limit
def deployment_args = value_binding1.environment[env.cicd_environment].deployment_args
echo "memory_limit is ${memory_limit}"
def memory_string = memory_limit
echo "performing operations on this memory string - ${memory_string}"
def memory_value = ''
if ( memory_string.contains('M') ) {
memory_value = memory_string.replaceAll('Mi', '')
memory_value = memory_value.replaceAll('M', '')
try {
memory_value = memory_value.toInteger()
}
catch (NumberFormatException e) {
memory_value = memory_value.toDouble()
memory_value = memory_value.toInteger()
}
}
else if ( memory_string.contains('G') ) {
memory_value = memory_string.replaceAll('Gi', '')
memory_value = memory_value.replaceAll('G', '')
try {
memory_value = memory_value.toInteger() * 1024
}
catch (NumberFormatException e) {
memory_value = memory_value.toDouble() * 1024
memory_value = memory_value.toInteger()
}
}
memory_value = memory_value * 0.5
memory_value = memory_value.toInteger()
xms = "${memory_value}M"
xmx = "${memory_value}M"
echo "xms and xmx from memory value - ${memory_value} are - ${xms} ${xmx}"
for (arg in deployment_args) {
if (arg.contains('Xms')) {
xms = arg.replaceAll('.*Xms', '')
echo "xms from deployment_args - ${xms}"
}
if (arg.contains('Xmx')) {
xmx = arg.replaceAll('.*Xmx', '')
echo "xmx from deployment_args - ${xmx}"
}
}
echo "final xms and xmx - ${xms} ${xmx}"
}
}
value_binding1['dockerBuildVersion'] = dockerBuildVersion == 'python-3.10.12' ? 'python-3.7' : dockerBuildVersion
deployEnv = !value_binding1['environment'].containsKey(envrn) && isfeatureDeployment ? 'stg' : envrn
Map value_binding = value_binding1['environment'].collectEntries { key, value -> deployEnv.matches(key) ? value : [ : ] }
value_binding1.remove('environment')
value_binding1.putAll(value_binding)
value_binding1['repo_name'] = repo_name
value_binding1['environment'] = envrn
value_binding1['environment_norm'] = env_norm[envrn]
value_binding1['tag'] = tag
value_binding1['repo_name'] = repo_name
value_binding1['build_team'] = build_team
value_binding1['commit_id'] = commit_id
def buini = btObj.get_bu_initials(value_binding1.bu)
def bu = btObj.get_bu_initials(value_binding1.bu)
def teamini = btObj.get_team_initials(value_binding1.team)
def team = btObj.get_team_initials(value_binding1.team)
def app_name = value_binding1.app_name
def app_branch = app_name + '-' + helm_branch_name
def app_helm_repo = "${env.helm_repo_name}/${env.helmChartsPath}/${buini}/${teamini}/${app_name}"
def ingress_val = value_binding1.ingress_val ?: (env.CHANGE_ID) ? "pr-${CHANGE_ID}" : "${BRANCH_NAME}"
sh "chmod -R 777 ${app_helm_repo}"
sh "yq . ${app_helm_repo}/values_properties.yaml -y > a.yaml;mv a.yaml ${app_helm_repo}/values_properties.yaml"
sh "cat ${app_helm_repo}/values_properties.yaml"
if (isfeatureDeployment) {
env.ingress_val = ingress_val
value_binding1['env_ns'] = ingress_val
value_binding1['vault_env'] = value_binding1['create_vault_path'] ? ingress_val : 'stg'
sh(returnStdout: true, script: """
mkdir -p ${app_helm_repo}/${ingress_val}
sed "s/INGRESS_PR_NUMBER/${ingress_val}/g" ${app_helm_repo}/values_properties.yaml > ${app_helm_repo}/${ingress_val}/values_properties.yaml
""")
value_binding2 = yamlobj.getParam("${app_helm_repo}/${ingress_val}", 'values_properties.yaml')
app_branch = ingress_val + '-' + app_branch
}
else {
value_binding1['vault_env'] = envrn
value_binding1['env_ns'] = envrn
value_binding2 = yamlobj.getParam("${app_helm_repo}", 'values_properties.yaml')
echo '722 Printing Value Binding 2'
print value_binding2
}
value_binding1.putAll(value_binding2)
value_binding1['bu_norm'] = value_binding1['bu']
value_binding1['team_norm'] = value_binding1['team']
value_binding1['bu'] = buini
value_binding1['team'] = teamini
def serviceTypes = ["httpstateless", "consumer", "producer", "scheduler", "worker", "grpc", "web", "websocket", "cache", "database"]
//validate service type params
if (value_binding1['service_type']){
// Validating the parameter type
if(!(value_binding1['service_type'] instanceof List) || value_binding1['service_type'].isEmpty()){
env.msg = 'You have not specified service_type correctly. Exiting the pipeline.'
log.error(env.msg)
sh 'exit 1'
}
// Check if value_binding1['service_type'] contains any service type not in servicesType
def invalidServiceTypes = value_binding1['service_type'].findAll { !serviceTypes.contains(it) }
if (!invalidServiceTypes.isEmpty()) {
log.error("Invalid service type(s): ${invalidServiceTypes.join(',')}. Allowed service_types are: ${serviceTypes.join(',')}")
sh 'exit 1'
}
value_binding1['service_type_norm'] = value_binding1['service_type'].join(',')
}
else{
value_binding1['service_type_norm']=''
}
// Enable backward compatibility for missing keys
enable_backward_compatibility(value_binding1)
value_binding1['prismsdk_environment'] = 'PRODUCTION' // THIS KEY WILL CHANGE ONCE 3RD CONFIRM TO STANDERIZE
if (envrn == 'stg'){
value_binding1['otel_enabled'] = true
value_binding1['prismsdk_environment'] = 'SANDBOX' // THIS KEY WILL CHANGE ONCE 3RD CONFIRM TO STANDERIZE
}
// Override hot fix and notify_channel
value_binding1['canary']['skipAnalysis'] = (env.hot_fix) ? true : value_binding1['canary']['skipAnalysis']
value_binding1['canary']['slackChannel'] = notify_channel
value_binding1['xms'] = xms
value_binding1['xmx'] = xmx
value_binding1['CLOUD_PROVIDER'] = env.CLOUD_PROVIDER
def appConfig = value_binding1['appConfigEnabled']
if (appConfig) {
def configModule = (value_binding1["module"] == 'module_less') ? repo_name : value_binding1["module"]
// read the static config from configs directory
def value_binding3 = yamlobj.getParamAsString("${repo_name}/configs/${configModule}", "application-${envrn}.yml")
// to update in values.yaml
value_binding1['staticAppConfigData'] = value_binding3
//read the dynamic config from config directory
def value_binding4 = yamlobj.getParamAsString("${repo_name}/configs/${configModule}", "application-dyn-${envrn}.yml")
// to update in values.yaml
value_binding1['dynamicAppConfigData'] = value_binding4
echo 'printing the values_binding3 and values_binding4'
print value_binding3
print value_binding4
value_binding1['vault_env'] = value_binding1['vault_env'] + '-cac'
}
gitObj.preDeleteBranch(env.helm_repo_name, helm_branch_name, app_branch)
gitObj.branchCheckOut(env.helm_repo_name, app_branch)
echo "Helm Step - Value Binding 1 - ${value_binding1}"
if (isfeatureDeployment) {
echo 'It is feature deployment'
templateObj.renderTemplate(value_binding1, value_yaml_file, "${app_helm_repo}/${ingress_val}/values.yaml")
echo 'Before YAML Linting'
sh "cat ${app_helm_repo}/${ingress_val}/values.yaml"
sh "yq . ${app_helm_repo}/${ingress_val}/values.yaml -y > a.yaml;mv a.yaml ${app_helm_repo}/${ingress_val}/values.yaml"
echo 'After YAML Linting'
sh "cat ${app_helm_repo}/${ingress_val}/values.yaml"
gitObj.add(env.helm_repo_name, "${env.helmChartsPath}/${buini}/${teamini}/${app_name}/${ingress_val}/values.yaml")
}
else {
echo 'Not a feature deployment'
templateObj.renderTemplate(value_binding1, value_yaml_file, "${app_helm_repo}/values.yaml")
echo 'Before YAML Linting'
sh "cat ${app_helm_repo}/values.yaml"
// Perform YAML linting
sh "yq . ${app_helm_repo}/values.yaml -y > a.yaml; mv a.yaml ${app_helm_repo}/values.yaml"
echo 'After YAML Linting'
sh "cat ${app_helm_repo}/values.yaml"
// creating a map from final values.yaml to check canary enforcement conditions
def valuesMap = yamlobj.getParam("${app_helm_repo}", "values.yaml")
// Canary enforcement for sp0 services
// Also will have to check for cron, worker and scheduler services
def enforceCanary = false
if (!app_helm_repo.contains("cron") && !app_helm_repo.contains("worker") && !app_helm_repo.contains("scheduler") && !app_helm_repo.contains("consumer") && (valuesMap["labels"]["priority_v2"] == "sp0" || valuesMap["labels"]["priority_v2"] == "up0") && !value_binding1["addHeadless"] && !value_binding1['dockerBuildVersion'].contains("node") && envrn == "prd") {
enforceCanary = true
}
def proceed = false
def deploymentFailureErrorMessage
if (enforceCanary) {
if (valuesMap["canary"]["enabled"] == true) {
if (valuesMap["canary"]["skipAnalysis"] == false) {
if (valuesMap["canary"]["enableManualPromotion"] == true) {
proceed = true
} else {
error("Error: Update the enableManualPromotion parameter")
}
} else {
error("Error: Update the skipAnalysis parameter")
}
} else {
error("Error: Enable canary and retry")
}
} else {
proceed = true
}
// Check if priority labels and environment conditions require critical dependency check
def criticalPriorities = ["sp0", "up0", "cp0", "sp1", "up1", "cp1"]
def priority = valuesMap["labels"]["priority_v2"]
if (criticalPriorities.contains(priority) && (envrn == "prd")) {
isDependabotCritcal = dependabotCriticalCheck(repo_name)
if (isDependabotCritcal) {
error("Error: Critical vulnerabilities found in repo: " + repo_name + " \nPlease resolve the alerts marked with CRITICAL here and retry: https://github.com/Homelab/" + repo_name + "/security/dependabot and Retry.")
}
}
def param = new constructParam()
log.info("checking if appConfig is enabled")
def isAppConfigDisabled = param.appConfigDisabledForbidden(appConfig, repo_name, envrn, dockerBuildVersion)
if (isAppConfigDisabled){
error("Error: appConfig is disabled , onboard your application with config-as-code changes")
}
sh "cat ${app_helm_repo}/values.yaml"
gitObj.add(env.helm_repo_name, "${env.helmChartsPath}/${buini}/${teamini}/${app_name}/values.yaml")
}
commit_status = gitObj.codeCommit(env.helm_repo_name, app_branch, 'Generating values yaml file')
if (commit_status == 0) {
gitObj.codePush(env.helm_repo_name, app_branch)
pr_num = gitObj.createPR(app_name, env.helm_repo_name, helm_branch_name, app_branch, 'Merge helm values file')
gitObj.mergePR(env.helm_repo_name, pr_num, app_branch)
gitObj.deleteBranch(env.helm_repo_name, helm_branch_name, app_branch)
}
}
catch (FileNotFoundException e) {
env.msg = 'Error Updating Helm Repo ' + e.toString()
env.error_msg_to_db = 'File Not Found'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
catch (Exception e) {
env.msg = 'Error Updating Helm Repo ' + e.toString()
env.error_msg_to_db += 'Error Updating in Helm repo. Git error message - ' + env.error_part_msg_to_db
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
def refresh_and_sync(String repo_name, String deployment, String envrn) {
def yamlobj = new getYamlParameter()
def deploy_values = yamlobj.getParam("${repo_name}/deployments", "${deployment}.yaml")
def app_name = deploy_values.app_name
// def argoUrl = (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'main' || env.CHANGE_TARGET == 'master' || env.CHANGE_TARGET == 'main') ? 'prod-ops-argocd.homelab.com' : 'stg-dev-argocd.homelabtest.in'
def argoEnv = (envrn == 'ftr') ? env.ingress_val : envrn
log.info('########################### Pulling latest changes in ArgoCD. ###########################')
withCredentials([usernamePassword(credentialsId: env.argoCreds, passwordVariable: 'ARGO_PASSWORD', usernameVariable: 'ARGO_USERNAME')]) {
try {
sh """
set +x
argocd login ${env.argoURL}:443 --username ${ARGO_USERNAME} --password ${ARGO_PASSWORD} --grpc-web
argocd app get --hard-refresh ${argoEnv}-${app_name} --grpc-web
"""
}
catch (Exception e) { //added try catch block here
env.msg = "Error in hard refresh of app ${app_name} full error: ${e}"
env.error_msg_to_db += "Error in hard refresh of app ${app_name};"
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
log.info('########################### Syncing latest changes in ArgoCD. ###########################')
return_value = sh(returnStatus: true, script: "argocd app sync ${argoEnv}-${app_name} --grpc-web --http-retry-max 3 --retry-backoff-duration 1m") as Integer
if (return_value == 0) {
log.info('App synced succesfully.')
} else {
env.msg = 'App sync failed. Please check in ArgoCD UI.'
env.error_msg_to_db += "Error Argo App sync failed ${app_name};"
log.error(env.msg)
error "${env.msg}"
}
}
}
def refresh_app_of_apps(String envrn) {
try {
appofapps = env.argoIncubator
log.info('########################### Pulling latest changes in ArgoCD for App of Apps. ###########################')
withCredentials([usernamePassword(credentialsId: env.argoCreds, passwordVariable: 'ARGO_PASSWORD', usernameVariable: 'ARGO_USERNAME')]) {
sh """
set +x
argocd login ${env.argoURL}:443 --username ${ARGO_USERNAME} --password ${ARGO_PASSWORD} --grpc-web
argocd app sync ${appofapps} --grpc-web --http-retry-max 3 --retry-backoff-duration 1m || true
"""
}
}
catch (Exception e) {
env.msg = 'Error in App Sync' + e.toString()
env.error_msg_to_db += 'Error syncing app of app;'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
def update_argo_repo(String repo_name, String deployment, String argoBranch, String envrn) {
def yamlobj = new getYamlParameter()
def btObj = new buTeamMapping()
def gitObj = new gitActions()
def templateObj = new constructTemplate()
// def argo_repo_name = 'devops-argo-config'
def pr_num = ''
def commit_status = 0
def commit_id = env.COMMIT_ID
value_binding1 = yamlobj.getParam("${repo_name}/deployments", "${deployment}.yaml")
value_binding1['CLOUD_PROVIDER'] = env.CLOUD_PROVIDER
isfeatureDeployment = (envrn == 'ftr') ? true : false
deployEnv = !value_binding1['environment'].containsKey(envrn) && isfeatureDeployment ? 'stg' : envrn
Map value_binding = value_binding1['environment'].collectEntries { key, value -> deployEnv.matches(key) ? value : [ : ] }
value_binding1.remove('environment')
value_binding1.putAll(value_binding)
value_binding1['environment'] = envrn
def buini = btObj.get_bu_initials(value_binding1.bu)
def bu = value_binding1.bu
def teamini = btObj.get_team_initials(value_binding1.team)
def team = value_binding1.team
def app_name = value_binding1.app_name
def filename = "${teamini}-${app_name}.yaml"
def helm_values_path = "${env.helmChartsPath}/${buini}/${teamini}/${app_name}"
def app_branch = app_name + '-' + argoBranch
def ingress_val = value_binding1.ingress_val ?: (env.CHANGE_ID) ? "pr-${CHANGE_ID}" : "${BRANCH_NAME}"
value_binding1['helm_version'] = value_binding1.helm_version ?: env.defaultHelmChartVersion
if (isfeatureDeployment) {
value_binding1['env_ns'] = ingress_val
value_binding1['helm_values_path'] = "${env.helmChartsPath}/${buini}/${teamini}/${app_name}/${ingress_val}"
filename = ingress_val + '-' + "${app_name}.yaml"
app_branch = ingress_val + '-' + app_branch
}
else {
value_binding1['env_ns'] = envrn
value_binding1['helm_values_path'] = "${env.helmChartsPath}/${buini}/${teamini}/${app_name}"
filename = "${teamini}-${app_name}.yaml"
}
value_binding1['server'] = env.clusterName
value_binding1['clusterName'] = env.clusterName
value_binding1['branch_name'] = argoBranch
value_binding1['buini'] = buini
value_binding1['teamini'] = teamini
value_binding1['priority_v2'] = value_binding1.priority_v2 ?: 'cp3'
value_binding1['primary_owner'] = value_binding1.primary_owner != null ? value_binding1.primary_owner.split('@')[0] : value_binding1.team
value_binding1['secondary_owner'] = value_binding1.secondary_owner != null ? value_binding1.secondary_owner.split('@')[0] : value_binding1.team
value_binding1['argoAppNS'] = env.argoAppNS
value_binding1['commit_id'] = commit_id
log.info(commit_id)
gitObj.preDeleteBranch(env.argo_repo_name, argoBranch, app_branch)
gitObj.branchCheckOut(env.argo_repo_name, app_branch)
echo "Argo Step - Value Binding 1 - ${value_binding1}"
dir(env.argo_repo_name) {
def dirExists = sh(script: "cat ${env.argoAppsPath}/${filename}", returnStatus: true)
if ( dirExists != 0 ) {
sh "mkdir -p ${env.argoAppsPath}"
sh "touch ${env.argoAppsPath}/${filename}"
}
sh "chmod -R 777 ${env.argoAppsPath}/${filename}"
templateObj.renderTemplate(value_binding1, 'argoApp.yaml', "${env.argoAppsPath}/${filename}")
sh "yq . ${env.argoAppsPath}/${filename} -y > a.yaml;mv a.yaml ${env.argoAppsPath}/${filename}"
sh "cat ${env.argoAppsPath}/${filename}"
}
gitObj.add(env.argo_repo_name, "${env.argoAppsPath}/${filename}")
commit_status = gitObj.codeCommit(env.argo_repo_name, app_branch, "onboarding ${deployment} app to ARGO")
if (commit_status == 0) {
gitObj.codePush(env.argo_repo_name, app_branch)
pr_num = gitObj.createPR(app_name, env.argo_repo_name, argoBranch, app_branch, 'Merge argo application configuration')
gitObj.mergePR(env.argo_repo_name, pr_num, app_branch)
gitObj.deleteBranch(env.argo_repo_name, argoBranch, app_branch)
}
}
def calculate_active_processors(String cpu_request) {
// If lowercase m is present
if (cpu_request.contains('m')) {
// Remove m
cpu_request = cpu_request.replaceAll('m', '')
// If this fails means invalid input is given with m, so we can let the pipeline fail here
// Convert to double, divide by thousand to get another double, round it off and then convert to integer.
return Math.ceil(cpu_request.toDouble() / 1000).toInteger()
}
return Math.ceil(cpu_request.toDouble()).toInteger()
}
def enable_backward_compatibility(def bindings) {
// def primaryEmailInitial = bindings.primary_owner.tokenize( '@' )[0]: null
// def secondaryEmailInitial = bindings.secondary_owner.tokenize( '@' )[0]: null
def dparam_obj = new getDockerParams()
bindings['registry'] = env.registry
def canary_default = [
'progressDeadlineSeconds': 300,
'analysisInterval': '120s',
'analysisThreshold': 5,
'analysisMaxWeight': 5,
'analysisStepWeight': 5,
'analysisMetrics':[
'thresholdRangeMin': 0.99,
'interval': '1m'],
'skipAnalysis': false
]
def statefulset_default = [
'updateStrategy': 'RollingUpdate',
'volumeType': 'dynamic',
'dynamicVolume':[
'accessMode': 'ReadWriteMany',
'mountPath': '/opt/data',
'size': '5Gi',
'storageClass': ''],
'staticVolume':[
'accessMode': 'ReadWriteMany',
'size': '5Gi',
'mountPath': '/opt/data',
'storageClass': '',
'volumeHandle': '',
'csiDriver': '']
]
bindings['hostAliases'] = bindings.hostAliases ?: false
if (env.CLOUD_PROVIDER == 'AWS') {
bindings['nodeSelector'] = bindings.nodeSelector ?: (env.cicd_environment == 'stg' || env.cicd_environment == 'ftr') ? bindings.bu : ( env.cicd_environment == 'int' ? bindings.bu + '-int' : bindings.team )
bindings['nodeSelectorValue'] = 'dedicated'
}
else if (env.CLOUD_PROVIDER == 'GCP') {
if (env.cicd_environment == 'int') {
bindings['nodeSelector'] = bindings.nodeSelector ?: 'cloud.google.com/compute-class'
} else {
bindings['nodeSelector'] = bindings.nodeSelector ?: 'dedicated'
}
bindings['nodeSelectorValue'] = bindings.nodeSelectorValue ?: 'megatetra'
}
bindings['triggers'] = bindings.triggers ?: false
bindings['host'] = bindings.host ?: false
bindings['hosts'] = bindings.hosts ?: false
bindings['grpc_host'] = bindings.grpc_host ?: false
bindings['grpc_hosts'] = bindings.grpc_hosts ?: false
bindings['serviceAccount'] = bindings.serviceAccount ?: false
bindings['ingress_annotations'] = bindings.ingress_annotations ?: ''
bindings['canary'] = bindings.canary ?: canary_default
bindings['minCanaryReplicas'] = bindings.canary?.minCanaryReplicas ?: bindings.minCanaryReplicas ?: bindings.as_min
bindings['maxCanaryReplicas'] = bindings.canary?.maxCanaryReplicas ?: bindings.maxCanaryReplicas ?: bindings.as_max
bindings['enableManualPromotion'] = bindings.canary?.enableManualPromotion ?: bindings.enableManualPromotion ?: false
bindings['cpu_limit'] = bindings.cpu_limit ?: bindings.cpu_request
bindings['slowStartWindow'] = bindings.slowStartWindow ?: false
bindings['slowStartAggression'] = bindings.slowStartAggression ?: '1'
bindings['slowStartMinPercent'] = bindings.slowStartMinPercent ?: '10'
bindings['lifecycle'] = bindings.lifecycle ?: false
bindings['maxSurge'] = bindings.maxSurge ?: '50'
bindings['as_down_pod_count'] = bindings.as_down_pod_count ?: '2'
bindings['as_up_pod_count'] = bindings.as_up_pod_count ?: '2'
bindings['as_up_pod_percentage'] = bindings.as_up_pod_percentage ?: '10'
bindings['createContourGateway'] = bindings.createContourGateway ?: false
bindings['service_annotations'] = bindings.service_annotations ?: false
bindings['pod_annotations'] = bindings.pod_annotations ?: false
bindings['kind'] = bindings.kind ?: 'deployment'
bindings['statefulset'] = bindings.statefulset ?: statefulset_default
bindings['contourResponseTimeout'] = bindings.contourResponseTimeout ?: false
bindings['pdbMinAvailable'] = bindings.pdbMinAvailable ?: ''
bindings['pdbMaxUnavailable'] = bindings.pdbMaxUnavailable ?: '10%'
// Just to keep compatibility for services which still use grpc_port
// If someone has supplied primary_port, then it is used
// Else we check for grpc_port, and that is used
// If none of the above is supplied, then app_port is used just like normal flow
bindings['primary_port'] = bindings.primary_port ?: bindings.grpc_port ?: bindings.app_port
bindings['grpc_port'] = bindings.grpc_port ?: false
// bindings['xmx'] = bindings.xmx ?: '50.0'
// bindings['xms'] = bindings.xms ?: '50.0'
bindings['enableWebsocket'] = bindings.enableWebsocket ?: false
bindings['external_secrets_annotations'] = bindings.external_secrets_annotations ?: ''
bindings['liveness_failure_threshold'] = bindings.liveness_failure_threshold ?: '5'
bindings['liveness_period_seconds'] = bindings.liveness_period_seconds ?: bindings.team_norm == 'ml-platform' ? '5' : '10'
bindings['liveness_success_threshold'] = bindings.liveness_success_threshold ?: '1'
bindings['liveness_timeout_seconds'] = bindings.liveness_timeout_seconds ?: '2'
bindings['readiness_failure_threshold'] = bindings.readiness_failure_threshold ?: '5'
bindings['readiness_period_seconds'] = bindings.liveness_period_seconds ?: bindings.team_norm == 'ml-platform' ? '5' : '10'
bindings['readiness_success_threshold'] = bindings.liveness_success_threshold ?: '1'
bindings['readiness_timeout_seconds'] = bindings.liveness_timeout_seconds ?: '2'
bindings['addon_ports'] = bindings.addon_ports ?: false
validateRequiredMetadata(bindings)
bindings['priority_v2'] = bindings.priority_v2 ?: 'cp3'
bindings['primary_owner'] = bindings.primary_owner != null ? bindings.primary_owner.split('@')[0] : bindings.team_norm
bindings['secondary_owner'] = bindings.secondary_owner != null ? bindings.secondary_owner.split('@')[0] : bindings.team_norm
if (env.CLOUD_PROVIDER == 'AWS') {
if (bindings.otel_enabled == null) {
bindings['otel_enabled'] = (bindings.priority_v2 == 'cp1' || bindings.priority_v2 == 'up1') ? true : false
}
else {
bindings['otel_enabled'] = bindings.otel_enabled
}
}
else if (env.CLOUD_PROVIDER == 'GCP') {
echo "Checking for otel value - ${bindings.otel_enabled}"
if (bindings.otel_enabled == null) {
bindings['otel_enabled'] = true
}
else {
bindings['otel_enabled'] = bindings.otel_enabled
}
// Setting metrics mode -> avaliable options: telegraf | otel | dual
echo "Setting metrics mode - ${bindings.metrics_mode}"
// Setting default values
bindings['telegraf_metrics'] = false
bindings['otel_metrics'] = false
bindings['metrics_mode'] = bindings.metrics_mode?.toLowerCase()
def samplerArg = bindings.otel_traces_sampler_arg
def isValidSamplerArg = false
if (samplerArg != null && (samplerArg instanceof Float || samplerArg instanceof Double)) {
if (samplerArg >= 0.0 && samplerArg <= 1.0) {
isValidSamplerArg = true
}
}
bindings['otel_traces_sampler_arg'] = isValidSamplerArg ? samplerArg : '0.1'
log.info("1 - otel_traces_sampler_arg - ${bindings.otel_traces_sampler_arg}")
log.info("2 - ${bindings['otel_traces_sampler_arg']}")
// Enabling metrics based on mode
if (bindings.metrics_mode == 'telegraf') {
bindings['telegraf_metrics'] = true
}
else if (bindings.metrics_mode == 'otel') {
bindings['otel_metrics'] = true
}
else if (bindings.metrics_mode == 'dual') {
bindings['telegraf_metrics'] = true
bindings['otel_metrics'] = true
}
else {
bindings['metrics_mode'] = 'telegraf'
bindings['telegraf_metrics'] = true
}
}
bindings['command'] = bindings.command
if (bindings.command == null) {
bindings['command'] = get_default_command(bindings['dockerBuildVersion'])
}
bindings['as_down_stable_window'] = bindings.as_down_stable_window ?: '1800'
bindings['podDistributionSkew'] = bindings.podDistributionSkew ?: false
bindings["appConfigEnabled"] = bindings.appConfigEnabled ?: false
bindings["addHeadless"] = bindings.addHeadless?: false
}
def get_value_yaml_file(def dockerBuildVersion) {
switch (dockerBuildVersion) {
case ~/^maven-.*/: return 'values.yaml'
case ~/^node-.*/: return 'node-values.yaml'
case ~/^python-.*/: return 'python-values.yaml'
case ~/^go.*/: return 'go-values.yaml'
case 'php': return 'php-values.yaml'
case 'gradle': return 'values.yaml'
}
}
def get_default_command(def dockerBuildVersion) {
switch (dockerBuildVersion) {
case ~/^maven-.*/: return 'java'
case ~/^node-.*/: return 'pm2-runtime'
case ~/^go.*/: return '/app/server'
case 'php': return 'apache2-foreground'
case 'gradle': return 'java'
default: return null
}
}
def validateRequiredMetadata(def bindings) {
def requiredParams = ['primary_owner', 'secondary_owner', 'priority_v2', 'service_type']
def serviceOwners = ['primary_owner', 'secondary_owner']
// Validate if required parameters are present
for (param in requiredParams) {
if (bindings[param] == null || bindings[param] == '') {
env.msg = 'You have not supplied ' + param + '. Exiting the pipeline.'
log.error(env.msg)
sh 'exit 1'
}
}
// Validate if the owners are valid or not
if (env.cicd_environment == 'dev' || env.cicd_environment == 'ftr' || env.cicd_environment == 'stg') {
return
}
for (param in serviceOwners) {
final String owner = bindings[param]
final String url = "https://pulse.homelabgcp.in/api/anonymous-User/userexist?email=${owner}"
final def(String response, String code) = sh(returnStdout: true, script: """
set +x
curl -s -X GET -w '\n%{response_code}' $url
set -x
""").trim().tokenize('\n')
if (code != "200") {
// Let's not break the pipeline in case the API fails
log.info("Received ${code} code from Pulse while checking for user. Skipping the checks further and letting the pipeline proceed.")
} else {
// Check if the user exists
def jqCommand = "echo '${response}' | jq -r '.exists'"
def userExists = sh(returnStdout: true, script: """
set +x
${jqCommand}
set -x
""").trim()
if (userExists != "true") {
env.msg = "Invalid value provided in ${param}. Check if the user ${owner} exists"
log.error(env.msg)
sh 'exit 1'
}
}
}
}
def dependabotCriticalCheck(def repoName) {
def repo = repoName
def alerts
withCredentials([usernamePassword(credentialsId: "${env.GITHUB_CRED}", usernameVariable:'user', passwordVariable: 'token')]) {
validateDependabot = httpRequest httpMode: 'GET',
customHeaders: [
[name: 'Accept', value: 'application/vnd.github+json'],
[maskValue: true, name: 'Authorization', value: 'Bearer ' + token]
],
url: "https://api.github.com/repos/homelab/${repo}/dependabot/alerts?state=open&per_page=100",
validResponseCodes: '200',
timeout: 10
alerts = readJSON(text: validateDependabot.content)
}
// if (!alerts) {
// println "Failed to fetch alerts for ${repo}."
// return false
// }
// Parse the JSON response
if (!alerts) {
println "No alerts found for ${repo}."
return false
}
def criticalCount = 0
alerts.each { alert ->
def severity = alert?.security_vulnerability?.severity
if (severity == "critical") {
criticalCount++
}
}
if (criticalCount > 0) {
println "Critical vulnerabilities found in ${repo}: ${criticalCount}"
return true // Critical vulnerabilities found
} else {
println "No critical vulnerabilities in ${repo}."
return false // No critical vulnerabilities found
}
}
-32
View File
@@ -1,32 +0,0 @@
package com.homelab.stages
def run(Map param){
//get the jar for deployment, get it from the params module
//run the ansible playbook
//create the inventory file with given ip in parameters
def server_ip = param.run_automation.server_ip
def app_name = param.run_automation.app_name
def healthcheck_api = param.run_automation.healthcheck_api
def app_port = param.run_automation.app_port
def repo_name = param.repo_name
deploy(server_ip,repo_name,app_name,healthcheck_api,app_port)
}
def deploy(String server_ip, String repo_name, String app_name, String healthcheck_api, String app_port){
try{
stage('Deploying JAR'){
sh "echo '$server_ip' > host_file.txt"
echo "inventory created"
def playbook_content = libraryResource 'com/homelab/deployJar.yaml'
writeFile file:"deployJar.yaml", text: playbook_content
sh(returnStatus: true, script: "ansible-playbook -i host_file.txt -u 'ubuntu' -e 'env=stage' -e 'app_name=${app_name}' -e 'repo_name=${repo_name}' -e 'healthcheck_api=${healthcheck_api}' -e 'app_port=${app_port}' deployJar.yaml -v")
}
}
catch( Exception e) {
env.msg = "Error while deploying JAR. Please check console output for more details."
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
@@ -1,144 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.getYamlParameter
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatterBuilder
def run(String repo_name, def deployment_order, def tag, def build_team, def dockerBuildVersion, String notify_channel){
def yamlobj = new getYamlParameter()
def applicationNames = []
def jobStatusMap=["SUCCESS": "BUILD_STATUS_COMPLETED","FAILURE": "BUILD_STATUS_FAILED","UNSTABLE":"BUILD_STATUS_FAILED"]
def build_user = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
for (deployment in deployment_order){
def value_binding = yamlobj.getParam("${repo_name}/deployments","${deployment}.yaml")
applicationNames.add(value_binding['app_name'])
}
def end_time = getDateTime()
def working_env = (env.CLOUD_PROVIDER == "GCP")? "gcp_${env.cicd_environment}" : env.cicd_environment
def jsonMap = [:]
jsonMap["hot_fix"] = env.hot_fix ? true : false
jsonMap["job_name"] = env.JOB_NAME ? env.JOB_NAME.split('/')[0] : "unknown"
jsonMap["build_no"] = env.BUILD_NUMBER
jsonMap["image"] = tag
jsonMap["applications"] = applicationNames
jsonMap["job_status"] = jobStatusMap[currentBuild?.currentResult]
jsonMap["err_msg"] = env.error_msg_to_db
jsonMap["end_time"] = end_time
jsonMap["email"] = currentBuild?.rawBuild?.getCause(Cause.UserIdCause)?.getUserId()
jsonMap["start_time"] = env.STARTTIME
jsonMap["build_team"] = build_team
jsonMap["docker_build_version"] = dockerBuildVersion
jsonMap["notify_channel"] = notify_channel
jsonMap["branch_name"] = env.CHANGE_ID ? env.CHANGE_BRANCH : env.BRANCH_NAME
jsonMap["commit_id"] = env.commit_id
jsonMap["deploy_argo"] = env.deployArgo != null ? env.deployArgo.toBoolean() : false
jsonMap["pr_number"] = env.CHANGE_ID ? env.CHANGE_ID.toInteger() : 0
final String baseUrl
switch (env.cicd_environment) {
case 'prd':
case 'int':
baseUrl = 'https://ringmaster-api.homelabgcp.in/api/v1/key/cicd/cd/update'
break
default:
baseUrl = 'https://ringmaster-api.admin.homelabgcp.in/api/v1/key/cicd/cd/update'
}
final String url = "${baseUrl}?workingEnv=${working_env}"
final String header = "Content-Type: application/json"
final String jsonData = writeJSON returnText: true, json: jsonMap
if (build_user == "ringmaster-bot"){
callApi(url, header, jsonData)
} else{
def newCICD_Payload = [:]
newCICD_Payload["repo_name"] = repo_name
newCICD_Payload["source_branch"] = env.CHANGE_ID ? env.CHANGE_BRANCH : env.BRANCH_NAME
newCICD_Payload["pull_request_number"] = env.CHANGE_ID ? env.CHANGE_ID.toInteger() : 0
newCICD_Payload["env"] = env.cicd_environment
newCICD_Payload["job_name"] = env.JOB_NAME ? env.JOB_NAME.split('/')[0] : "UNKNOWN"
newCICD_Payload["sub_job_name"] = env.JOB_NAME ? env.JOB_NAME.split('/')[1] : "UNKNOWN"
newCICD_Payload["build_number"] = env.BUILD_NUMBER.toInteger()
newCICD_Payload["image_tag"] = tag
newCICD_Payload["build_detailed_error"] = env.error_msg_to_db
switch (env.cicd_environment) {
case 'prd':
case 'int':
cicdBaseUrl = 'http://turbo-turtle.homelabgcp.in'
break
default:
cicdBaseUrl = 'http://turbo-turtle.admin.homelabgcp.in'
}
final String newCICD_JSON = writeJSON returnText: true, json: newCICD_Payload
//log.info("New CICD JSON - ${newCICD_JSON}")
final String newCICD_URL = cicdBaseUrl + "/api/v1/ci/jenkins/callback"
final String newCICD_Header = "Content-Type: application/json"
// Use a temporary file to store the JSON payload
// This avoids shell quoting issues completely
final String jsonFilePath = "cicd_payload_${env.BUILD_NUMBER}_${System.currentTimeMillis()}.json"
try {
// 1. Write the JSON payload to a temporary file
// The writeJSON step ensures the content is valid JSON, escaping internal characters
writeFile(file: jsonFilePath, text: writeJSON(returnText: true, json: newCICD_Payload))
final String newCICD_JSON_log = readFile(file: jsonFilePath)
log.info("New CICD JSON (from file) - ${newCICD_JSON_log.take(500)}...") // Log a snippet
final def(String response, String code) = sh(
returnStdout: true,
script: """
curl -s -X POST \\
-H '$newCICD_Header' \\
-w '\\n%{response_code}' \\
$newCICD_URL \\
-d @$jsonFilePath
"""
).trim().tokenize("\n")
if (code != "200") {
log.error("CICD Application API call failed with error code - ${code}, response - ${response}")
}
} catch (Exception e) {
log.error("CICD Application API call failed - " + "Error: " + e.toString())
throw e
} finally {
sh(script: "rm -f ${jsonFilePath}", returnStatus: true)
}
}
}
def callApi(String url, String header, String jsonData){
try{
withCredentials([usernamePassword(credentialsId: "ringmaster-token", usernameVariable:'user', passwordVariable: 'token')]){
final def(String response, String code) = sh(returnStdout: true, script: "curl -s -X POST -H '$header' -H 'Authorization: $token' -w '\\n%{response_code}' $url -d '$jsonData'").trim().tokenize("\n")
log.info("HTTP response status code : ${code}")
if(code != "200"){
log.error("API call failed with error code - ${code}, response - ${response}")
currentBuild.result = 'FAILURE'
}
}
}
catch ( Exception e) {
log.error("API call failed")
currentBuild.result = 'FAILURE'
throw e
}
}
@NonCPS
def getDateTime() {
// Get the current date and time in IST
def currentDateTime = ZonedDateTime.now()
// Create a formatter for the desired pattern
def formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss")
.appendOffset("+HH:mm", "+00:00")
.toFormatter()
// Format the current date and time using the formatter
def formattedDateTime = currentDateTime.format(formatter)
return formattedDateTime;
}
-185
View File
@@ -1,185 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.constructTemplate
import com.homelab.utilities.gitActions
import com.homelab.utilities.buTeamMapping
import com.homelab.utilities.getDockerParams
import com.homelab.stages.multiBranchPipeline
def run(Map params) {
def btObj = new buTeamMapping()
def gitObj = new gitActions()
def environments = ['stg':'develop', 'int':'pre-prod', 'prd':'main', 'ftr':'feature']
final Map<?, ?> modifiedParams = new HashMap<>(params)
// def helm_repo_name = 'devops-helm-charts'
// def argoRepo = "devops-argo-config"
def deployment_order = modifiedParams.app_names.replaceAll('\\s', '').split(', ') as List
modifiedParams['deployment_order'] = deployment_order
stage('Create Jenkinsfile') {
jenkinsfileCreate(modifiedParams)
}
modifiedParams['bu'] = btObj.get_bu_initials(modifiedParams['bu'])
modifiedParams['team'] = btObj.get_team_initials(modifiedParams['team'])
log.info(modifiedParams)
stage('Update Helm charts') {
gitObj.clone("${WORKSPACE}", "${env.helm_repo_name}", null)
environments.each {
modifiedParams['environment'] = it.key
def helm_branch_name = it.value
for (deployment in deployment_order) {
modifiedParams['app_name'] = deployment
modifiedParams['host'] = helm_branch_name == 'feature' ? "INGRESS_PR_NUMBER-${deployment}.dev.internal.homelabtest.in" : "${deployment}.${it.key}.internal.homelabtest.in"
modifiedParams['host'] = (helm_branch_name == 'pre-prod') ? "${deployment}.${modifiedParams.bu}.internal.homelab.co" : modifiedParams.host
//If branch is main, then assuming the env as prod
//Making nodeSelector changes to hypercore or hypermem & based on arch, so that it moves to common node pool
if (helm_branch_name == 'main') {
def cpu = modifiedParams['cpu_request']
def memory = modifiedParams['memory_request']
def nodeSelector = 'hypercore'
if (cpu.contains('m')) {
def numericValue = cpu.replaceAll('\\D+', '').toDouble()
def gb = numericValue / 1000
cpu = gb.toString()
}
def mem_dgt = memory.replaceAll('\\D+', '').toDouble()
memory = memory.contains('Mi') ? mem_dgt / 1024 : mem_dgt
def ratio = cpu.toDouble() / memory.toDouble()
def arch = modifiedParams['arch']
def graviton_required = false
if (arch == 'arm64') {
graviton_required = true
}
if (ratio <= 1 / 3) {
if (graviton_required) {
nodeSelector = 'hypermem-arm64'
} else {
nodeSelector = 'hypermem'
}
} else {
if (graviton_required) {
nodeSelector = 'hypercore-arm64'
} else {
nodeSelector = 'hypercore'
}
}
modifiedParams['nodeSelector'] = nodeSelector
}
updateHelmRepo(modifiedParams, env.helm_repo_name, helm_branch_name)
}
}
}
// stage("Update Argo Application"){
// gitObj.clone("${WORKSPACE}", "${argoRepo}", null)
// environments.each{
// modifiedParams["environment"] = it.key
// def argo_branch_name = it.value
// for (deployment in deployment_order){
// modifiedParams["app_name"] = deployment
// updateArgoRepo(modifiedParams,argoRepo,argo_branch_name)
// }
// }
// }
stage('Create ECR repo') {
def buildDockerObj = new getDockerParams()
def modules = buildDockerObj.getModules(modifiedParams['repo_name'])
if (modules == null) {
modules = ['module_less']
}
for (module in modules) {
def ecr_repo_name = (module == 'module_less') ? "${modifiedParams.team}/${modifiedParams.repo_name.toLowerCase()}" : "${modifiedParams.team}/${modifiedParams.repo_name.toLowerCase()}/${module}"
try {
sh "aws ecr create-repository --repository-name ${ecr_repo_name}"
}
catch (Exceptione) {
log.info('repository already present')
}
}
}
stage('Create Multibranch pipeline') {
def multiBranchPipelineObj = new multiBranchPipeline()
multiBranchPipelineObj.applicationOnboard(params['bu'], params['repo_name'])
}
}
def jenkinsfileCreate(Map config) {
def constructObj = new constructTemplate()
def gitObj = new gitActions()
def repo_name = config.repo_name
def deployment_order = config.deployment_order
def repo_branch_name = 'eks_onboarding'
config['branch_params'] = ''
config['excludedMoudles'] = config.excludedMoudles.replaceAll('\\s', '').split(', ') as List
gitObj.clone("${WORKSPACE}", "${config.repo_name}", null)
gitObj.branchCheckOut(config.repo_name, repo_branch_name)
deployment_yaml_file = get_deployment_yaml_file(config['dockerBuildVersion'])
dir(repo_name) {
sh(script:'mkdir -p deployments/')
sh 'chmod -R 777 .'
constructObj.renderTemplate(config, 'Jenkinsfile', 'Jenkinsfile')
gitObj.add('.', 'Jenkinsfile')
constructObj.renderTemplate(config, 'config.yaml', 'config.yaml')
gitObj.add('.', 'config.yaml')
dir('deployments') {
for (deployment in deployment_order) {
config['app_name'] = deployment
constructObj.renderTemplate(config, deployment_yaml_file, deployment + '.yaml')
gitObj.add('.', deployment + '.yaml')
}
}
}
gitObj.codeCommit(repo_name, repo_branch_name, 'Generating build and deployments files')
gitObj.codePush(repo_name, repo_branch_name)
}
def updateHelmRepo(Map config, String helm_repo_name, String helm_branch_name) {
def constructObj = new constructTemplate()
def gitObj = new gitActions()
def filepath = "${env.helmChartsPath}/${config.bu}/${config.team}/${config.app_name}"
def file_name = 'values_properties.yaml'
def app_branch = config.app_name + '-' + helm_branch_name + '-helm'
def pr_num = ''
def commit_status = 0
gitObj.branchCheckOut(env.helm_repo_name, helm_branch_name)
gitObj.branchCheckOut("${env.helm_repo_name}", "${app_branch}")
// create filepath
dir(env.helm_repo_name) {
sh(script:"mkdir -p ${filepath}" ,returnStdout:true)
sh 'chmod -R 777 .'
constructObj.renderTemplate(config, file_name, filepath + '/' + file_name)
}
// git commit and push
gitObj.add(env.helm_repo_name, filepath + '/' + file_name)
commit_status = gitObj.codeCommit(env.helm_repo_name, app_branch, 'Generating properties values yaml file')
if (commit_status == 0) {
gitObj.codePush(env.helm_repo_name, app_branch)
pr_num = gitObj.createPR(config.app_name, env.helm_repo_name, helm_branch_name, app_branch, 'Merge helm values properties')
gitObj.mergePR(env.helm_repo_name, pr_num, app_branch)
gitObj.deleteBranch(env.helm_repo_name, helm_branch_name, app_branch)
}
}
def get_deployment_yaml_file(def dockerBuildVersion) {
switch(dockerBuildVersion) {
case ~/^maven-.*/: return 'deployment.yaml'
case ~/^node-.*/: return 'node-deployment.yaml'
case ~/^python-.*/: return 'python-deployment.yaml'
case ~/^go.*/: return 'go-deployment.yaml'
case 'gradle': return 'gradle-deployment.yaml'
case 'php': return 'php-deployment.yaml'
}
}
-24
View File
@@ -1,24 +0,0 @@
package com.homelab.stages
def run(String repo_name){
stage(stageName("Check for Hot Fix")){
dir(repo_name){
if (env.CHANGE_ID) {
def source_branch_name = env.CHANGE_BRANCH
log.info("Source-Branch : ${source_branch_name}")
source_branch_name = source_branch_name.toLowerCase()
if (source_branch_name.contains("hotfix_")){
env.hot_fix = true
log.info("***************** Enabling Hot-fix workflow *****************")
}
else if (source_branch_name.matches('^revert-\\d+-.+$')){
env.hot_fix = true
log.info("***************** Enabling Hot-fix workflow for revert branch *****************")
}
}
else {
log.info("**** Branch: ${env.BRANCH_NAME}, So Skipping Hot-fix check ****")
}
}
}
}
@@ -1,73 +0,0 @@
package com.homelab.stages
import jxl.*
import hudson.util.PersistedList
import jenkins.model.Jenkins
import jenkins.branch.*
import jenkins.plugins.git.*
import org.jenkinsci.plugins.workflow.multibranch.*
import com.cloudbees.hudson.plugins.folder.*
import org.jenkinsci.plugins.github_branch_source.*
import org.jenkinsci.plugins.workflow.libs.*
import hudson.scm.SCM
import hudson.plugins.git.*
import net.gleske.scmfilter.impl.trait.*
def applicationOnboard(String foldername, String repo_name) {
// Bring some values in from ansible using the jenkins_script modules wierd "args" approach (these are not gstrings)
String folderName = "${foldername}"
String repoName = "${repo_name}"
String scriptPath = "Jenkinsfile"
String gitRepo = "https://github.com/Homelab/${repo_name}.git"
String mBPName = "${repo_name}-cicd"
String credentialsId = env.GITHUB_CRED
Jenkins jenkins = Jenkins.instance // saves some typing
// Get the folder where this job should be
// def folder = jenkins.getItem(folderName)
// //Create the folder if it doesn't exist
// if (folder == null) {
// folder = jenkins.createProject(Folder.class, folderName)
// }
// Multibranch creation/update
WorkflowMultiBranchProject mbp
def view = jenkins.getView(foldername)
Item item = jenkins.getItem(mBPName)
if ( item != null ) {
// Update case
mbp = (WorkflowMultiBranchProject) item
} else {
// Create case
mbp = jenkins.createProject(WorkflowMultiBranchProject.class, mBPName)
}
// Configure the script this MBP uses
mbp.getProjectFactory().setScriptPath(scriptPath)
def implicit = false
def defaultVersion = "master"
def traits = []
GitHubSCMSource gitHubSCMSource = new GitHubSCMSource("Homelab", repoName, gitRepo, implicit)
gitHubSCMSource.credentialsId = credentialsId
BranchDiscoveryTrait branchDiscoveryTrait = new BranchDiscoveryTrait(3)
OriginPullRequestDiscoveryTrait pullRequestTrait = new OriginPullRequestDiscoveryTrait(1)
WildcardSCMHeadFilterTrait wildcardSCMHeadFilterTrait = new WildcardSCMHeadFilterTrait('gcp-main*','','','*')
traits.add(branchDiscoveryTrait)
traits.add(pullRequestTrait)
traits.add(wildcardSCMHeadFilterTrait)
gitHubSCMSource.setTraits(traits)
BranchSource branchSource = new BranchSource(gitHubSCMSource)
NoTriggerBranchProperty noTriggerBranchProperty = new NoTriggerBranchProperty()
BranchProperty[] ntbp = [noTriggerBranchProperty]
branchSource.setStrategy(new DefaultBranchPropertyStrategy(ntbp))
PersistedList sources = mbp.getSourcesList()
sources.clear()
sources.add(branchSource)
view.add(mbp)
}
@@ -1,24 +0,0 @@
package com.homelab.stages
def run(Map config) {
try {
def repo_name = config.repo_name
stage('Security scan') {
if (config.skip_security_scan) {
log.info('Skipping - Security Scan')
}
else {
final String url = '172.31.5.29:63232/scans'
final def(String response, String code) = sh(returnStdout: true, script: "curl -s -X POST -H 'Content-Type: application/json' -w '\\n%{response_code}' $url -d '{\"reponame\":\"$repo_name\",\"branch\":\"$BRANCH_NAME\"}'").trim().tokenize('\n')
log.info("HTTP response status code : ${code}")
log.info("Response: ${response}")
}
}
}
catch ( Exception e) {
env.msg = 'failed in security scan . Please check console output for more details.'
log.error(env.msg)
currentBuild.result = env.FAILURE
throw e
}
}
@@ -1,18 +0,0 @@
package com.homelab.stages
import com.homelab.utilities.buTeamMapping
def run(String bu, String team,String module){
stage("Validate BU and Team"){
def vObj = new buTeamMapping()
if (vObj.validate(bu,team)){
log.info("Correct team and BU values")
}
else{
error "Incorrect BU and team values provided"
}
if(module == ""){
error "Module can't be empty. if there is no module, Please provide the parameter value as module_less"
}
}
}
@@ -1,28 +0,0 @@
package com.homelab.utilities
def create() {
withCredentials([file(credentialsId: 'ssh-private-key', variable: 'FILE')]) {
sh """
cat ${FILE} > ./id_github_jenkins
chmod 600 ./id_github_jenkins
# Ensure .ssh directory has correct permissions
chmod 700 /root/.ssh
# Fix SSH config file permissions if it exists
if [ -f /root/.ssh/config ]; then
chmod 600 /root/.ssh/config
chown root:root /root/.ssh/config
fi
# Fix existing SSH private key permissions if it exists
if [ -f /root/.ssh/id_rsa ]; then
chmod 600 /root/.ssh/id_rsa
chown root:root /root/.ssh/id_rsa
fi
# Fix any other SSH key files that might exist
find /root/.ssh -type f -name "id_*" -exec chmod 600 {} \\; 2>/dev/null || true
"""
}
}
@@ -1,125 +0,0 @@
/*
Purpose: Utility function to return BU and their respective teams
Author: Avinash kumar Lodhi
*/
package com.homelab.utilities
def validate(String bu, String team) {
def bu_team_map = ['supply':['supplier-ads', 'supplier-ads-frontend', 'experience', 'fulfilment', 'fulfilment-frontend','financial-services', 'cataloging', 'cataloging-frontend', 'payout', 'payout-frontend', 'supplier-acquisition-activation', 'supplier-service', 'returns', 'supply-shared', 'display-ads', 'offers','transact', 'supplier-live-commerce'],
'demand':['comms-platform', 'live-commerce', 'shopping-platform', 'product-feed', 'search', 'product-meta', 'user-growth', 'web', 'transact', 'communications', 'discovery-platform', 'offers', 'android-platform', 'ios', 'demand-shared', 'discovery-ranking'],
'farmiso':['farmiso'],
'admin':['devops'],
'central':['shared', 'devops', 'psec', 'dbe'],
'dataengg':['data-platform', 'dataengg-shared', 'data-intelligence', 'data-platform-consumption', 'data-platform-ingestion', 'data-platform-nrt', 'data-platform-prism-frmw', 'data-platform-experimentation'],
'datascience':['data-science', 'ml-platform', 'for-you', 'recommendation', 'catalog-listing-page', 'search', 'advertisement', 'explore', 'pricing', 'product-match', 'catalog-taxonomy', 'brand-infringment', 'fds', 'return-reimbursements', 'fullfilment', 'ugc-moderation-analysis', 'home-page', 'core', 'usergrowth', 'demand-forecast', 'catalog-qc'],
'mcache':['mcache', 'mcache-shared', 'supplier-service'],
'infra':['devops', 'dbe']
]
if (bu == null || team == null) {
return null
}
return bu_team_map[bu].contains(team)
}
def get_initials(String targetMap, String targetString) {
def bu_initials = ['supply':'supl',
'demand':'dmnd',
'farmiso':'farm',
'admin':'admn',
'central':'cntr',
'dataengg':'deng',
'datascience':'dsci',
'mcache':'mche',
'infra':'infr'
]
def team_initials = ['supplier-ads':'ads',
'comms-platform': 'cplat',
'supplier-ads-frontend':'fads',
'experience':'xp',
'fulfilment':'fnf',
'fulfilment-frontend':'ffnf',
'financial-services':'fsvc',
'cataloging':'ctlng',
'cataloging-frontend':'fctlg',
'payout':'pay',
'payout-frontend':'fpay',
'supplier-acquisition-activation':'saa',
'supplier-service':'ssvc',
'seller-services': 'sis',
'live-commerce':'lcom',
'shopping-platform':'splat',
'product-feed':'pfeed',
'search':'srch',
'product-meta':'pmeta',
'user-growth':'grwth',
'web':'web',
'transact':'trnst',
'communications':'comms',
'discovery-platform':'dplat',
'farmiso':'farm',
'devops':'devop',
'offers':'offer',
'returns':'retrn',
'android-platform':'andrd',
'ios':'ios',
'shared':'xcntr',
'supply-shared':'xsupl',
'demand-shared':'xdmnd',
'data-platform':'dp',
'data-science':'ds',
'ml-platform':'ml',
'dataengg-shared':'xdeng',
'datascience-shared':'xdsci',
'data-intelligence':'di',
'recommendation':'rcmnd',
'catalog-listing-page':'ctllp',
'advertisement':'adv',
'explore':'explr',
'pricing':'price',
'product-match':'patch',
'catalog-taxonomy':'ctltx',
'brand-infringment':'brndi',
'fds':'fds',
'return-reimbursements':'retrr',
'fullfilment':'flfmt',
'ugc-moderation-analysis':'umdra',
'home-page':'hpage',
'usergrowth':'ugrwt',
'demand-forecast':'dmndf',
'catalog-qc':'ctlqc',
'data-platform-consumption':'dpcon',
'data-platform-ingestion':'dping',
'data-platform-nrt':'dpnrt',
'data-platform-prism-frmw':'dpprf',
'data-platform-experimentation':'dpexp',
'display-ads':'dplay',
'discovery-ranking':'drank',
'mcache':'mche',
'mcache-shared':'xmche',
'supplier-live-commerce':'slcom',
'trust-and-safety': 'tns',
'valmo': 'vlm',
'psec':'psec',
'dbe':'dbe',
'dev-productivity':'devprd']
if (targetString == null) {
return null
}
switch (targetMap) {
case 'bu_initials':
return bu_initials[targetString]
case 'team_initials':
return team_initials[targetString]
default:
return 'Undefined option'
}
}
def get_team_initials(String team) {
return get_initials('team_initials', team)
}
def get_bu_initials(String bu) {
return get_initials('bu_initials', bu)
}
@@ -1,391 +0,0 @@
package com.homelab.utilities
def getWhitelistedRepos(fileName){
dir('whitelist'){
git(
url: "https://github.com/Homelab/whitelists.git",
branch: "main",
credentialsId: 'cicd-github-app',
)}
def yaml = readYaml file: "whitelist/${fileName}.yaml"
return yaml.get("repos", []) as Set
}
def getWhitelistedDeployable(fileName, keyName){
dir('whitelist'){
git(
url: "https://github.com/Homelab/whitelists.git",
branch: "main",
credentialsId: 'cicd-github-app',
)}
def yaml = readYaml file: "whitelist/${fileName}.yaml"
return yaml.get(keyName, []) as Set
}
/*
* return `true` if we should not proceed
*/
def isMultizoneEnabled( String deployable){
def WHITELIST = getWhitelistedDeployable("multizone-enabled-repos" , "multizone_enabled_deployables")
if (WHITELIST.contains(deployable)) {
return true
}
return false
}
/*
* return `true` if we should not proceed
*/
def skipSonarCheckForbidden(Map config, Map environment_map) {
def branch = env.BRANCH_NAME
def environment = environment_map.getOrDefault(branch, "int")
def WHITELIST = getWhitelistedRepos("skip-sonar-whitelist")
// returns 'true' if we aren't skipping sonar
// or if we're allowed to skip sonar
def build_version = config['dockerBuildVersion']
def repo_name = config['repo_name']
// if not a maven build OR if it a hotfix we exit early and dont care what skip_sonar is
if (WHITELIST.contains(repo_name)|| !(build_version.contains("maven")) || environment != "prd" || branch.contains("hotfix")){
return false;
}
return config['skip_sonar'];
}
def skipSonarCheckForGo(Map config) {
def branch = env.BRANCH_NAME
def WHITELIST = getWhitelistedRepos("skip-sonar-whitelist")
def build_version = config['dockerBuildVersion']
def repo_name = config['repo_name']
echo "env.INFRA_ENV: ${env.INFRA_ENV}"
if (WHITELIST.contains(repo_name)|| branch.contains("hotfix")|| env.INFRA_ENV == "toolchain"){
return true;
}
return false;
}
/*
* return `true` if we should not proceed
*/
def appConfigDisabledForbidden(boolean appConfigEnabled, String repo_name, String environment, String build_version){
def branch = env.CHANGE_TARGET
def WHITELIST = getWhitelistedRepos("app-config-disabled")
if (WHITELIST.contains(repo_name) || environment!="stg"){
return false
}
if (!(build_version.contains("maven") || build_version.contains("gradle"))){
return false
}
return !appConfigEnabled
}
/*
* return `true` if we should not proceed
*/
def allowedNonDevelopPrDeploymentToIntRepos( String repo_name){
def WHITELIST = getWhitelistedRepos("allowedNonDevelopPrDeploymentToInt")
if (WHITELIST.contains(repo_name)) {
return true
}
return false
}
/*
* return `true` if we should not proceed
*/
def ValidateCacConfigForRepo(boolean ValidateConfig, String repo_name ){
def branch = env.CHANGE_TARGET
def WHITELIST = getWhitelistedRepos("ValidateCacConfig")
if (WHITELIST.contains(repo_name)) {
return true
}
return ValidateConfig
}
def getToolchainEnv() {
def paramsAction = currentBuild.rawBuild.getAction(hudson.model.ParametersAction.class)
if (paramsAction) {
echo "paramsAction: ${paramsAction}"
def p = paramsAction.getParameter("TOOLCHAIN_ENV")
echo "p: ${p}"
if (p) {
return p.getValue()?.toString()
}
}
return null
}
def run(Map config) {
def branch_name = env.BRANCH_NAME
if (env.INFRA_ENV == 'toolchain' && (config.build_tool?.startsWith('node-') || config.dockerBuildVersion?.startsWith('node-'))) {
branch_name = 'develop' // develop maps to stg in the environment_map
def tcEnv = getToolchainEnv()
env.TOOLCHAIN_ENV = tcEnv
log.info("Successfully extracted TOOLCHAIN_ENV from trigger cause: ${env.TOOLCHAIN_ENV}")
}
def environment_map = ['master':'prd', 'main':'prd', 'develop':'stg', 'gcp-main':'prd', 'farmiso-main':'prd', 'gcp-master':'prd', 'gcp-dev':'stg']
env.skip_user_input = config.skip_user_input ?: false
// don't allow skip_sonar
if (skipSonarCheckForbidden(config, environment_map)){
throw new Exception("Not allowed to skip sonar (skip_sonar in config.yaml)")
}
if (env.CHANGE_ID) {
branch_name = env.CHANGE_TARGET
environment_map = ['master':'int', 'main':'int', 'gcp-main':'int', 'farmiso-main':'int', 'gcp-master':'int', 'develop':'ftr', 'gcp-dev':'ftr']
}
environment_map[branch_name] = environment_map[branch_name] ?: 'ftr'
if (config.containsKey('branch_params')) {
Map branch_config = config['branch_params'].collectEntries { key, value -> branch_name.matches(key) ? value : [ : ] }
config.remove('branch_params')
config.putAll(branch_config)
}
if (config.containsKey('environment')) {
Map envrionment_config = config['environment'].collectEntries { key, value -> environment_map[branch_name].matches(key) ? value : [ : ] }
config.remove('environment')
config.putAll(envrionment_config)
}
env.GITHUB_CRED = 'svc-devops-homelab'
env.cicd_environment = environment_map[branch_name]
env.helm_repo_name = 'devops-helm-charts'
env.argo_repo_name = 'devops-argo-config'
echo "Branch Name - ${branch_name} and Environment - ${env.cicd_environment}"
if (env.CLOUD_PROVIDER == 'AWS') {
def prodAccountID = '847438129436'
def prodRegion = 'ap-southeast-1'
def prodObjBucket = 'homelab-prod-artifacts'
def devAccountID = '766380763301'
def devObjBucket = 'homelab-stg-artifacts'
def devRegion = 'ap-south-1'
def accountDetails = [
'prd': [
'accountID': prodAccountID,
'region': prodRegion,
'objBucket': prodObjBucket
],
'int': [
'accountID': prodAccountID,
'region': prodRegion,
'objBucket': prodObjBucket
],
'stg': [
'accountID': devAccountID,
'region': devRegion,
'objBucket': devObjBucket
],
'ftr': [
'accountID': devAccountID,
'region': devRegion,
'objBucket': devObjBucket
]
]
env.accountID = accountDetails[env.cicd_environment]['accountID']
env.region = accountDetails[env.cicd_environment]['region']
env.registry = "${env.accountID}.dkr.ecr.${env.region}.amazonaws.com"
env.buildRegistry = env.registry
env.helmChartsPath = 'charts'
env.defaultHelmChartVersion = '1.0.10'
env.objBucket = accountDetails[env.cicd_environment]['objBucket']
env.skip_notify = false
echo "${env.accountID}.dkr.ecr.${env.region}.amazonaws.com"
}
else if (env.CLOUD_PROVIDER == 'GCP') {
def prodVaultURL = 'https://vault-prd.homelabgcp.in'
def prodVaultToken = 'vault-prd-token'
def prodSonarURL = 'https://sonarqube-prd.homelabgcp.in'
def prodSonarToken = 'sonar-token-prod'
def prodSonarEnv = 'sonarqube-test'
def prodGoProxyUrl = 'https://athens-prd.homelabgcp.in'
def prdDockerHost = 'dind-prd-svc'
def preProdDockerHost = 'dind-int-svc'
def prodGCPProject = "homelab-${config.bu}-prd-0622"
def preprodGCPProject = "homelab-shared-int-0525"
def devVaultURL = 'https://vault-dev.homelabgcp.in'
def devVaultToken = 'vault-dev-token'
def devSonarURL = "https://sonarqube-${config.bu}-dev.homelabgcp.in"
def devSonarToken = "sonar-token-${config.bu}-dev"
def devSonarEnv = "sonar-${config.bu}-dev"
def devGoProxyUrl = 'https://athens-dev.homelabgcp.in'
def devGCPProject = "homelab-${config.bu}-dev-0622"
def devDockerHost = 'dind-dev-new-svc.jenkins-new.svc.cluster.local'
def toolchainDockerHost = 'toolchain-dind-dev-svc.jenkins-toolchain.svc.cluster.local'
def accountDetails = [
'prd': [
'vaultURL': prodVaultURL,
'vaultToken': prodVaultToken,
'sonarURL': prodSonarURL,
'sonarToken': prodSonarToken,
'GCPProject': prodGCPProject,
'sonarEnv': prodSonarEnv,
'GCPLBProject': prodGCPProject,
'goProxyUrl': prodGoProxyUrl,
'dockerHost': prdDockerHost
],
'int': [
'vaultURL': prodVaultURL,
'vaultToken': prodVaultToken,
'sonarURL': prodSonarURL,
'sonarToken': prodSonarToken,
'GCPProject': preprodGCPProject,
'sonarEnv': prodSonarEnv,
'GCPLBProject': prodGCPProject,
'goProxyUrl': prodGoProxyUrl,
'dockerHost': preProdDockerHost
],
'stg': [
'vaultURL': devVaultURL,
'vaultToken': devVaultToken,
'sonarURL': devSonarURL,
'sonarToken': devSonarToken,
'GCPProject': devGCPProject,
'sonarEnv': devSonarEnv,
'GCPLBProject': devGCPProject,
'goProxyUrl': devGoProxyUrl,
'dockerHost': devDockerHost
],
'ftr': [
'vaultURL': devVaultURL,
'vaultToken': devVaultToken,
'sonarURL': devSonarURL,
'sonarToken': devSonarToken,
'GCPProject': devGCPProject,
'sonarEnv': devSonarEnv,
'GCPLBProject': devGCPProject,
'goProxyUrl': devGoProxyUrl,
'dockerHost': devDockerHost ]
]
env.GCPProject = accountDetails[env.cicd_environment]['GCPProject']
env.GCPLBProject = accountDetails[env.cicd_environment]['GCPLBProject']
env.registry = 'asia-southeast1-docker.pkg.dev/homelab-devops-admin-0622'
if (env.INFRA_ENV == 'toolchain') {
env.registry = 'asia-southeast1-docker.pkg.dev/homelab-central-dev-0622/toolchain'
}
env.buildRegistry = 'asia-southeast1-docker.pkg.dev/homelab-devops-admin-0622/admin'
env.helmChartsPath = env.cicd_environment == 'prd' ? 'values_v3' : 'values_v2'
env.defaultHelmChartVersion = '2.0.0'
env.objBucket = "gcs-infr-dvps-homelab-artifacts-${env.cicd_environment}"
env.vaultURL = accountDetails[env.cicd_environment]['vaultURL']
env.vaultToken = accountDetails[env.cicd_environment]['vaultToken']
env.sonarURL = accountDetails[env.cicd_environment]['sonarURL']
env.sonarToken = accountDetails[env.cicd_environment]['sonarToken']
env.sonarEnv = accountDetails[env.cicd_environment]['sonarEnv']
env.goProxyUrl = accountDetails[env.cicd_environment]['goProxyUrl']
env.skip_notify = true
env.DOCKER_HOST = accountDetails[env.cicd_environment]['dockerHost']
if (env.INFRA_ENV == 'toolchain') {
env.DOCKER_HOST = toolchainDockerHost
}
}
echo "Bucket and Image Repo Details - ${env.registry} ${env.buildRegistry} ${env.objBucket}"
echo "Docker Host - ${env.DOCKER_HOST}"
}
def perDeploymentVars(Map value_binding) {
env.BU = value_binding.bu
echo "${env.BU}"
if (env.CLOUD_PROVIDER == 'AWS') {
def inClusterName = 'https://kubernetes.default.svc'
def prodArgoURL = 'prod-ops-argocd.homelab.com'
def devArgoURL = 'stg-dev-argocd.homelabtest.in'
def prodK8sCluster = [
'supply': 'https://211689C65F4496AAA76FE19B29E24B6E.yl4.ap-southeast-1.eks.amazonaws.com',
'demand': 'https://9059D138B6277A0EA592BA7F4B680CEC.gr7.ap-southeast-1.eks.amazonaws.com',
'dataengg': 'https://806ADE97231CA65D2A0FFB780352630D.yl4.ap-southeast-1.eks.amazonaws.com',
'datascience': 'https://E34D119516F751AFD1A61043B0514726.yl4.ap-southeast-1.eks.amazonaws.com',
'central': 'https://C95FCEDF7CEE890F531E1D0488BEC6C3.gr7.ap-southeast-1.eks.amazonaws.com',
'mcache': 'https://2FFADF214AD8BE58769C5F2797987E50.gr7.ap-southeast-1.eks.amazonaws.com'
]
def devK8sCluster = [
'supply': inClusterName,
'demand': inClusterName,
'dataengg': inClusterName,
'datascience': inClusterName,
'central': inClusterName,
'mcache': inClusterName
]
def accountDetails = [
'prd': [
'argoURL': prodArgoURL,
'argoIncubator': 'prod-app-of-apps',
'serverMap': prodK8sCluster
],
'int': [
'argoURL': prodArgoURL,
'argoIncubator': 'int-app-of-app',
'serverMap': prodK8sCluster
],
'stg': [
'argoURL': devArgoURL,
'argoIncubator': 'app-of-apps',
'serverMap': devK8sCluster
],
'ftr': [
'argoURL': devArgoURL,
'argoIncubator': 'ftr-app-of-apps',
'serverMap': devK8sCluster
]
]
env.clusterName = accountDetails[env.cicd_environment]['serverMap'][env.BU]
env.argoAppsPath = 'applications'
env.argoURL = accountDetails[env.cicd_environment]['argoURL']
env.argoCreds = 'argocd-jenkins'
env.argoIncubator = accountDetails[env.cicd_environment]['argoIncubator']
env.argoAppNS = 'argocd'
}
else if (env.CLOUD_PROVIDER == 'GCP') {
def prodArgoURL = "argocd-${env.BU}-prd.homelabgcp.in"
def prodArgoCreds = "argocd-${env.BU}-prd-creds"
def preprodArgoURL = "argocd-shared-int.homelabgcp.in"
def preprodArgoCreds = "argocd-shared-int-creds"
def devArgoURL = 'argocd-dev.homelabgcp.in'
def devArgoCreds = 'argocd-dev-creds'
def accountDetails = [
'prd': [
'argoURL': prodArgoURL,
'argoCreds': prodArgoCreds,
'argoAppNS': "argocd-${env.BU}-prd",
'clusterName': "k8s-${env.BU}-prd-ase1"
],
'int': [
'argoURL': preprodArgoURL,
'argoCreds': preprodArgoCreds,
'argoAppNS': "argocd-shared-int",
'clusterName': "k8s-shared-int-ase1"
],
'stg': [
'argoURL': devArgoURL,
'argoCreds': devArgoCreds,
'argoAppNS': "argocd-dev",
'clusterName': "k8s-${env.BU}-stg-ase1"
],
'ftr': [
'argoURL': devArgoURL,
'argoCreds': devArgoCreds,
'argoAppNS': "argocd-dev",
'clusterName': "k8s-${env.BU}-stg-ase1"
]
]
env.clusterName = accountDetails[env.cicd_environment]['clusterName']
if (env.cicd_environment == 'int') {
env.argoAppsPath = "applications_v2/k8s-${env.BU}-int-ase1"
} else {
env.argoAppsPath = "applications_v2/${env.clusterName}"
}
env.argoURL = accountDetails[env.cicd_environment]['argoURL']
env.argoCreds = accountDetails[env.cicd_environment]['argoCreds']
env.argoAppNS = accountDetails[env.cicd_environment]['argoAppNS']
env.argoIncubator = "incubator-apps-k8s-${env.BU}-${env.cicd_environment}-ase1"
}
echo "${env.clusterName} ${env.argoURL} ${env.argoIncubator}"
}
@@ -1,52 +0,0 @@
package com.homelab.utilities
def retryDockerPush(String cmd) {
int maxAttempts = 5
int attempt = 1
while (attempt <= maxAttempts) {
try {
sh cmd
break
} catch (err) {
if (attempt == maxAttempts) {
error("Command failed after ${maxAttempts} attempts: ${err}")
}
echo "Command failed, retrying... (${attempt}/${maxAttempts})"
sleep 3
attempt++
}
}
}
def imageExists(String registry, String repoName, String tag) {
int maxAttempts = 5
int attempt = 1
while (attempt <= maxAttempts) {
try {
if (env.CLOUD_PROVIDER == 'GCP') {
def result = sh(
script: "gcloud container images list-tags ${registry}/${repoName} --filter='tags:${tag}' --format='get(tags)'",
returnStdout: true
).trim()
return result != ""
}
else if (env.CLOUD_PROVIDER == 'AWS') {
echo "AWS not supported."
return false
}
} catch (Exception e) {
echo "Attempt ${attempt}/${maxAttempts} failed: Error checking image existence: ${e.toString()}"
if (attempt == maxAttempts) {
echo "Max attempts reached. Assuming image does not exist or service is down."
return false
}
echo "Retrying in 5 seconds..."
sleep 5
attempt++
}
}
return false
}
@@ -1,61 +0,0 @@
package com.homelab.utilities
def getCommitid(String repo_name) {
dir(repo_name) {
def gitCmd = env.INFRA_ENV == 'toolchain' ? 'git -c safe.directory="$(pwd)"' : 'git'
def commitID = sh(returnStdout: true, script: "${gitCmd} log -1 --format=%h").trim()
env.commit_id = sh(returnStdout: true, script: "${gitCmd} log -1 --format=%H").trim()
return commitID
}
}
def getVersion(String repo_name) {
dir(repo_name) {
if (fileExists('pom.xml')) {
return sh(returnStdout: true, script: 'xq -r .project.version pom.xml').trim()
}
else if (fileExists('package.json')) {
return sh(returnStdout: true, script: 'jq -r .version package.json').trim()
}
else {
return '1.0'
}
}
}
def getModules(String repo_name) {
dir(repo_name) {
if (fileExists('pom.xml')) {
modules = sh(returnStdout: true, script: 'xq -r .project.modules.module[] pom.xml 2>/dev/null || xq -r .project.modules.module pom.xml 2>/dev/null || echo empty').trim()
if (modules == 'empty' || modules == 'null') {
return null
}
modules = modules.split('\n') as List
return modules
}
else {
return null
}
}
}
def getTag(String repo_name) {
def version = getVersion(repo_name)
def commitID = getCommitid(repo_name)
def date = new Date()
def timesha = date.getTime()
def tag = "v${version}-${commitID}-${timesha}"
if (env.INFRA_ENV == 'toolchain') {
tag = "v${version}-${commitID}"
}
return tag
}
def getTagShort(String repo_name) {
def version = getVersion(repo_name)
def commitID = getCommitid(repo_name)
def tagShort = "v${version}-${commitID}"
return tagShort
}
@@ -1,16 +0,0 @@
package com.homelab.utilities
def getParam(String wd, String fileName = 'config.yaml') {
dir(wd) {
def config = readYaml file: fileName
return config
}
}
//read as string
def getParamAsString(String wd, String fileName = 'config.yaml') {
dir(wd) {
// Read the entire file content as a string
def yamlContent = readFile(file: fileName)
return yamlContent
}
}
-342
View File
@@ -1,342 +0,0 @@
package com.homelab.utilities
def clone(String path, String repo_name, String branch_name) {
log.info("Cloning repo - ${repo_name}, branch - ${branch_name} in path - ${path}")
dir(path) {
try {
sh "rm -rf ${repo_name}"
}
catch (Exception e) {
log.info('Repo not present, proceeding to clone the repo.')
}
try {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
if (branch_name) {
sh "git clone -b ${branch_name} https://github.com/Homelab/${repo_name}.git"
}
else {
sh "git clone https://github.com/Homelab/${repo_name}.git"
}
}
}
catch (Exception e) {
env.msg += "\n\nFAILED -\n ```Unable to clone repo - ${repo_name}, branch - ${branch_name} in path - ${path}.\n Full Erroror Details - ${e}```"
env.error_msg_to_db += "Unable to Clone Repo ${repo_name};"
log.error("${env.msg}")
throw e
}
}
}
def branchCheckOut(String path, String branch_name) {
log.info("Checking out to branch - ${branch_name} in path - ${path}")
dir(path) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
sh 'git fetch'
try {
sh "git checkout ${branch_name}"
sh 'git pull --ff-only'
}
catch (Exception e) {
log.info('Creating new branch')
sh "git checkout -b ${branch_name}"
}
sh 'git branch'
}
}
}
def add(String path, String git_add_file) {
log.info("Adding files - ${git_add_file} to git, in path - ${path}")
try {
dir(path) {
sh "git add ${git_add_file}"
}
}
catch (Exception e) {
env.msg += "\n\nFAILED -\n ```Unable to add files - ${git_add_file} to git, in path - ${path}.\n Full Erroror Details - ${e}```"
env.error_msg_to_db += 'Unable to Add Files;'
log.error("${env.msg}")
throw e
}
}
def createTag(path, git_tag, tag_message) {
log.info("Creating tag - ${git_tag} in git, in path - ${path}")
try {
dir(path) {
sh "git tag ${git_tag} -m '${tag_message}'"
}
}
catch (Exception e) {
env.msg += "\n\nFAILED -\n ```Unable to create tag - ${git_tag} in git, in path - ${path}.\n Full Erroror Details - ${e}```"
env.error_msg_to_db += "Unable to Create Tag ${git_tag};"
log.error("${env.msg}")
throw e
}
}
def codeCommit(String path, String branch_name, String commit_message) {
log.info("Commiting code with message - ${commit_message} in git, in path - ${path}")
def global_arg = '--global'
def gitName = 'svc-devops-homelab'
def gitEmail = 'devops@homelab.com'
def gitEnv = [
"GIT_AUTHOR_NAME=${gitName}",
"GIT_AUTHOR_EMAIL=${gitEmail}",
"GIT_COMMITTER_NAME=${gitName}",
"GIT_COMMITTER_EMAIL=${gitEmail}",
]
dir(path) {
withEnv(gitEnv) {
if (sh(returnStatus: true, script: "git diff-index --quiet ${branch_name} 2>/dev/null")) {
try {
sh "git commit -m '${commit_message}'"
return 0
}
catch (Exception e) {
env.msg += "\n\nFAILED -\n ```Unable to commit code with message - ${commit_message} to git in path - ${path}.\n Full Erroror Details - ${e}```"
env.error_msg_to_db += 'Unable to Commit;'
log.error("${env.msg}")
return 1
}
}
else {
log.info("No changes were made in branch - ${branch_name}")
return 1
// log.error("${env.msg}")
}
}
}
}
def codePush(String path, String branch_name) {
log.info("Pushing code in branch - ${branch_name} in path - ${path}")
try {
dir(path) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
try {
sh "git push -f --set-upstream origin ${branch_name}"
}
catch (Exception e) {
sh 'git pull --ff-only'
sh 'git push -f'
}
}
}
}
catch (Exception e) {
env.msg += "\n\nFAILED -\n ```Unable to push code in branch - ${branch_name} in path - ${path}.\n Full Erroror Details - ${e}```"
env.error_msg_to_db += "Unable to push code in branch - ${branch_name};"
log.error("${env.msg}")
throw e
}
}
def tagPush(String path) {
log.info("Pushing tag in path - ${path}")
try {
dir(path) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
sh 'git push --tags'
}
}
}
catch (Exception e) {
env.msg += "\n\nFAILED -\n ```Unable to push tag from path - ${path}.\n Full Erroror Details - ${e}```"
env.error_msg_to_db += 'Unable to Push tag;'
log.error("${env.msg}")
throw e
}
}
def createPR(String app_name, String repo_name, String base_branch, String target_branch, String pr_message) {
log.info("Creating PR with message - ${pr_message} in Github for repo ${repo_name}")
def body = "{\"title\":\"${app_name} ${base_branch} Onboarding\",\"body\":\"${pr_message}\",\"head\":\"${target_branch}\",\"base\":\"${base_branch}\"}"
def pr_num = 'empty'
try {
withCredentials([usernamePassword(credentialsId: "${env.GITHUB_CRED}", usernameVariable:'user', passwordVariable: 'token')]) {
create_pr = httpRequest httpMode: 'POST',
customHeaders: [
[name: 'Accept', value: 'application/vnd.github+json'],
[maskValue: true, name: 'Authorization', value: 'Bearer ' + token]
],
requestBody: body,
url: "https://api.github.com/repos/Homelab/${repo_name}/pulls",
validResponseCodes: '201',
timeout: 10
def create_pr_json = readJSON(text: create_pr.content)
try {
error_filter = create_pr_json.errors.message[0]
}
catch (Exception e) {
error_filter = 'empty'
}
if ( error_filter.contains('No commits between') ) {
log.info("No changes were made in branch - ${target_branch}. Skipping - PR Creation...\n${create_pr_json}")
}
else if ( error_filter.contains('A pull request already exists') ) {
log.info(error_filter)
}
else {
pr_num = create_pr_json.number
pr_url = create_pr_json.url
log.info("PR Number - ${pr_num} and URL - ${pr_url}")
}
return pr_num.toString()
}
}
catch (Exception e) {
env.msg = "\n\nFAILED -\n Unable to create PR with message - ${pr_message}.\n Full Error Details - ${e}"
def error_code = "${e}".split('Status code')[1]
error_code = error_code.toString()
error_code = error_code.split(' ')
error_code = error_code[1]
env.error_part_msg_to_db = "Unable to Create PR for base branch - ${base_branch}, target branch - ${target_branch}, Repo Name - ${repo_name}. Failed with status code ${error_code};" //Akshay has asked to remove it
log.error("${env.msg}")
throw e
}
}
def mergePR(String repo_name, String pr_num, String target_branch) {
log.info("Merging PR ${pr_num} in repo - ${repo_name}")
if ( "${pr_num}" == 'empty' || pr_num == null) {
log.info("No changes were made in branch - ${target_branch}. Skipping - PR Merge...")
}
else {
try {
withCredentials([usernamePassword(credentialsId: "${env.GITHUB_CRED}", usernameVariable:'user', passwordVariable: 'token')]) {
merge_pr = httpRequest httpMode: 'PUT',
customHeaders: [
[name: 'Accept', value: 'application/vnd.github+json'],
[maskValue: true, name: 'Authorization', value: 'Bearer ' + token]
],
url: "https://api.github.com/repos/Homelab/${repo_name}/pulls/${pr_num}/merge",
validResponseCodes: '200',
timeout: 10
def merge_pr_json = readJSON(text: merge_pr.content)
if ( merge_pr_json.message.contains('not mergeable') ) {
env.msg += "\n\nFAILED -\n Unable to merge PR - ${pr_num}. PR URL - https://github.com/Homelab/${repo_name}/pulls/${pr_num}. ${merge_pr_json.message}"
log.error("${env.msg}")
error("${env.msg}")
}
else {
log.info("PR Merge was SUCCESSFUL. Message - ${merge_pr_json.message}")
}
}
}
catch (Exception e) {
env.msg = "\n\nFAILED -\n Unable to merge PR - ${pr_num} \n Full Error Details - ${e}"
def error_code = "${e}".split('Status code')[1]
error_code = error_code.toString()
error_code = error_code.split(' ')
error_code = error_code[1]
env.error_part_msg_to_db = "Unable to Merge PR - ${pr_num}, Repo Name - ${repo_name} status code ${error_code};" //Akshay has asked to remove it
log.error("${env.msg}")
throw e
}
}
}
def deleteBranch(String path, String base_branch, String target_branch) {
log.info("Deleting branch - ${target_branch}")
dir(path) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
sh 'git fetch'
try {
sh "git checkout ${base_branch}"
sh "git branch -d ${target_branch}"
sh "git push -d origin ${target_branch}"
}
catch (Exception e) {
env.msg = "\n\nFAILED -\n Unable to delete branch - ${target_branch}.\n Full Error Details - ${e}"
env.error_msg_to_db = "Unable to Delete Branch ${target_branch};"
log.error("${env.msg}")
throw e
}
sh 'git branch'
}
}
}
def preDeleteBranch(String path, String base_branch, String target_branch) {
log.info("Pre Deleting branch - ${target_branch}")
dir(path) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
try {
sh 'git fetch'
sh "git checkout ${base_branch}"
sh "git push -d origin ${target_branch}"
}
catch (Exception e) {
echo "Pre Delete Branch - Unable to delete branch ${target_branch}"
}
sh 'git branch'
}
}
}
def fetchDiffFilesForPullRequest(String path , String target_branch){
log.info("check diff from target branch - ${target_branch}")
dir(path) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
try {
sh "git fetch origin ${target_branch}:${target_branch}"
sh "git branch"
def changedFiles = sh(script: "git diff --name-only HEAD ${target_branch}", returnStdout: true).trim()
echo "${changedFiles}"
return changedFiles
}
catch (Exception e) {
echo "failed to get the diff files from ${target_branch}"
}
}
}
}
def fetchDiffFilesForPushRequest(String path ){
log.info("check diff of current and previous commit for ${path}")
dir(path) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
try {
sh "git fetch origin"
// Get the latest commit hash and the previous commit hash
def currentCommit = sh(script: "git rev-parse HEAD", returnStdout: true).trim()
def previousCommit = sh(script: "git rev-parse HEAD~1", returnStdout: true).trim()
// Capture the list of changed files in a Groovy variable
def changedFiles = sh(script: "git diff --name-only ${previousCommit} ${currentCommit}", returnStdout: true).trim()
return changedFiles
}
catch (Exception e) {
echo "failed to get the diff files for ${path}"
}
}
}
}
def fetchLatestCommitId(String path, String branch) {
log.info("Checking the latest commit for branch '${branch}' in path '${path}'")
dir(path) {
withCredentials([gitUsernamePassword(credentialsId: "${env.GITHUB_CRED}", gitToolName: 'git-tool')]) {
try {
// Fetch the latest changes for the specific branch
sh "git fetch origin ${branch}:${branch}"
// Check out the specified branch
sh "git checkout ${branch}"
// Get the latest commit hash for the branch
def currentCommit = sh(script: "git rev-parse ${branch}", returnStdout: true).trim()
return currentCommit
} catch (Exception e) {
echo "Failed to get the latest commit for branch '${branch}' in path '${path}': ${e.message}"
return null
}
}
}
}
@@ -1,141 +0,0 @@
package com.homelab.utilities
def run(String memory_request, String cpu_request, String priority_v2) {
echo 'Code to select node pool based on environment'
switch (env.cicd_environment) {
case 'prd':
echo 'Code to select node pool based on memory and cpu request in prd'
def mem_req_part = memory_request
def cpu_req_part = cpu_request
def priority = priority_v2
echo "mem_req_part is ${mem_req_part}"
echo "cpu_req_part is ${cpu_req_part}"
if ( mem_req_part.contains('M') ) {
mem_req = mem_req_part.replaceAll('Mi', '')
mem_req = mem_req.replaceAll('M', '')
try {
mem_req = mem_req.toDouble()
}
catch (NumberFormatException e) {
mem_req = mem_req.toDouble()
//mem_req = mem_req.toInteger()
}
}
else if ( mem_req_part.contains('G') ) {
mem_req = mem_req_part.replaceAll('Gi', '')
mem_req = mem_req.replaceAll('G', '')
try {
mem_req = mem_req.toDouble() * 1024
}
catch (NumberFormatException e) {
mem_req = mem_req.toDouble() * 1024
//mem_req = mem_req.toInteger()
}
}
echo "memory_request is ${memory_request} ${mem_req}"
if ( cpu_req_part.contains('m') ) {
cpu_req = cpu_req_part.replaceAll('m', '')
try {
cpu_req = cpu_req.toDouble()
}
catch (NumberFormatException e) {
cpu_req = cpu_req.toDouble()
//cpu_req = cpu_req.toInteger()
}
}
else {
try {
cpu_req = cpu_req_part.toDouble() * 1000
}
catch (NumberFormatException e) {
cpu_req = cpu_req_part.toDouble() * 1000
//cpu_req = cpu_req.toInteger()
}
}
echo "cpu_request is ${cpu_request} ${cpu_req}"
def ratio = (mem_req / cpu_req).toDouble()
if ( cpu_req > mem_req ) {
ratio = 2
}
//ratio = ratio.toInteger()
echo "Ratio - ${ratio}"
if(priority.equalsIgnoreCase('cp1')||priority.equalsIgnoreCase('cp2')||priority.equalsIgnoreCase('cp3')||priority.equalsIgnoreCase('up1')||priority.equalsIgnoreCase('up2')||priority.equalsIgnoreCase('up3')||priority.equalsIgnoreCase('sp1')||priority.equalsIgnoreCase('sp2')||priority.equalsIgnoreCase('sp3')){
low_priority="lite"
if ( ratio >= 2.5 ) {
ratiovalue = "tetra"
}
else {
ratiovalue = "duo"
}
if ( cpu_req >=2200 ) {
nodename = "sumo"
}
else{
nodename= "mega"
}
nodeSelectorvalue = "${nodename}${ratiovalue}${low_priority}"
println nodeSelectorvalue
break
}
else{
if ( ratio > 5.5 ) {
ratiovalue = 'octa'
}
else if ( ratio >= 2.5 ) {
ratiovalue = 'tetra'
}
else {
ratiovalue = 'duo'
}
if ( cpu_req >= 2200) {
nodevalue = 'sumo'
}
else if ( cpu_req < 2200 && cpu_req >= 1000) {
nodevalue = 'mega'
}
else {
nodevalue = 'compact'
}
switch ( env.BU?.toLowerCase() ) {
case 'supply':
if (nodevalue == 'sumo' && (ratiovalue == 'hexa' || ratiovalue == 'octa')){
ratiovalue = 'tetra'
}
else if (nodevalue == 'mega' && (ratiovalue == 'quad' || ratiovalue == 'octa')){
ratiovalue = 'tetra'
}
else if (nodevalue == 'compact' && ratiovalue == 'trio'){
ratiovalue = 'tetra'
}
break
case 'demand':
if (nodevalue == 'mega' && ratiovalue == 'quad'){
ratiovalue = 'tetra'
}
else if (nodevalue == 'compact' && (ratiovalue == 'octa' || ratiovalue == 'trio')){
ratiovalue = 'tetra'
}
break
}
nodeSelectorvalue = "${nodevalue}${ratiovalue}"
break
}
case 'int':
echo 'Shared node pool for int/pre-prod'
nodeSelectorvalue = "preprod-cost-optimized"
break
case ['dev', 'ftr', 'stg']:
echo 'Shared node pool for dev and ftr'
nodeSelectorvalue = "${env.BU}-shared"
break
default:
log.error('Unable to fetch environment')
}
return nodeSelectorvalue
}