blob: 460ed88754a3828d1a6235dc2c0bd5e4332da5be [file] [log] [blame]
Dennis Dmitrievb3b37492018-07-08 21:23:00 +03001package com.mirantis.system_qa
2
Dennis Dmitriev27a96792018-07-30 07:52:03 +03003import groovy.xml.XmlUtil
Dennis Dmitrievb3b37492018-07-08 21:23:00 +03004
Dennis Dmitriev27a96792018-07-30 07:52:03 +03005def run_cmd(String cmd, Boolean returnStdout=false, Boolean exeption_with_logs=false) {
Dennis Dmitrievb3b37492018-07-08 21:23:00 +03006 def common = new com.mirantis.mk.Common()
7 common.printMsg("Run shell command:\n" + cmd, "blue")
8 def VENV_PATH='/home/jenkins/fuel-devops30'
Dennis Dmitriev27a96792018-07-30 07:52:03 +03009 def stdout_path = "/tmp/${JOB_NAME}_${BUILD_NUMBER}_stdout.log"
10 def stderr_path = "/tmp/${JOB_NAME}_${BUILD_NUMBER}_stderr.log"
Dennis Dmitrievb3b37492018-07-08 21:23:00 +030011 script = """\
12 set +x;
13 echo 'activate python virtualenv ${VENV_PATH}';
14 . ${VENV_PATH}/bin/activate;
Dennis Dmitriev27a96792018-07-30 07:52:03 +030015 bash -c 'set -ex; set -ex; ${cmd.stripIndent()}' 1>${stdout_path} 2>${stderr_path}
Dennis Dmitrievb3b37492018-07-08 21:23:00 +030016 """
Dennis Dmitriev27a96792018-07-30 07:52:03 +030017 def result
18 try {
19 result = sh(script: script)
20 if (returnStdout) {
21 def stdout = readFile("${stdout_path}")
22 return stdout
23 } else {
24 return result
25 }
26 } catch (e) {
27 if (exeption_with_logs) {
28 def stdout = readFile("${stdout_path}")
29 def stderr = readFile("${stderr_path}")
30 def error_message = e.message + "\n<<<<<< STDOUT: >>>>>>\n" + stdout + "\n<<<<<< STDERR: >>>>>>\n" + stderr
31 throw new Exception(error_message)
32 } else {
33 throw e
34 }
35 } finally {
36 sh(script: "rm ${stdout_path} ${stderr_path} || true")
37 }
Dennis Dmitrievb3b37492018-07-08 21:23:00 +030038}
39
40def run_cmd_stdout(cmd) {
Dennis Dmitriev27a96792018-07-30 07:52:03 +030041 return run_cmd(cmd, true, true)
Dennis Dmitrievb3b37492018-07-08 21:23:00 +030042}
43
Dennis Dmitriev27a96792018-07-30 07:52:03 +030044def build_pipeline_job(job_name, parameters) {
45 //Build a job, grab the results if failed and use the results in exception
46 def common = new com.mirantis.mk.Common()
47 common.printMsg("Start building job '${job_name}' with parameters:", "purple")
48 common.prettyPrint(parameters)
49
50 def job_info = build job: "${job_name}",
51 parameters: parameters,
52 propagate: false
53
54 if (job_info.getResult() != "SUCCESS") {
55 currentBuild.result = job_info.getResult()
56 def build_number = job_info.getNumber()
57 common.printMsg("Job '${job_name}' failed, getting details", "red")
58 def workflow_details=run_cmd_stdout("""\
59 export JOB_NAME=${job_name}
60 export BUILD_NUMBER=${build_number}
61 python ./tcp_tests/utils/get_jenkins_job_stages.py
62 """)
63 throw new Exception(workflow_details)
64 }
65}
66
67def build_shell_job(job_name, parameters, junit_report_filename=null, junit_report_source_dir='**/') {
68 //Build a job, grab the results if failed and use the results in exception
69 //junit_report_filename: if not null, try to copy this JUnit report first from remote job
70 def common = new com.mirantis.mk.Common()
71 common.printMsg("Start building job '${job_name}' with parameters:", "purple")
72 common.prettyPrint(parameters)
73
74 def job_info = build job: "${job_name}",
75 parameters: parameters,
76 propagate: false
77
78 if (job_info.getResult() != "SUCCESS") {
79 def build_status = job_info.getResult()
80 def build_number = job_info.getNumber()
81 def build_url = job_info.getAbsoluteUrl()
82 def job_url = "${build_url}"
83 currentBuild.result = build_status
84 if (junit_report_filename) {
85 common.printMsg("Job '${job_url}' failed with status ${build_status}, getting details", "red")
86 step($class: 'hudson.plugins.copyartifact.CopyArtifact',
87 projectName: job_name,
88 selector: specific("${build_number}"),
89 filter: "${junit_report_source_dir}/${junit_report_filename}",
90 target: '.',
91 flatten: true,
92 fingerprintArtifacts: true)
93
94 def String junit_report_xml = readFile("${junit_report_filename}")
95 def String junit_report_xml_pretty = new XmlUtil().serialize(junit_report_xml)
96 def String msg = "Job '${job_url}' failed with status ${build_status}, JUnit report:\n"
97 throw new Exception(msg + junit_report_xml_pretty)
98 } else {
99 throw new Exception("Job '${job_url}' failed with status ${build_status}, please check the console output.")
100 }
101 }
102}
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300103
104def prepare_working_dir() {
105 println "Clean the working directory ${env.WORKSPACE}"
106 deleteDir()
107
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300108 // do not fail if environment doesn't exists
109 println "Remove environment ${ENV_NAME}"
110 run_cmd("""\
111 dos.py erase ${ENV_NAME} || true
112 """)
113 println "Remove config drive ISO"
114 run_cmd("""\
115 rm /home/jenkins/images/${CFG01_CONFIG_IMAGE_NAME} || true
116 """)
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300117
118 run_cmd("""\
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300119 git clone https://github.com/Mirantis/tcp-qa.git ${env.WORKSPACE}
120 if [ -n "$TCP_QA_REFS" ]; then
121 set -e
122 git fetch https://review.gerrithub.io/Mirantis/tcp-qa $TCP_QA_REFS && git checkout FETCH_HEAD || exit \$?
123 fi
124 pip install --upgrade --upgrade-strategy=only-if-needed -r tcp_tests/requirements.txt
125 """, false, true)
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300126}
127
128def swarm_bootstrap_salt_cluster_devops() {
129 def common = new com.mirantis.mk.Common()
130 def parameters = [
131 string(name: 'PARENT_NODE_NAME', value: "${NODE_NAME}"),
132 string(name: 'PARENT_WORKSPACE', value: pwd()),
133 string(name: 'LAB_CONFIG_NAME', value: "${LAB_CONFIG_NAME}"),
134 string(name: 'ENV_NAME', value: "${ENV_NAME}"),
135 string(name: 'MCP_VERSION', value: "${MCP_VERSION}"),
136 string(name: 'MCP_IMAGE_PATH1604', value: "${MCP_IMAGE_PATH1604}"),
137 string(name: 'IMAGE_PATH_CFG01_DAY01', value: "${IMAGE_PATH_CFG01_DAY01}"),
138 string(name: 'CFG01_CONFIG_IMAGE_NAME', value: "${CFG01_CONFIG_IMAGE_NAME}"),
139 string(name: 'TCP_QA_REFS', value: "${TCP_QA_REFS}"),
140 string(name: 'PIPELINE_LIBRARY_REF', value: "${PIPELINE_LIBRARY_REF}"),
141 string(name: 'MK_PIPELINES_REF', value: "${MK_PIPELINES_REF}"),
142 string(name: 'COOKIECUTTER_TEMPLATE_COMMIT', value: "${COOKIECUTTER_TEMPLATE_COMMIT}"),
143 string(name: 'SALT_MODELS_SYSTEM_COMMIT', value: "${SALT_MODELS_SYSTEM_COMMIT}"),
144 booleanParam(name: 'SHUTDOWN_ENV_ON_TEARDOWN', value: false),
145 ]
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300146
147 build_pipeline_job('swarm-bootstrap-salt-cluster-devops', parameters)
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300148}
149
150def swarm_deploy_cicd(String stack_to_install='core,cicd') {
151 // Run openstack_deploy job on cfg01 Jenkins for specified stacks
152 def common = new com.mirantis.mk.Common()
153 def parameters = [
154 string(name: 'PARENT_NODE_NAME', value: "${NODE_NAME}"),
155 string(name: 'PARENT_WORKSPACE', value: pwd()),
156 string(name: 'ENV_NAME', value: "${ENV_NAME}"),
157 string(name: 'STACK_INSTALL', value: stack_to_install),
158 string(name: 'TCP_QA_REFS', value: "${TCP_QA_REFS}"),
159 booleanParam(name: 'SHUTDOWN_ENV_ON_TEARDOWN', value: false),
160 ]
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300161 build_pipeline_job('swarm-deploy-cicd', parameters)
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300162}
163
164def swarm_deploy_platform(String stack_to_install) {
165 // Run openstack_deploy job on CICD Jenkins for specified stacks
166 def common = new com.mirantis.mk.Common()
167 def parameters = [
168 string(name: 'PARENT_NODE_NAME', value: "${NODE_NAME}"),
169 string(name: 'PARENT_WORKSPACE', value: pwd()),
170 string(name: 'ENV_NAME', value: "${ENV_NAME}"),
171 string(name: 'STACK_INSTALL', value: stack_to_install),
172 string(name: 'TCP_QA_REFS', value: "${TCP_QA_REFS}"),
173 booleanParam(name: 'SHUTDOWN_ENV_ON_TEARDOWN', value: false),
174 ]
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300175 build_pipeline_job('swarm-deploy-platform', parameters)
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300176}
177
Dennis Dmitrievfde667f2018-07-23 16:26:50 +0300178def swarm_run_pytest(String passed_steps) {
179 // Run pytest tests
180 def common = new com.mirantis.mk.Common()
181 def parameters = [
182 string(name: 'ENV_NAME', value: "${ENV_NAME}"),
183 string(name: 'PASSED_STEPS', value: passed_steps),
184 string(name: 'RUN_TEST_OPTS', value: "${RUN_TEST_OPTS}"),
185 string(name: 'PARENT_NODE_NAME', value: "${NODE_NAME}"),
186 string(name: 'PARENT_WORKSPACE', value: pwd()),
187 string(name: 'TCP_QA_REFS', value: "${TCP_QA_REFS}"),
188 booleanParam(name: 'SHUTDOWN_ENV_ON_TEARDOWN', value: false),
189 string(name: 'LAB_CONFIG_NAME', value: "${LAB_CONFIG_NAME}"),
190 string(name: 'REPOSITORY_SUITE', value: "${MCP_VERSION}"),
191 string(name: 'MCP_IMAGE_PATH1604', value: "${MCP_IMAGE_PATH1604}"),
192 string(name: 'IMAGE_PATH_CFG01_DAY01', value: "${IMAGE_PATH_CFG01_DAY01}"),
193 ]
194 common.printMsg("Start building job 'swarm-run-pytest' with parameters:", "purple")
195 common.prettyPrint(parameters)
196 build job: 'swarm-run-pytest',
197 parameters: parameters
198}
199
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300200def generate_cookied_model() {
201 def common = new com.mirantis.mk.Common()
202 // do not fail if environment doesn't exists
203 def IPV4_NET_ADMIN=run_cmd_stdout("dos.py net-list ${ENV_NAME} | grep admin-pool01").trim().split().last()
204 def IPV4_NET_CONTROL=run_cmd_stdout("dos.py net-list ${ENV_NAME} | grep private-pool01").trim().split().last()
205 def IPV4_NET_TENANT=run_cmd_stdout("dos.py net-list ${ENV_NAME} | grep tenant-pool01").trim().split().last()
206 def IPV4_NET_EXTERNAL=run_cmd_stdout("dos.py net-list ${ENV_NAME} | grep external-pool01").trim().split().last()
207 println("IPV4_NET_ADMIN=" + IPV4_NET_ADMIN)
208 println("IPV4_NET_CONTROL=" + IPV4_NET_CONTROL)
209 println("IPV4_NET_TENANT=" + IPV4_NET_TENANT)
210 println("IPV4_NET_EXTERNAL=" + IPV4_NET_EXTERNAL)
211
212 def cookiecuttertemplate_commit = env.COOKIECUTTER_TEMPLATE_COMMIT ?: env.MCP_VERSION
213 def saltmodels_system_commit = env.SALT_MODELS_SYSTEM_COMMIT ?: env.MCP_VERSION
214
215 def parameters = [
216 string(name: 'LAB_CONTEXT_NAME', value: "${LAB_CONFIG_NAME}"),
217 string(name: 'CLUSTER_NAME', value: "${LAB_CONFIG_NAME}"),
218 string(name: 'DOMAIN_NAME', value: "${LAB_CONFIG_NAME}.local"),
219 string(name: 'REPOSITORY_SUITE', value: "${env.MCP_VERSION}"),
220 string(name: 'SALT_MODELS_SYSTEM_COMMIT', value: "${saltmodels_system_commit}"),
221 string(name: 'COOKIECUTTER_TEMPLATE_COMMIT', value: "${cookiecuttertemplate_commit}"),
222 string(name: 'TCP_QA_REVIEW', value: "${TCP_QA_REFS}"),
223 string(name: 'IPV4_NET_ADMIN', value: IPV4_NET_ADMIN),
224 string(name: 'IPV4_NET_CONTROL', value: IPV4_NET_CONTROL),
225 string(name: 'IPV4_NET_TENANT', value: IPV4_NET_TENANT),
226 string(name: 'IPV4_NET_EXTERNAL', value: IPV4_NET_EXTERNAL),
227 ]
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300228
229 build_shell_job('swarm-cookied-model-generator', parameters, "deploy_generate_model.xml")
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300230}
231
232def generate_configdrive_iso() {
233 def common = new com.mirantis.mk.Common()
234 def SALT_MASTER_IP=run_cmd_stdout("""\
235 export ENV_NAME=${ENV_NAME}
236 . ./tcp_tests/utils/env_salt
237 echo \$SALT_MASTER_IP
238 """).trim().split().last()
239 println("SALT_MASTER_IP=" + SALT_MASTER_IP)
240 def parameters = [
241 string(name: 'CLUSTER_NAME', value: "${LAB_CONFIG_NAME}"),
242 string(name: 'MODEL_URL', value: "http://cz8133.bud.mirantis.net:8098/${LAB_CONFIG_NAME}.git"),
243 string(name: 'MODEL_URL_OBJECT_TYPE', value: "git"),
244 booleanParam(name: 'DOWNLOAD_CONFIG_DRIVE', value: true),
245 string(name: 'MCP_VERSION', value: "${MCP_VERSION}"),
246 string(name: 'COMMON_SCRIPTS_COMMIT', value: "${MCP_VERSION}"),
247 string(name: 'NODE_NAME', value: "${NODE_NAME}"),
248 string(name: 'CONFIG_DRIVE_ISO_NAME', value: "${CFG01_CONFIG_IMAGE_NAME}"),
249 string(name: 'SALT_MASTER_DEPLOY_IP', value: SALT_MASTER_IP),
250 string(name: 'PIPELINE_REPO_URL', value: "https://github.com/Mirantis"),
251 booleanParam(name: 'PIPELINES_FROM_ISO', value: true),
252 string(name: 'MCP_SALT_REPO_URL', value: "http://apt.mirantis.com/xenial"),
253 string(name: 'MCP_SALT_REPO_KEY', value: "http://apt.mirantis.com/public.gpg"),
254 string(name: 'PIPELINE_LIBRARY_REF', value: "${PIPELINE_LIBRARY_REF}"),
255 string(name: 'MK_PIPELINES_REF', value: "${MK_PIPELINES_REF}"),
256 ]
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300257 build_pipeline_job('create-cfg-config-drive', parameters)
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300258}
259
260def run_job_on_day01_node(stack_to_install, timeout=1800) {
261 // stack_to_install="core,cicd"
262 def stack = "${stack_to_install}"
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300263 try {
264 run_cmd("""\
265 export ENV_NAME=${ENV_NAME}
266 . ./tcp_tests/utils/env_salt
267 . ./tcp_tests/utils/env_jenkins_day01
268 export JENKINS_BUILD_TIMEOUT=${timeout}
269 JOB_PARAMETERS=\"{
270 \\\"SALT_MASTER_URL\\\": \\\"\${SALTAPI_URL}\\\",
271 \\\"STACK_INSTALL\\\": \\\"${stack}\\\"
272 }\"
273 JOB_PREFIX="[ ${ENV_NAME}/{build_number}:${stack} {time} ] "
274 python ./tcp_tests/utils/run_jenkins_job.py --verbose --job-name=deploy_openstack --job-parameters="\$JOB_PARAMETERS" --job-output-prefix="\$JOB_PREFIX"
275 """)
276 } catch (e) {
277 common.printMsg("Product job 'deploy_openstack' failed, getting details", "red")
278 def workflow_details=run_cmd_stdout("""\
279 . ./tcp_tests/utils/env_salt
280 . ./tcp_tests/utils/env_jenkins_day01
281 export JOB_NAME=deploy_openstack
282 export BUILD_NUMBER=lastBuild
283 python ./tcp_tests/utils/get_jenkins_job_stages.py
284 """)
285 throw new Exception(workflow_details)
286 }
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300287}
288
289def run_job_on_cicd_nodes(stack_to_install, timeout=1800) {
290 // stack_to_install="k8s,calico,stacklight"
291 def stack = "${stack_to_install}"
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300292 try {
293 run_cmd("""\
294 export ENV_NAME=${ENV_NAME}
295 . ./tcp_tests/utils/env_salt
296 . ./tcp_tests/utils/env_jenkins_cicd
297 export JENKINS_BUILD_TIMEOUT=${timeout}
298 JOB_PARAMETERS=\"{
299 \\\"SALT_MASTER_URL\\\": \\\"\${SALTAPI_URL}\\\",
300 \\\"STACK_INSTALL\\\": \\\"${stack}\\\"
301 }\"
302 JOB_PREFIX="[ ${ENV_NAME}/{build_number}:${stack} {time} ] "
303 python ./tcp_tests/utils/run_jenkins_job.py --verbose --job-name=deploy_openstack --job-parameters="\$JOB_PARAMETERS" --job-output-prefix="\$JOB_PREFIX"
304 sleep 60 # Wait for IO calm down on cluster nodes
305 """)
306 } catch (e) {
307 common.printMsg("Product job 'deploy_openstack' failed, getting details", "red")
308 def workflow_details=run_cmd_stdout("""\
309 . ./tcp_tests/utils/env_salt
310 . ./tcp_tests/utils/env_jenkins_cicd
311 export JOB_NAME=deploy_openstack
312 export BUILD_NUMBER=lastBuild
313 python ./tcp_tests/utils/get_jenkins_job_stages.py
314 """)
315 throw new Exception(workflow_details)
316 }
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300317}
318
319def sanity_check_component(stack) {
320 // Run sanity check for the component ${stack}.
321 // Result will be stored in JUnit XML file deploy_${stack}.xml
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300322 try {
323 run_cmd("""\
324 py.test --junit-xml=deploy_${stack}.xml -m check_${stack}
325 """)
326 } catch (e) {
327 def String junit_report_xml = readFile("deploy_${stack}.xml")
328 def String junit_report_xml_pretty = new XmlUtil().serialize(junit_report_xml)
329 def String msg = "Sanity check for '${stack}' failed, JUnit report:\n"
330 throw new Exception(msg + junit_report_xml_pretty)
331 }
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300332}
333
334def devops_snapshot(stack) {
335 // Make the snapshot with name "${stack}_deployed"
336 // for all VMs in the environment.
337 // If oslo_config INI file ${ENV_NAME}_salt_deployed.ini exists,
338 // then make a copy for the created snapshot to allow the system
339 // tests to revert this snapshot along with the metadata from the INI file.
340 run_cmd("""\
341 dos.py suspend ${ENV_NAME}
342 dos.py snapshot ${ENV_NAME} ${stack}_deployed
343 dos.py resume ${ENV_NAME}
Dennis Dmitrievfde667f2018-07-23 16:26:50 +0300344 dos.py time-sync ${ENV_NAME} || dos.py time-sync ${ENV_NAME} # sometimes, timesync may fail. Need to update it in fuel-devops.
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300345 if [ -f \$(pwd)/${ENV_NAME}_salt_deployed.ini ]; then
346 cp \$(pwd)/${ENV_NAME}_salt_deployed.ini \$(pwd)/${ENV_NAME}_${stack}_deployed.ini
347 fi
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300348 """, exeption_with_logs: true)
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300349}
350
Dennis Dmitrievfde667f2018-07-23 16:26:50 +0300351def get_steps_list(steps) {
352 // Make a list from comma separated string
353 return steps.split(',').collect { it.split(':')[0] }
354}
355
Dennis Dmitrievb3b37492018-07-08 21:23:00 +0300356def report_deploy_result(deploy_expected_stacks) {
357}
358
359def report_test_result() {
Dennis Dmitriev27a96792018-07-30 07:52:03 +0300360}