diff --git a/fe/fe-portal/cd-portal-frontend.Jenkinsfile b/fe/fe-portal/cd-portal-frontend.Jenkinsfile index e69de29..a25c7c0 100644 --- a/fe/fe-portal/cd-portal-frontend.Jenkinsfile +++ b/fe/fe-portal/cd-portal-frontend.Jenkinsfile @@ -0,0 +1,240 @@ +pipeline { + agent any + parameters { + choice(name: 'ENV', choices: ['prod', 'uat'], description: 'Choose Environment') + string(name: 'CI_JOB_BUILD_NUMBER', defaultValue: '', description: 'Build number of CI Job') + } + environment { + PROJECT_NAME = 'portal' + CI_JOB_NAME_UAT = 'CI-UAT-PORTAL' // tên của job build code môi trường uat + CI_JOB_NAME_PROD = 'CI-PORTAL-PORTA' // tên của job build code môi trường prod + + CI_JOB_METADATA_FILENAME = "${params.ENV}_${PROJECT_NAME}_metadata.json" // tên file metadata đã được lưu từ job build code + + GIT_PAT_CREDENTIALS_ID = 'b03f36c4-bba3-4764-94ca-b620651b2a68' // Id của Personal Access Token lưu trên jenkins + GIT_ANSIBLE_URL = 'work.gct.com.vn/thienvv/nsg_ansible.git' + GIT_ANSIBLE_BRANCH = 'v2' + + NEXUS_CREDENTIALS = credentials('Nexus_credential') + ANSIBLE_SSH_CONNECTION = 'root@103.166.183.172 -p 24700' + + ANSIBLE_FOLDER_PATH = '/srv/ansible_v2' + ANSIBLE_INVENTORY_PATH = "inventory/${params.ENV}.ini" + ANSIBLE_PLAYBOOK_PATH = 'playbooks/deploy_fe.yml' + + TELEGRAM_CHAT_ID = -4678013464 + TELEGRAM_BOT_TOKEN = credentials('TELEGRAM_BOT_TOKEN') + } + + stages { + stage('Retrieve Artifact Metadata From CI Job') { + steps { + script { + switch (params.ENV) { + case 'uat': + env.CI_JOB_NAME = env.CI_JOB_NAME_UAT + break + case 'prod': + env.CI_JOB_NAME = env.CI_JOB_NAME_PROD + break + default: + error "Unsupported environment: ${params.ENV}" + } + + def ciJobBuildNumber = params.CI_JOB_BUILD_NUMBER + echo "Retrieving artifact from CI_JOB_BUILD_NUMBER: ${ciJobBuildNumber}" + + def metadata = retrieveArtifactMetadataFromCIJOB( + env.CI_JOB_NAME, + ciJobBuildNumber, + env.CI_JOB_METADATA_FILENAME) + + env.NEXUS_URL = metadata.nexusUrl + echo "env.NEXUS_URL : ${env.NEXUS_URL}" + + env.NEXUS_ARTIFACT_NAME = metadata.nexusArtifactName + echo "env.NEXUS_ARTIFACT_NAME : ${env.NEXUS_ARTIFACT_NAME}" + } + } + } + + stage('Checkout Ansible Code Git ') { + steps { + script { + checkoutFromGit( + env.ANSIBLE_SSH_CONNECTION, + env.GIT_ANSIBLE_URL, + env.GIT_PAT_CREDENTIALS_ID, + env.GIT_ANSIBLE_BRANCH, + env.ANSIBLE_FOLDER_PATH + ) + } + } + } + + stage('Deploy with Ansible') { + steps { + triggerAnsible( + env.ANSIBLE_SSH_CONNECTION, + env.ANSIBLE_FOLDER_PATH, + env.ANSIBLE_INVENTORY_PATH, + env.ANSIBLE_PLAYBOOK_PATH, + params.ENV, + env.PROJECT_NAME, + env.NEXUS_URL, + env.NEXUS_ARTIFACT_NAME, + env.NEXUS_CREDENTIALS_USR, + env.NEXUS_CREDENTIALS_PSW) + } + } + } + + post { + always { + echo 'Pipeline execution finished.' + } + success { + script { + def message = "Deploy thành công : FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}" + sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\"" + } + } + failure { + script { + def message = "Deploy thất bại: FRONTEND - Môi trường ${params.ENV} - Dự án ${env.PROJECT_NAME}, ${currentBuild.fullDisplayName}\n${env.BUILD_URL}" + sh "curl -s -X POST https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage -d chat_id=${env.TELEGRAM_CHAT_ID} -d text=\"${message}\"" + } + } + } +} + +//Thienvv- hàm checkout git code ansible về máy ansible +def checkoutFromGit( + String ansibleSSHConnection, + String gitUrl, + String gitAnsibleCredentialsId, + String branch, + String ansibleFolderPath) { + try { + // kiểm tra đã tồn tại code ansible trên thư mục của máy ansible + Boolean repoExists = sh( + script: """ + ssh -v ${ansibleSSHConnection} \\ + ' [ -d ${ansibleFolderPath}/.git ] && echo '1' || echo '0' ' + """, + returnStdout: true + ).trim() == '1' + + withCredentials([usernamePassword( + credentialsId: gitAnsibleCredentialsId, + usernameVariable: 'GIT_USERNAME', + passwordVariable: 'GIT_PAT')]) { + if (repoExists) { // nếu tồn tại source code ansible rồi thì pull về + echo "Repository already exists on ${ansibleFolderPath}. Pulling latest changes..." + + Integer result = sh(script: """ + ssh -v ${ansibleSSHConnection} \\ + 'cd ${ansibleFolderPath} && \\ + git reset --hard && \\ + git clean -fd && \\ + git fetch origin && \\ + git checkout ${branch} && \\ + git pull origin ${branch} -vvvv ' + """, returnStatus: true) + + if (result == 0) { + echo 'Pull ansible code successfully' + } else { + error "Pull ansible code failed, status: ${result}" + } + } else { //nếu chưa tồn tại code ansible + Integer result = sh(script: """ + ssh -v ${ansibleSSHConnection} \\ + 'git clone --branch ${branch} http://${GIT_USERNAME}@${gitUrl} ${ansibleFolderPath} -vvvv ' + """, returnStatus: true) + + if (result == 0) { + echo 'Clone ansible code successfully' + } else { + error "Clone ansible code failed, status: ${result}" + } + } + } + } catch (Exception e) { + echo "[ERROR] Unexpected error: ${e.message}" + throw e + } + } + +//Hàm lấy artifact metadata file từ CI job +def retrieveArtifactMetadataFromCIJOB(String ciJobName, String ciJobBuildNumber, String metadataFilename) { + try { + def selector = null + + if (ciJobBuildNumber != '') { // nếu ciJobBuildNumber khác rỗng thì + selector = [$class: 'SpecificBuildSelector', buildNumber: ciJobBuildNumber] // selector = ciJobBuildNumber + } else { //còn nếu ciJobBuildNumber = rỗng thì + selector = lastSuccessful() //selector = build thành công gần nhất + } + // Sao chép artifact từ dự án khác + copyArtifacts projectName: ciJobName, + selector: selector, + filter: metadataFilename, + target: '.' + + // Kiểm tra sự tồn tại của file metadata + if (!fileExists(metadataFilename)) { + error "File ${metadataFilename} not found after copyArtifacts!" + } else { + echo "File ${metadataFilename} successfully copied." + } + + // Đọc dữ liệu từ file JSON + def metadata = readJSON file: metadataFilename + + return metadata + } catch (Exception e) { + echo "[ERROR] Unexpected error: ${e.message}" + throw e + } +} + +def triggerAnsible( + String sshAnsibleConnection, + String ansibleansibleFolderPath, + String inventoryPath, + String playbookPath, + String deployENV, + String projectName, + String nexusUrl, + String nexusArtifactName, + String nexusUsername, + String nexusPassword) { + + try { + Integer result = sh( + script: """ + ssh ${sshAnsibleConnection} " + cd ${ansibleansibleFolderPath} && + ansible-playbook -i ${inventoryPath} ${playbookPath} \\ + -e 'deploy_env=${deployENV} \\ + project_name=${projectName} \\ + nexus_url=${nexusUrl} \\ + artifact_name=${nexusArtifactName} \\ + nexus_username=${nexusUsername} \\ + nexus_password=${nexusPassword}' -vvvv + " + """, + returnStatus: true + ) + + if (result == 0) { + echo 'triggerAnsible successfully' + } else { + error "triggerAnsible failed, status: ${result}" + } + } catch (Exception e) { + echo "[ERROR] Unexpected error: ${e.message}" + throw e + } + }