2025-01-09 16:05:16 +07:00
|
|
|
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'
|
2025-01-09 16:46:52 +07:00
|
|
|
CI_JOB_NAME_UAT = 'CI-UAT-FE-PORTAL' // tên của job build code môi trường uat
|
2025-01-09 16:23:50 +07:00
|
|
|
CI_JOB_NAME_PROD = 'CI-PROD-FE-PORTAL' // tên của job build code môi trường prod
|
2025-01-09 16:05:16 +07:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|