import java.text.SimpleDateFormat import groovy.transform.Field // import java.time.* // import hudson.model.Computer.ListPossibleNames @Field int NUMBER_OF_STANDS = 4 @Field String STAND_NAME_TEMPLATE = "nccbranch" pipeline { agent { node { label 'ncc-apps' customWorkspace '/opt/ncc/' } } parameters { choice( name: 'ACTION', choices: ['Deploy', 'Prolong', 'Stop'], description: 'Выбор действия' ) choice( name: 'STAND', choices: "${getStandsNames()}", description: 'Выбор стенда' ) string( name: 'VERSION', defaultValue: '7.5', description: 'Номер версии NCC' ) string( name: 'NOT_OFF', defaultValue: getParamNotOff(), description: 'Не выключать до указанного времени, например, "31/01 20-00"' ) booleanParam( name: 'clearDB', defaultValue: false, description: "Очистить базу данных" ) } options { timestamps() buildDiscarder(logRotator(numToKeepStr: '10')) skipDefaultCheckout() timeout(time: 40, unit: 'MINUTES') } environment { BUILD_USER = getBuildUser() CHAT_PORT = getPort("${STAND}") DIR_STAND = "/opt/ncc/${STAND}" CURRENT_DATE = new Date().format( 'dd.MM.yy_HHmm' ) COMPOSE_INTERACTIVE_NO_CLI = 1 COMPOSE_HTTP_TIMEOUT = 180 } triggers{ parameterizedCron(''' 02 3 * * * %STAND=nccbranch4;ACTION=Deploy;BUILD_USER=Jenkins ''') } stages { stage('Stop') { when { beforeAgent true environment name: 'ACTION', value: 'Stop' } steps { dir("${DIR_STAND}/ncc-compose/") { sh ''' docker version docker-compose --ansi never version docker-compose --ansi never ps && docker-compose --ansi never down --remove-orphans --volumes || exit 0 ''' } } } stage('PrepareDB') { when { beforeAgent true environment name: 'clearDB', value: 'false' not { environment name: 'VERSION', value: '' } environment name: 'ACTION', value: 'Deploy' } steps { dir("${DIR_STAND}/ncc-compose/") { sh ''' docker version docker-compose --ansi never version docker login -u user -p 123 sd-docker-registry2.naumen.ru docker login -u pavykeka -p pesogane33145713 ncc-75.nau.team rm -rf ./createdb/*.bak || true ''' } dir("${DIR_STAND}") { sh ''' echo "BUILD_ID=${BUILD_ID}" > build.properties echo "BUILD_USER=${BUILD_USER}" >> build.properties echo "VERSION=${VERSION}" >> build.properties echo "NOT_OFF=${NOT_OFF}" >> build.properties ''' } updateDesc() } } stage('Prepare') { when { beforeAgent true environment name: 'clearDB', value: 'true' not { environment name: 'VERSION', value: '' } environment name: 'ACTION', value: 'Deploy' } steps { dir("${DIR_STAND}/ncc-compose/") { sh ''' docker version docker-compose --ansi never version docker-compose --ansi never ps && docker-compose --ansi never down --remove-orphans --volumes || exit 0 docker login -u user -p 123 sd-docker-registry2.naumen.ru docker login -u pavykeka -p pesogane33145713 ncc-75.nau.team sudo chown -R administrator. ./ ''' } dir("${DIR_STAND}") { deleteDir() gitClone("master") sh ''' echo "BUILD_ID=${BUILD_ID}" > build.properties echo "BUILD_USER=${BUILD_USER}" >> build.properties echo "VERSION=${VERSION}" >> build.properties echo "NOT_OFF=${NOT_OFF}" >> build.properties mkdir ./ncc-compose/dbdata sudo chown -R 100 ./ncc-compose/consul-data sudo chown -R 777 ./ncc-compose/dbdata sudo chown -R 777 ./ncc-compose/spool sudo chown -R 777 ./ncc-compose/createdb ''' } updateDesc() } } stage('Deploy') { when { beforeAgent true not { environment name: 'VERSION', value: '' } environment name: 'ACTION', value: 'Deploy' } steps { script { currentBuild.description = "${STAND} <- $VERSION
Не выключать до $NOT_OFF" } dir("${DIR_STAND}/ncc-compose/") { writeFile file:".env_tmp", text:getEnvFile() sh ''' cat .env_tmp > .env docker-compose --ansi never config docker-compose --ansi never up --build -d sudo chown -R 777 spool ''' } dir("${DIR_STAND}/ncc-compose/") { sh 'docker-compose --ansi never ps || exit 0' } } } stage('Prolong') { when { beforeAgent true environment name: 'ACTION', value: 'Prolong' } steps { script { currentBuild.description = "${STAND} <- Prolong
Не выключать до $NOT_OFF" } dir("${DIR_STAND}") { sh 'sed -i -r "s|(NOT_OFF=).*|\\1${NOT_OFF}|" build.properties' } } } } post { always { updateDesc() emailext ( subject: "${currentBuild.currentResult}: Pipeline ${currentBuild.fullDisplayName}", body: "${currentBuild.currentResult} Pipeline: ${currentBuild.fullDisplayName}:\n${currentBuild.absoluteUrl}", recipientProviders: [[$class: 'RequesterRecipientProvider']] ) } } } // def node = jenkins.model.Jenkins.instance.getNode( "ncc-ci" ) // def node_ip = node.computer.getChannel().call(new ListPossibleNames()) // println "${node_ip}" def getParamNotOff() { return new Date().plus(1).format( 'dd/MM ' ) + "20-00" // LocalDateTime t = LocalDateTime.now(); // return t as String } def getBuildUser() { return currentBuild.rawBuild.getCause(Cause.UserIdCause)?.getUserId() } def getProjectDirectory() { return fileExists("${DIR_STAND}") ? "${DIR_STAND}" : "${DIR_STAND}" } def getPort(String stand) throws NumberFormatException { int initialPort = 10000 return initialPort + (stand - STAND_NAME_TEMPLATE).toInteger() } def getEnvFile() { String stand = "${STAND}" int initialDbPort = 54320 int initalNCCPort = 10100 int initalNCCFPort = 10110 int initialCONSULPort = 8000 int initialWSPort = 10800 int NCCPort = initalNCCPort + (stand - STAND_NAME_TEMPLATE).toInteger() int CONSULPort = initialCONSULPort + (stand - STAND_NAME_TEMPLATE).toInteger() int NCCFPort = initalNCCFPort + (stand - STAND_NAME_TEMPLATE).toInteger() int WSPort = initialWSPort + (stand - STAND_NAME_TEMPLATE).toInteger() int dbPort = initialDbPort + (stand - STAND_NAME_TEMPLATE).toInteger() return """ COMPOSE_PROJECT_NAME=${stand} COMPOSE_FILE=docker-compose.yaml chatOnSite=https://${stand}.nsd.naumen.ru/chatOnSite/ URL=https://${stand}.nsd.naumen.ru/workplace.html#/login CHAT_PORT=${CHAT_PORT} NCC_PORT=${NCCPort} NCCF_PORT=${NCCFPort} DB_PORT=${dbPort} CONSUL_PORT=${CONSULPort} WS_PORT=${WSPort} """ } def gitClone(String stand) { checkout poll: false, scm: [ $class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, userRemoteConfigs: [[url: 'git@gitsd.naumen.ru:ops/compose.git']] ] } def updateDesc() { def d = [BUILD_ID: '', BUILD_USER: '', VERSION: '', NOT_OFF: ''] def props = [] for (int i = 1; i <= NUMBER_OF_STANDS; i++) { prop = readProperties defaults: d, file: "/opt/ncc/nccbranch${i}/build.properties" props << prop } println props def item = Jenkins.instance.getItemByFullName("${JOB_NAME}") item.setDescription("${getDescTemplate(props)}") } def nowTime() { return new Date().format( 'yyyy-MM-dd HH:mm' ) } def getStandStatus(String notOff) { if (!(notOff =~ /^[0-9][0-9]?\/[0-9][0-9] [0-9][0-9]?[-:][0-9][0-9]/)) { standStatus = '' } else { yy = new Date().format( 'yyyy' ) fullDate = yy + ' ' + notOff till = new SimpleDateFormat("yyyy dd/MM HH-mm").parse(fullDate).getTime() now = new Date().getTime() standStatus = (till > now) ? 'stand_busy' : 'stand_free' } return standStatus } def getDescTemplate(List props) { return """ Задача обновляет один из стендов из ветки
Если сборка не прошла, то обращаться в ТПиВИ
${props.collect { prop -> def idx = props.findIndexOf { it.equals(prop) } return """ """ }.join('')}
Стенды:
Стенд Административный интерфейс admin/admin Чат на сайте Номер сборки Пользователь Нода Порт шины Файловое Хранилище Порт консула Не отключать
${idx+1} https://nccbranch${idx+1}.nsd.naumen.ru/workplace.html#/login https://nccbranch${idx+1}.nsd.naumen.ru/chatOnSite/ ${prop.BUILD_ID} ${prop.BUILD_USER} nccbranch${idx+1}.sd.naumen.ru 1010${idx+1} https://nccbranch${idx+1}.nsd.naumen.ru/fx 800${idx+1} ${prop.NOT_OFF}
Last updated: ${nowTime()}



При запуске необходимо выбрать стенд для обновления и указать параметры:
""" } def getStandsNames() { def standsNames = '' for (int i = 1; i <= NUMBER_OF_STANDS; i++) { standsNames += "nccbranch${i}" standsNames += "${i.equals(NUMBER_OF_STANDS) ? "" : "\n"}" } return standsNames }