406 lines
15 KiB
Groovy
406 lines
15 KiB
Groovy
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 <br> Не выключать до $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 <br> Не выключать до $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 """
|
||
<?xml version="1.0" encoding="UTF-8"?><html>
|
||
<body>
|
||
<b>Задача обновляет один из стендов из ветки</b>
|
||
<div style="font-wight:bold;">
|
||
Если сборка не прошла, то обращаться в ТПиВИ
|
||
</div>
|
||
<style>
|
||
.stand_table { margin:15px 0; /*border: 1px solid #cdcdcd;*/ border:none; border-collapse:collapse; border-spacing:0; font-size:100%; width: 90%;}
|
||
.stand_table th, .stand_table td { padding:3px 4px; border: 1px solid #cdcdcd; }
|
||
.stand_table th { text-align:center; font-weight:bold; border: 1px solid #cdcdcd; background:#f9efcf; }
|
||
.stand_table .last_update { text-align:right; font-size:75%; border:none; }
|
||
.stand_table .stand:hover { background:#f6faf2; }
|
||
.stand_table .col_title { width:120px; }
|
||
.stand_table .col_date { width:150px; }
|
||
.stand_table .col_link { width:120px; }
|
||
.stand_free { background:#B4EEA1; color:#349714; }
|
||
.stand_busy { background:#FF8282; color:#B21818; }
|
||
</style>
|
||
<table class="stand_table">
|
||
<tr>
|
||
<th colspan="8" style="text-align:left;">Стенды:</th>
|
||
</tr>
|
||
<tr>
|
||
<th abbr="stand">Стенд</th>
|
||
<th abbr="link">Административный интерфейс admin/admin</th>
|
||
<th abbr="chatOnSite">Чат на сайте</th>
|
||
<th abbr="buildnum">Номер сборки</th>
|
||
<th abbr="userid">Пользователь</th>
|
||
<th abbr="ip">Нода</th>
|
||
<th abbr="ncc_port">Порт шины</th>
|
||
<th abbr="fx_url">Файловое Хранилище</th>
|
||
<th abbr="consul_port">Порт консула</th>
|
||
<th abbr="notoff">Не отключать</th>
|
||
</tr>
|
||
${props.collect { prop ->
|
||
def idx = props.findIndexOf { it.equals(prop) }
|
||
return """ <tr class="stand">
|
||
<td abbr="stand">${idx+1}</td>
|
||
<td abbr="link">
|
||
<a href="https://nccbranch${idx+1}.nsd.naumen.ru/workplace.html#/login">https://nccbranch${idx+1}.nsd.naumen.ru/workplace.html#/login</a>
|
||
</td>
|
||
<td abbr="chatOnSite">
|
||
<a href="https://nccbranch${idx+1}.nsd.naumen.ru/chatOnSite/">https://nccbranch${idx+1}.nsd.naumen.ru/chatOnSite/</a>
|
||
</td>
|
||
<td abbr="buildnum">${prop.BUILD_ID}</td>
|
||
<td abbr="userid">${prop.BUILD_USER}</td>
|
||
<td abbr="ip">nccbranch${idx+1}.sd.naumen.ru</td>
|
||
<td abbr="ncc_port">1010${idx+1}</td>
|
||
<td abbr="fx_url">
|
||
<a href="https://nccbranch${idx+1}.nsd.naumen.ru/fx">https://nccbranch${idx+1}.nsd.naumen.ru/fx</a>
|
||
</td>
|
||
<td abbr="consul_port">800${idx+1}</td>
|
||
<td abbr="notoff" class="${getStandStatus(prop.NOT_OFF)}">${prop.NOT_OFF}</td>
|
||
</tr>"""
|
||
}.join('')}
|
||
<tr>
|
||
<td align="right" abbr="lastupd" COLSPAN="8" class="last_update">Last updated: ${nowTime()}</td>
|
||
</tr>
|
||
</table>
|
||
<br/>
|
||
<br/>
|
||
<br/>При запуске необходимо выбрать стенд для обновления и указать параметры:
|
||
<br/>
|
||
<ul>
|
||
<li>
|
||
<b>ACTION</b> - выполняемое действие (Deploy, Prolong, Stop)
|
||
<ul>
|
||
<li>
|
||
<b>Deploy</b> - развертывание стенда. Используемые параметры: VERSION, NOT_OFF, крыжик clearDB (пересоздаст с настройками по умолчанию)
|
||
</li>
|
||
<li>
|
||
<b>Prolong</b> - продление стенда. Используемые параметры: NOT_OFF
|
||
</li>
|
||
<li>
|
||
<b>Stop</b> - остановить стенд. По просьбе тестирования, для эмуляции сбоя. Последующий запускс стенда через Delpoy
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<b>STAND</b> - имя стенда
|
||
</li>
|
||
<li>
|
||
<b>VERSION</b> - версия системы, заложено на будущее, а настоящее время, интеграция тестировалась только на версии 7.5
|
||
</li>
|
||
<li>
|
||
<b>Не отключать</b> - указать время и дату, до которой нужен стенд (поле информативное, стенд не будет автоматически выключен)
|
||
</li>
|
||
<li>
|
||
<b>Нода</b> - данные указать в поле Адрес сервера при настройке интеграции со стороны NSD
|
||
</li>
|
||
<li>
|
||
<b>Порт шины</b> - данные для поля порт при настройке интеграции со стороны NSD
|
||
</li>
|
||
<li>
|
||
<b>Файловое хранилище</b> - Пишем в поле файлового хранилища при настроке интеграции со стороны NSD
|
||
</li>
|
||
<li>
|
||
<b>Логины к чату на сайте</b> - Логины в системе: <b>portal1...portal8</b> (под портальные бранчи), <b>test1...test4</b> (под ncc). Пароли для всех <b>123</b>. Менять, добавлять, логины к витринам: <b>http://nccbranch1.sd.naumen.ru:8001/</b>.
|
||
</li>
|
||
</ul>
|
||
|
||
</body>
|
||
</html>
|
||
"""
|
||
}
|
||
|
||
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
|
||
}
|