diff --git a/ci-scripts/Jenkinsfile-GitLab-Docker b/ci-scripts/Jenkinsfile-GitLab-Docker new file mode 100644 index 0000000000000000000000000000000000000000..d1212d7306befeba08e3d8727e6c6d5fae972cdb --- /dev/null +++ b/ci-scripts/Jenkinsfile-GitLab-Docker @@ -0,0 +1,270 @@ +#!/bin/groovy +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +//------------------------------------------------------------------------------- +// Abstraction function to send social media messages: +// like on Slack or Mattermost +def sendSocialMediaMessage(pipeChannel, pipeColor, pipeMessage) { + if (params.pipelineUsesSlack != null) { + if (params.pipelineUsesSlack) { + slackSend channel: pipeChannel, color: pipeColor, message: pipeMessage + } + } +} + +// Location of the CN executor node +def cn_ci_host = params.Host_CN_CI_Server + +// for lock +def cn_ci_resource = params.DockerContainers +def ds_tester_ci_resource = params.DsTester + +// Location of the 2nd CN executor +def new_host_flag = false +def new_host = "" +def new_host_user = "" + +// Location of the CN tester +def dsT_host_flag = false +def dsT_host = "" +def dsT_host_user = "" +def dsT_host_ip_addr = "" + +// Flags +def scmEvent = false +def upstreamEvent = false + +// Default tags / branches --> could be passed on by upstream job or by PR content +def amfTag = 'develop' +def amfBranch = 'develop' +def smfTag = 'develop' +def smfBranch = 'develop' +def spgwuTag = 'develop' +def spgwuBranch = 'develop' + +//------------------------------------------------------------------------------- +// Pipeline start +pipeline { + agent { + label cn_ci_host + } + options { + disableConcurrentBuilds() + timestamps() + ansiColor('xterm') + lock(cn_ci_resource) + } + stages { + stage ('Verify Parameters') { + steps { + script { + echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' + + JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"' + JOB_TIMESTAMP = JOB_TIMESTAMP.trim() + + if (params.Host_CN_CI_2nd_Server_Flag != null) { + new_host_flag = params.Host_CN_CI_2nd_Server_Flag + if (new_host_flag) { + new_host = params.Host_CN_CI_2nd_Server + new_host_user = params.Host_CN_CI_2nd_Server_Login + echo "1st Node is ${NODE_NAME}" + echo "2nd Node is ${new_host}" + } else { + echo "Node is ${NODE_NAME}" + } + } else { + echo "Node is ${NODE_NAME}" + } + if (params.DS_Tester_Server_Flag != null) { + dsT_host_flag = params.DS_Tester_Server_Flag + if (dsT_host_flag) { + def allParametersPresent = true + if (params.DS_Tester_Server_Name == null) { + allParametersPresent = false + } else { + dsT_host = params.DS_Tester_Server_Name + } + if (params.DS_Tester_Server_Login == null) { + allParametersPresent = false + } else { + dsT_host_user = params.DS_Tester_Server_Login + } + if (params.DS_Tester_Server_IP_Addr == null) { + allParametersPresent = false + } else { + dsT_host_ip_addr = params.DS_Tester_Server_IP_Addr + } + if (allParametersPresent) { + echo "DS Tester is on ${dsT_host}" + } else { + echo "Some DS Tester parameters are missing!" + sh "./ci-scripts/fail.sh" + } + } + } + + // Find out the cause of the trigger + for (cause in currentBuild.getBuildCauses()) { + if (cause.toString() ==~ /.*UpstreamCause.*/) { + upstreamEvent = true + } else { + scmEvent = true + } + } + + if (upstreamEvent) { + if (params.AMF_TAG != null) { + amfTag = params.AMF_TAG + echo "Upstream Job passed AMF_TAG to use: ${amfTag}" + } + if (params.AMF_BRANCH != null) { + amfBranch = params.AMF_BRANCH + echo "Upstream Job passed AMF_BRANCH to use: ${amfBranch}" + } + if (params.SMF_TAG != null) { + smfTag = params.SMF_TAG + echo "Upstream Job passed SMF_TAG to use: ${smfTag}" + } + if (params.SMF_BRANCH != null) { + smfBranch = params.SMF_BRANCH + echo "Upstream Job passed SMF_BRANCH to use: ${smfBranch}" + } + sh "git clean -x -d -f > /dev/null 2>&1" + sh "mkdir -p archives DS-TEST-RESULTS" + if (new_host_flag) { + // Prepare the workspace in remote server + myShCmd('git clean -x -d -f > /dev/null 2>&1', new_host_flag, new_host_user, new_host) + myShCmd('mkdir -p archives DS-TEST-RESULTS', new_host_flag, new_host_user, new_host) + } + } + } + } + } + stage ('Deploy Whole EPC') { + stages { + stage ('Create Public Network') { + steps { + script { + myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=CreateNetworks', new_host_flag, new_host_user, new_host) + } + } + } + stage ('Deploy Containers') { + steps { + script { + sh "sleep 10" + } + } + } + } + } + stage ('Check with DS Tester') { + when { expression {dsT_host_flag} } + steps { + lock (ds_tester_ci_resource) { + script { + sh "sleep 10" + } + } + } + } + stage ('Undeploy EPC') { + stages { + stage ('Undeploy Containers') { + steps { + script { + // Remove the containers + //myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=RemoveAllContainers', new_host_flag, new_host_user, new_host) + sh "sleep 10" + } + } + } + stage ('Delete Public Network') { + steps { + script { + myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=RemoveNetworks', new_host_flag, new_host_user, new_host) + } + } + } + } + } + } + post { + always { + script { + // Removing all containers + myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=RemoveAllContainers', new_host_flag, new_host_user, new_host) + // Removing the network + myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=RemoveNetworks', new_host_flag, new_host_user, new_host) + // Zipping all archived log files + sh "zip -r -qq fed_docker_logs.zip archives DS-TEST-RESULTS/*.tar DS-TEST-RESULTS/status.txt" + if (fileExists('fed_docker_logs.zip')) { + archiveArtifacts artifacts: 'fed_docker_logs.zip' + } + if (fileExists('test_results_oai_epc.html')) { + archiveArtifacts artifacts: 'test_results_oai_epc.html' + } + } + } + } +} + +// Functions + +def copyTo2ndServer(filename, flag, user, host) { + if (flag) { + sh "scp ${filename} ${user}@${host}:/tmp/CI-CN-FED" + } +} + +def copyFrom2ndServer(filename, target, flag, user, host) { + if (flag) { + sh "scp ${user}@${host}:/tmp/CI-CN-FED/${filename} ${target}" + } +} + +def myShCmd(cmd, flag, user, host) { + if (flag) { + sh "ssh -t -t ${user}@${host} 'cd /tmp/CI-CN-FED && ${cmd}'" + } else { + sh "${cmd}" + } +} + +def myShCmdWithLog(cmd, logFile, flag, user, host) { + if (flag) { + sh "ssh -t -t ${user}@${host} 'export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:.:/usr/local/devsol/bin && ${cmd}' > ${logFile} 2>&1" + } else { + sh "${cmd} > ${logFile} 2>&1" + } +} + +def myShRetCmd(cmd, flag, user, host) { + if (flag) { + ret = sh returnStdout: true, script: "ssh -t -t ${user}@${host} 'cd /tmp/CI-CN-FED && ${cmd}'" + } else { + ret = sh returnStdout: true, script: "${cmd}" + } + ret = ret.trim() + return ret +} diff --git a/ci-scripts/dsTestDeployTools.py b/ci-scripts/dsTestDeployTools.py new file mode 100644 index 0000000000000000000000000000000000000000..7159be656a277e25edcfea1d10b7466852ec1091 --- /dev/null +++ b/ci-scripts/dsTestDeployTools.py @@ -0,0 +1,110 @@ +#/* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- + +import os +import re +import sys +import subprocess +import time + +CICD_PRIVATE_NETWORK_RANGE='192.168.28.0/26' +CICD_PUBLIC_NETWORK_RANGE='192.168.61.192/26' + +class deployForDsTester(): + def __init__(self): + self.action = 'None' + self.tag = '' + + def createNetworks(self): + # first check if already up? + try: + res = subprocess.check_output('docker network ls | egrep -c "cicd-oai-public-net|cicd-oai-private-net"', shell=True, universal_newlines=True) + if int(str(res.strip())) > 0: + self.removeNetworks() + except: + pass + + subprocess_run_w_echo('docker network create --attachable --subnet ' + CICD_PUBLIC_NETWORK_RANGE + ' --ip-range ' + CICD_PUBLIC_NETWORK_RANGE + ' cicd-oai-public-net') + subprocess_run_w_echo('docker network create --attachable --subnet ' + CICD_PRIVATE_NETWORK_RANGE + ' --ip-range ' + CICD_PRIVATE_NETWORK_RANGE + ' cicd-oai-private-net') + + def removeNetworks(self): + try: + subprocess_run_w_echo('docker network rm cicd-oai-public-net cicd-oai-private-net') + except: + pass + +def subprocess_run_w_echo(cmd): + print(cmd) + subprocess.run(cmd, shell=True) + +def Usage(): + print('----------------------------------------------------------------------------------------------------------------------') + print('dsTestDeployTools.py') + print(' Deploy for DsTester in the pipeline.') + print('----------------------------------------------------------------------------------------------------------------------') + print('Usage: python3 dsTestDeployTools.py [options]') + print(' --help Show this help.') + print('---------------------------------------------------------------------------------------------- Mandatory Options -----') + print(' --action={CreateNetworks,RemoveNetworks,...}') + print('-------------------------------------------------------------------------------------------------------- Options -----') + print(' --tag=[Image Tag in registry]') + print('------------------------------------------------------------------------------------------------- Actions Syntax -----') + print('python3 dsTestDeployTools.py --action=CreateNetworks') + print('python3 dsTestDeployTools.py --action=RemoveNetworks') + +#-------------------------------------------------------------------------------------------------------- +# +# Start of main +# +#-------------------------------------------------------------------------------------------------------- + +DFDT = deployForDsTester() + +argvs = sys.argv +argc = len(argvs) + +while len(argvs) > 1: + myArgv = argvs.pop(1) + if re.match('^\-\-help$', myArgv, re.IGNORECASE): + Usage() + sys.exit(0) + elif re.match('^\-\-action=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-action=(.+)$', myArgv, re.IGNORECASE) + action = matchReg.group(1) + if action != 'CreateNetworks' and \ + action != 'RemoveNetworks': + print('Unsupported Action => ' + action) + Usage() + sys.exit(-1) + DFDT.action = action + elif re.match('^\-\-tag=(.+)$', myArgv, re.IGNORECASE): + matchReg = re.match('^\-\-tag=(.+)$', myArgv, re.IGNORECASE) + DFDT.tag = matchReg.group(1) + +if DFDT.action == 'CreateNetworks': + DFDT.createNetworks() +elif DFDT.action == 'RemoveNetworks': + DFDT.removeNetworks() + + +sys.exit(0) +