blob: b1755b267d9978e4f4e80626faa17c65eb1074b0 [file] [log] [blame]
Petr Lomakin47fee0a2017-08-01 10:46:05 -07001package com.mirantis.mcp
2
3/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -05004 * DEPRECATED
Petr Lomakin47fee0a2017-08-01 10:46:05 -07005 * Tests providing functions
6 *
7 */
8
9/**
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -060010 * Run docker container with basic (keystone) parameters
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050011 * For backward compatibility. Deprecated.
12 * Will be removed soon.
Petr Lomakin47fee0a2017-08-01 10:46:05 -070013 *
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -060014 * @param target Host to run container
15 * @param dockerImageLink Docker image link. May be custom or default rally image
Petr Lomakin47fee0a2017-08-01 10:46:05 -070016 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050017def runBasicContainer(master, target, dockerImageLink="xrally/xrally-openstack:0.10.1"){
Petr Lomakin47fee0a2017-08-01 10:46:05 -070018 def salt = new com.mirantis.mk.Salt()
19 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -050020 common.errorMsg('You are using deprecated method! Please migrate to validate.runContainer. This method will be removed')
21 error('You are using deprecated method! Please migrate to validate.runContainer. This method will be removed')
Sam Stoelinga28bdb722017-09-25 18:29:59 -070022 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
23 def keystone = _pillar['return'][0].values()[0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -060024 if ( salt.cmdRun(master, target, "docker ps -f name=cvp -q", false, null, false)['return'][0].values()[0] ) {
25 salt.cmdRun(master, target, "docker rm -f cvp")
26 }
27 salt.cmdRun(master, target, "docker run -tid --net=host --name=cvp " +
28 "-u root -e OS_USERNAME=${keystone.admin_name} " +
Petr Lomakin47fee0a2017-08-01 10:46:05 -070029 "-e OS_PASSWORD=${keystone.admin_password} -e OS_TENANT_NAME=${keystone.admin_tenant} " +
30 "-e OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0 " +
Oleksii Zhurba1bf9be12018-01-17 15:20:00 -060031 "-e OS_REGION_NAME=${keystone.region} -e OS_ENDPOINT_TYPE=admin --entrypoint /bin/bash ${dockerImageLink}")
Petr Lomakin47fee0a2017-08-01 10:46:05 -070032}
33
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050034
35/**
36 * Run docker container with parameters
37 *
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050038 * @param target Host to run container
39 * @param dockerImageLink Docker image link. May be custom or default rally image
40 * @param name Name for container
41 * @param env_var Environment variables to set in container
42 * @param entrypoint Set entrypoint to /bin/bash or leave default
43 * @param mounts Map with mounts for container
Sergey Galkin7137ad02019-11-07 14:52:13 +040044 * @param output_replacing Maps with regex with should be hide from output (passwords, etc)
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050045**/
46
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050047def runContainer(Map params){
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050048 def common = new com.mirantis.mk.Common()
Sergey Galkin7137ad02019-11-07 14:52:13 +040049 defaults = ["name": "cvp", "env_var": [], "entrypoint": true, "mounts": [:], "output_replacing": []]
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050050 params = defaults + params
51 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050052 def variables = ''
53 def entry_point = ''
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050054 def tempest_conf_mount = ''
55 def mounts = ''
56 def cluster_name = salt.getPillar(params.master, 'I@salt:master', '_param:cluster_name')['return'][0].values()[0]
57 default_mounts = ["/etc/ssl/certs/": "/etc/ssl/certs/",
58 "/srv/salt/pki/${cluster_name}/": "/etc/certs",
59 "/root/test/": "/root/tempest/",
60 "/tmp/": "/tmp/",
61 "/etc/hosts": "/etc/hosts"]
62 params.mounts = default_mounts + params.mounts
63 if ( salt.cmdRun(params.master, params.target, "docker ps -f name=${params.name} -q", false, null, false)['return'][0].values()[0] ) {
64 salt.cmdRun(params.master, params.target, "docker rm -f ${params.name}")
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050065 }
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050066 if (params.env_var.size() > 0) {
67 variables = ' -e ' + params.env_var.join(' -e ')
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050068 }
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050069 if (params.entrypoint) {
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050070 entry_point = '--entrypoint /bin/bash'
71 }
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050072 params.mounts.each { local, container ->
73 mounts = mounts + " -v ${local}:${container}"
74 }
Sergey Galkin7137ad02019-11-07 14:52:13 +040075 salt.cmdRun(params.master, params.target,
76 "docker run -tid --net=host --name=${params.name}" +
77 "${mounts} -u root ${entry_point} ${variables} ${params.dockerImageLink}",
78 true, null, true, [],
79 params.output_replacing)
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050080}
81
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050082def runContainer(master, target, dockerImageLink, name='cvp', env_var=[], entrypoint=true, mounts=[:]){
83 def common = new com.mirantis.mk.Common()
84 common.infoMsg("This method will be deprecated. Convert you method call to use Map as input parameter")
85 // Convert to Map
86 params = ['master': master, 'target': target, 'dockerImageLink': dockerImageLink, 'name': name, 'env_var': env_var,
87 'entrypoint': entrypoint, 'mounts': mounts]
88 // Call new method with Map as parameter
89 return runContainer(params)
90}
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050091
Petr Lomakin47fee0a2017-08-01 10:46:05 -070092/**
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -050093 * Get v2 Keystone credentials from pillars
94 *
95 */
96def _get_keystone_creds_v2(master){
97 def salt = new com.mirantis.mk.Salt()
98 def common = new com.mirantis.mk.Common()
99 def keystone = []
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500100 _pillar = false
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500101 common.infoMsg("Fetching Keystone v2 credentials")
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500102 _response = salt.runSaltProcessStep(master, 'I@keystone:server', 'pillar.get', 'keystone:server', null, false, 1)['return'][0]
103 for (i = 0; i < _response.keySet().size(); i++) {
104 if ( _response.values()[i] ) {
105 _pillar = _response.values()[i]
106 }
107 }
108 if (_pillar) {
109 keystone.add("OS_USERNAME=${_pillar.admin_name}")
110 keystone.add("OS_PASSWORD=${_pillar.admin_password}")
111 keystone.add("OS_TENANT_NAME=${_pillar.admin_tenant}")
112 keystone.add("OS_AUTH_URL=http://${_pillar.bind.private_address}:${_pillar.bind.private_port}/v2.0")
113 keystone.add("OS_REGION_NAME=${_pillar.region}")
114 keystone.add("OS_ENDPOINT_TYPE=admin")
115 return keystone
116 }
117 else {
118 throw new Exception("Cannot fetch Keystone v2 credentials. Response: ${_response}")
119 }
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500120}
121
122/**
123 * Get v3 Keystone credentials from pillars
124 *
125 */
126def _get_keystone_creds_v3(master){
127 def salt = new com.mirantis.mk.Salt()
128 def common = new com.mirantis.mk.Common()
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500129 _pillar = false
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500130 pillar_name = 'keystone:client:os_client_config:cfgs:root:content:clouds:admin_identity'
131 common.infoMsg("Fetching Keystone v3 credentials")
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500132 _response = salt.runSaltProcessStep(master, 'I@keystone:server', 'pillar.get', pillar_name, null, false, 1)['return'][0]
133 for (i = 0; i < _response.keySet().size(); i++) {
134 if ( _response.values()[i] ) {
135 _pillar = _response.values()[i]
136 }
137 }
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500138 def keystone = []
139 if (_pillar) {
140 keystone.add("OS_USERNAME=${_pillar.auth.username}")
141 keystone.add("OS_PASSWORD=${_pillar.auth.password}")
142 keystone.add("OS_TENANT_NAME=${_pillar.auth.project_name}")
143 keystone.add("OS_PROJECT_NAME=${_pillar.auth.project_name}")
144 keystone.add("OS_AUTH_URL=${_pillar.auth.auth_url}/v3")
145 keystone.add("OS_REGION_NAME=${_pillar.region_name}")
146 keystone.add("OS_IDENTITY_API_VERSION=${_pillar.identity_api_version}")
Oleksii Zhurbafa885ed2019-02-13 18:27:31 -0600147 keystone.add("OS_ENDPOINT_TYPE=internal")
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500148 keystone.add("OS_PROJECT_DOMAIN_NAME=${_pillar.auth.project_domain_name}")
149 keystone.add("OS_USER_DOMAIN_NAME=${_pillar.auth.user_domain_name}")
Oleksii Zhurbafa885ed2019-02-13 18:27:31 -0600150 // we mount /srv/salt/pki/${cluster_name}/:/etc/certs with certs for cvp container
151 keystone.add("OS_CACERT='/etc/certs/proxy-with-chain.crt'")
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500152 return keystone
153 }
154 else {
155 common.warningMsg("Failed to fetch Keystone v3 credentials")
156 return false
157 }
158}
159
160/**
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700161 * Get file content (encoded). The content encoded by Base64.
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700162 *
163 * @param target Compound target (should target only one host)
164 * @param file File path to read
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700165 * @return The encoded content of the file
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700166 */
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700167def getFileContentEncoded(master, target, file) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700168 def salt = new com.mirantis.mk.Salt()
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700169 def file_content = ''
170 def cmd = "base64 -w0 ${file} > ${file}_encoded; " +
171 "split -b 1MB -d ${file}_encoded ${file}__; " +
172 "rm ${file}_encoded"
173 salt.cmdRun(master, target, cmd, false, null, false)
174 def filename = file.tokenize('/').last()
175 def folder = file - filename
176 def parts = salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f", "name=${filename}__*"])
177 for ( part in parts['return'][0].values()[0]) {
178 def _result = salt.cmdRun(master, target, "cat ${part}", false, null, false)
179 file_content = file_content + _result['return'][0].values()[0].replaceAll('Salt command execution success','')
180 }
181 salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f", "name=${filename}__*", "delete"])
182 return file_content
183}
184
185/**
186 * Copy files from remote to local directory. The content of files will be
187 * decoded by Base64.
188 *
189 * @param target Compound target (should target only one host)
190 * @param folder The path to remote folder.
191 * @param output_dir The path to local folder.
192 */
193def addFiles(master, target, folder, output_dir) {
194 def salt = new com.mirantis.mk.Salt()
195 def _result = salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f"])
196 def files = _result['return'][0].values()[0]
197 for (file in files) {
198 def file_content = getFileContentEncoded(master, target, "${file}")
199 def fileName = file.tokenize('/').last()
200 writeFile file: "${output_dir}${fileName}_encoded", text: file_content
201 def cmd = "base64 -d ${output_dir}${fileName}_encoded > ${output_dir}${fileName}; " +
202 "rm ${output_dir}${fileName}_encoded"
203 sh(script: cmd)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700204 }
205}
206
207/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500208 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700209 * Get reclass value
210 *
211 * @param target The host for which the values will be provided
212 * @param filter Parameters divided by dots
213 * @return The pillar data
214 */
215def getReclassValue(master, target, filter) {
216 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500217 common.errorMsg('You are using deprecated method! This method will be removed')
218 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700219 def salt = new com.mirantis.mk.Salt()
220 def items = filter.tokenize('.')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700221 def _result = salt.cmdRun(master, 'I@salt:master', "reclass-salt -o json -p ${target}", false, null, false)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700222 _result = common.parseJSON(_result['return'][0].values()[0])
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700223 for (int k = 0; k < items.size(); k++) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700224 if ( _result ) {
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700225 _result = _result["${items[k]}"]
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700226 }
227 }
228 return _result
229}
230
231/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500232 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700233 * Create list of nodes in JSON format.
234 *
235 * @param filter The Salt's matcher
236 * @return JSON list of nodes
237 */
238def getNodeList(master, filter = null) {
239 def salt = new com.mirantis.mk.Salt()
240 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500241 common.errorMsg('You are using deprecated method! This method will be removed')
242 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700243 def nodes = []
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700244 def filtered_list = null
245 def controllers = salt.getMinions(master, 'I@nova:controller')
246 def hw_nodes = salt.getMinions(master, 'G@virtual:physical')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700247 if ( filter ) {
248 filtered_list = salt.getMinions(master, filter)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700249 }
250 def _result = salt.cmdRun(master, 'I@salt:master', "reclass-salt -o json -t", false, null, false)
251 def reclass_top = common.parseJSON(_result['return'][0].values()[0])
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700252 def nodesList = reclass_top['base'].keySet()
253 for (int i = 0; i < nodesList.size(); i++) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700254 if ( filtered_list ) {
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700255 if ( ! filtered_list.contains(nodesList[i]) ) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700256 continue
257 }
258 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700259 def ip = getReclassValue(master, nodesList[i], '_param.linux_single_interface.address')
260 def network_data = [ip: ip, name: 'management']
261 def roles = [nodesList[i].tokenize('.')[0]]
262 if ( controllers.contains(nodesList[i]) ) {
263 roles.add('controller')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700264 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700265 if ( hw_nodes.contains(nodesList[i]) ) {
266 roles.add('hw_node')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700267 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700268 nodes.add([id: i+1, ip: ip, roles: roles, network_data: [network_data]])
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700269 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700270 return common.prettify(nodes)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700271}
272
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500273/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500274 * DEPRECATED
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500275 * Execute mcp sanity tests
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500276 * Deprecated. Will be removed soon
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500277 *
278 * @param salt_url Salt master url
279 * @param salt_credentials Salt credentials
280 * @param test_set Test set for mcp sanity framework
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600281 * @param env_vars Additional environment variables for cvp-sanity-checks
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500282 * @param output_dir Directory for results
283 */
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600284def runSanityTests(salt_url, salt_credentials, test_set="", output_dir="validation_artifacts/", env_vars="") {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500285 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500286 common.errorMsg('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
287 error('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600288 def creds = common.getCredentials(salt_credentials)
289 def username = creds.username
290 def password = creds.password
291 def settings = ""
292 if ( env_vars != "" ) {
293 for (var in env_vars.tokenize(";")) {
294 settings += "export ${var}; "
295 }
296 }
297 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${settings}" +
Ievgeniia Zadorozhnac2152172019-10-11 13:23:46 +0300298 "pytest --junitxml ${output_dir}cvp_sanity.xml --tb=short -rs -sv ${env.WORKSPACE}/cvp-sanity-checks/cvp_checks/tests/${test_set}"
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500299 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
300 def statusCode = sh script:script, returnStatus:true
301 }
302}
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700303
304/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500305 * DEPRECATED
Oleksii Zhurba4e366ff2018-02-16 20:06:52 -0600306 * Execute pytest framework tests
307 *
308 * @param salt_url Salt master url
309 * @param salt_credentials Salt credentials
310 * @param test_set Test set to run
311 * @param env_vars Additional environment variables for cvp-sanity-checks
312 * @param output_dir Directory for results
313 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500314def runPyTests(salt_url, salt_credentials, test_set="", env_vars="", name='cvp', container_node="", remote_dir='/root/qa_results/', artifacts_dir='validation_artifacts/') {
315 def xml_file = "${name}_report.xml"
316 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500317 common.errorMsg('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
318 error('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500319 def salt = new com.mirantis.mk.Salt()
320 def creds = common.getCredentials(salt_credentials)
321 def username = creds.username
322 def password = creds.password
323 if (container_node != "") {
324 def saltMaster
325 saltMaster = salt.connection(salt_url, salt_credentials)
326 def script = "pytest --junitxml ${xml_file} --tb=short -sv ${test_set}"
327 env_vars.addAll("SALT_USERNAME=${username}", "SALT_PASSWORD=${password}",
328 "SALT_URL=${salt_url}")
329 variables = ' -e ' + env_vars.join(' -e ')
330 salt.cmdRun(saltMaster, container_node, "docker exec ${variables} ${name} bash -c '${script}'", false)
331 salt.cmdRun(saltMaster, container_node, "docker cp ${name}:/var/lib/${xml_file} ${remote_dir}${xml_file}")
332 addFiles(saltMaster, container_node, remote_dir+xml_file, artifacts_dir)
333 }
334 else {
335 if (env_vars.size() > 0) {
336 variables = 'export ' + env_vars.join(';export ')
337 }
338 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${variables}; " +
339 "pytest --junitxml ${artifacts_dir}${xml_file} --tb=short -sv ${env.WORKSPACE}/${test_set}"
340 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
341 def statusCode = sh script:script, returnStatus:true
342 }
343 }
344}
345
346/**
347 * Execute pytest framework tests
348 * For backward compatibility
349 * Will be removed soon
350 *
351 * @param salt_url Salt master url
352 * @param salt_credentials Salt credentials
353 * @param test_set Test set to run
354 * @param env_vars Additional environment variables for cvp-sanity-checks
355 * @param output_dir Directory for results
356 */
Oleksii Zhurba4e366ff2018-02-16 20:06:52 -0600357def runTests(salt_url, salt_credentials, test_set="", output_dir="validation_artifacts/", env_vars="") {
358 def common = new com.mirantis.mk.Common()
359 def creds = common.getCredentials(salt_credentials)
360 def username = creds.username
361 def password = creds.password
362 def settings = ""
363 if ( env_vars != "" ) {
364 for (var in env_vars.tokenize(";")) {
365 settings += "export ${var}; "
366 }
367 }
368 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${settings}" +
Ievgeniia Zadorozhnac2152172019-10-11 13:23:46 +0300369 "pytest --junitxml ${output_dir}report.xml --tb=short -rs -sv ${env.WORKSPACE}/${test_set}"
Oleksii Zhurba4e366ff2018-02-16 20:06:52 -0600370 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
371 def statusCode = sh script:script, returnStatus:true
372 }
373}
374
375/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500376 * DEPRECATED
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700377 * Execute tempest tests
378 *
379 * @param target Host to run tests
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700380 * @param dockerImageLink Docker image link
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700381 * @param pattern If not false, will run only tests matched the pattern
382 * @param output_dir Directory for results
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800383 * @param confRepository Git repository with configuration files for Tempest
384 * @param confBranch Git branch which will be used during the checkout
385 * @param repository Git repository with Tempest
386 * @param version Version of Tempest (tag, branch or commit)
Sergey Galkind1068e22018-02-13 13:59:32 +0400387 * @param results The reports directory
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700388 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400389def runTempestTests(master, target, dockerImageLink, output_dir, confRepository, confBranch, repository, version, pattern = "false", results = '/root/qa_results') {
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700390 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500391 def common = new com.mirantis.mk.Common()
392 common.errorMsg('You are using deprecated method! This method will be removed')
393 error('You are using deprecated method! This method will be removed')
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700394 def output_file = 'docker-tempest.log'
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700395 def dest_folder = '/home/rally/qa_results'
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800396 def skip_list = '--skip-list /opt/devops-qa-tools/deployment/skip_contrail.list'
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700397 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
398 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
399 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
400 def keystone = _pillar['return'][0].values()[0]
Dmitry Tsapikovb6911922018-07-24 15:21:23 +0000401 def env_vars = ['tempest_version=15.0.0',
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700402 "OS_USERNAME=${keystone.admin_name}",
403 "OS_PASSWORD=${keystone.admin_password}",
404 "OS_TENANT_NAME=${keystone.admin_tenant}",
405 "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0",
406 "OS_REGION_NAME=${keystone.region}",
407 'OS_ENDPOINT_TYPE=admin'].join(' -e ')
408 def cmd = '/opt/devops-qa-tools/deployment/configure.sh; '
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800409 if (confRepository != '' ) {
410 cmd = "git clone -b ${confBranch ?: 'master'} ${confRepository} test_config; " +
411 'rally deployment create --fromenv --name=tempest; rally deployment config; ' +
412 'rally verify create-verifier --name tempest_verifier --type tempest ' +
Dmitry Tsapikovb6911922018-07-24 15:21:23 +0000413 "--source ${repository ?: '/tmp/tempest/'} --version ${version: '15.0.0'}; " +
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800414 'rally verify configure-verifier --extend test_config/tempest/tempest.conf --show; '
415 skip_list = '--skip-list test_config/tempest/skip-list.yaml'
416 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700417 if (pattern == 'false') {
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800418 cmd += "rally verify start --pattern set=full ${skip_list} --detailed; "
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700419 }
420 else {
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800421 cmd += "rally verify start --pattern set=${pattern} ${skip_list} --detailed; "
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700422 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700423 cmd += "rally verify report --type json --to ${dest_folder}/report-tempest.json; " +
424 "rally verify report --type html --to ${dest_folder}/report-tempest.html"
mkraynovd49daf52018-07-12 16:11:14 +0400425 salt.cmdRun(master, target, "docker run -w /home/rally -i --rm --net=host -e ${env_vars} " +
Sergey Galkin193ef872017-11-29 14:20:35 +0400426 "-v ${results}:${dest_folder} --entrypoint /bin/bash ${dockerImageLink} " +
427 "-c \"${cmd}\" > ${results}/${output_file}")
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700428 addFiles(master, target, results, output_dir)
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700429}
430
431/**
Oleg Basov40e502c2018-09-04 20:42:21 +0200432 * Make all-in-one scenario cmd for rally tests
433 *
434 * @param scenarios_path Path to scenarios folder/file
435 * @param skip_scenarios Comma-delimited list of scenarios names to skip
436 * @param bundle_file Bundle name to create
437*/
Oleg Basov06fce2a2018-11-09 21:39:03 +0100438def bundle_up_scenarios(scenarios_path, skip_scenarios, bundle_file = '' ) {
Oleg Basov40e502c2018-09-04 20:42:21 +0200439 def skip_names = ''
440 def skip_dirs = ''
441 def result = ''
442 if (skip_scenarios != ''){
443 for ( scen in skip_scenarios.split(',') ) {
444 if ( scen.contains('yaml')) {
445 skip_names += "! -name ${scen} "
446 }
447 else {
Oleg Basovde899e02019-03-26 12:31:27 +0100448 skip_dirs += "-path '${scenarios_path}/${scen}' -prune -o "
Oleg Basov40e502c2018-09-04 20:42:21 +0200449 }
450 }
451 }
Oleg Basov06fce2a2018-11-09 21:39:03 +0100452 if (bundle_file != '') {
453 result = "if [ -f ${scenarios_path} ]; then cp ${scenarios_path} ${bundle_file}; " +
Oleg Basov40e502c2018-09-04 20:42:21 +0200454 "else " +
455 "find -L ${scenarios_path} " + skip_dirs +
456 " -name '*.yaml' " + skip_names +
457 "-exec cat {} >> ${bundle_file} \\; ; " +
458 "sed -i '/---/d' ${bundle_file}; fi; "
Oleg Basov06fce2a2018-11-09 21:39:03 +0100459 } else {
460 result = "find -L ${scenarios_path} " + skip_dirs +
Oleg Basovde899e02019-03-26 12:31:27 +0100461 " -name '*.yaml' -print " + skip_names
Oleg Basov06fce2a2018-11-09 21:39:03 +0100462 }
Oleg Basov40e502c2018-09-04 20:42:21 +0200463
464 return result
465}
466
467/**
Oleg Basovde899e02019-03-26 12:31:27 +0100468 * Prepare setupDockerAndTest() commands to start Rally tests (optionally with K8S/Stacklight plugins)
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700469 *
Oleg Basovde899e02019-03-26 12:31:27 +0100470 * @param platform Map with underlay platform data
Oleg Basov20afb152018-06-10 03:09:25 +0200471 * @param scenarios Directory inside repo with specific scenarios
Oleg Basov40e502c2018-09-04 20:42:21 +0200472 * @param sl_scenarios Directory inside repo with specific scenarios for stacklight
Oleg Basov20afb152018-06-10 03:09:25 +0200473 * @param tasks_args_file Argument file that is used for throttling settings
Oleg Basov1fa6c662019-03-05 22:04:01 +0100474 * @param db_connection_str Rally-compliant external DB connection string
475 * @param tags Additional tags used for tagging tasks or building trends
476 * @param trends Build rally trends if enabled
Oleg Basovde899e02019-03-26 12:31:27 +0100477 *
478 * Returns: map
479 *
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700480 */
Oleg Basov1fa6c662019-03-05 22:04:01 +0100481def runRallyTests(
Oleg Basov698bec72019-05-28 11:49:16 +0200482 platform, scenarios = '', sl_scenarios = '',
483 tasks_args_file = '', db_connection_str = '', tags = [],
484 trends = false, skip_list = '', generateReport = true
Oleg Basovde899e02019-03-26 12:31:27 +0100485 ) {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100486
Oleg Basovde899e02019-03-26 12:31:27 +0100487 def dest_folder = '/home/rally'
488 def pluginsDir = "${dest_folder}/rally-plugins"
489 def scenariosDir = "${dest_folder}/rally-scenarios"
490 def resultsDir = "${dest_folder}/test_results"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100491 def date = new Date()
492 date = date.format("yyyyMMddHHmm")
Oleg Basovde899e02019-03-26 12:31:27 +0100493 // compile rally deployment name
494 deployment_name = "env=${platform.cluster_name}:platform=${platform.type}:" +
495 "date=${date}:cmp=${platform.cmp_count}"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100496
Oleg Basovde899e02019-03-26 12:31:27 +0100497 // set up Rally DB
498 def cmd_rally_init = ''
Oleg Basov1fa6c662019-03-05 22:04:01 +0100499 if (db_connection_str) {
500 cmd_rally_init = "sudo sed -i -e " +
501 "'s#connection=.*#connection=${db_connection_str}#' " +
502 "/etc/rally/rally.conf; "
503 }
Oleg Basovde899e02019-03-26 12:31:27 +0100504 cmd_rally_init += 'rally db ensure; '
505 // if several jobs are running in parallel (same deployment name),
506 // then try to find and use existing in db env
507 if (db_connection_str) {
508 cmd_rally_init += 'rally env use --env $(rally env list|awk \'/' +
509 deployment_name + '/ {print $2}\') ||'
510 }
511
512 def cmd_rally_start
513 def cmd_rally_stacklight
514 def cmd_rally_task_args = tasks_args_file ?: 'job-params-light.yaml'
Oleg Basov698bec72019-05-28 11:49:16 +0200515 def cmd_rally_report = ''
Oleg Basov1fa6c662019-03-05 22:04:01 +0100516 def cmd_filter_tags = ''
Oleg Basovde899e02019-03-26 12:31:27 +0100517 def trends_limit = 20
Oleg Basov1fa6c662019-03-05 22:04:01 +0100518
Oleg Basov698bec72019-05-28 11:49:16 +0200519 // generate html report if required
520 if (generateReport) {
521 cmd_rally_report = 'rally task export ' +
522 '--uuid $(rally task list --uuids-only --status finished) ' +
523 "--type junit-xml --to ${resultsDir}/report-rally.xml; " +
524 'rally task report --uuid $(rally task list --uuids-only --status finished) ' +
525 "--out ${resultsDir}/report-rally.html; "
526 }
527
Oleg Basov1fa6c662019-03-05 22:04:01 +0100528 // build rally trends if required
529 if (trends && db_connection_str) {
530 if (tags) {
531 cmd_filter_tags = "--tag " + tags.join(' ')
532 }
Oleg Basov698bec72019-05-28 11:49:16 +0200533 cmd_rally_report += 'rally task trends --tasks ' +
Oleg Basovde899e02019-03-26 12:31:27 +0100534 '$(rally task list ' + cmd_filter_tags +
535 ' --all-deployments --uuids-only --status finished ' +
536 "| head -${trends_limit} ) " +
537 "--out ${resultsDir}/trends-rally.html"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100538 }
539
540 // add default env tags for inserting into rally tasks
541 tags = tags + [
Oleg Basovde899e02019-03-26 12:31:27 +0100542 "env=${platform.cluster_name}",
Oleg Basov1fa6c662019-03-05 22:04:01 +0100543 "platform=${platform.type}",
Oleg Basovde899e02019-03-26 12:31:27 +0100544 "cmp=${platform.cmp_count}"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100545 ]
546
Oleg Basovde899e02019-03-26 12:31:27 +0100547 // set up rally deployment cmd
Oleg Basov40e502c2018-09-04 20:42:21 +0200548 if (platform['type'] == 'openstack') {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100549 cmd_rally_init += "rally deployment create --name='${deployment_name}' --fromenv; " +
550 "rally deployment check; "
Oleg Basov40e502c2018-09-04 20:42:21 +0200551 } else if (platform['type'] == 'k8s') {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100552 cmd_rally_init += "rally env create --name='${deployment_name}' --from-sysenv; " +
553 "rally env check; "
Oleg Basov20afb152018-06-10 03:09:25 +0200554 } else {
555 throw new Exception("Platform ${platform} is not supported yet")
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800556 }
Oleg Basov1fa6c662019-03-05 22:04:01 +0100557
558 // set up rally task args file
Oleg Basov06fce2a2018-11-09 21:39:03 +0100559 switch(tasks_args_file) {
560 case 'none':
Oleg Basovde899e02019-03-26 12:31:27 +0100561 cmd_rally_task_args = ''
Oleg Basov20afb152018-06-10 03:09:25 +0200562 break
Oleg Basov06fce2a2018-11-09 21:39:03 +0100563 case '':
Oleg Basovde899e02019-03-26 12:31:27 +0100564 cmd_rally_task_args = "--task-args-file ${scenariosDir}/job-params-light.yaml"
Oleg Basov06fce2a2018-11-09 21:39:03 +0100565 break
566 default:
Oleg Basovde899e02019-03-26 12:31:27 +0100567 cmd_rally_task_args = "--task-args-file ${scenariosDir}/${tasks_args_file}"
Oleg Basov06fce2a2018-11-09 21:39:03 +0100568 break
569 }
Oleg Basovde899e02019-03-26 12:31:27 +0100570
571 // configure Rally for Stacklight (only with Openstack for now)
572 if (platform['stacklight']['enabled'] && (platform['type'] == 'openstack')) {
573 if (! sl_scenarios) {
574 throw new Exception("There's no Stacklight scenarios to execute")
575 }
576 def scenBundle = "${resultsDir}/scenarios_${platform.type}_stacklight.yaml"
577 cmd_rally_stacklight = bundle_up_scenarios(
578 scenariosDir + '/' + sl_scenarios,
Oleg Basov1fa6c662019-03-05 22:04:01 +0100579 skip_list,
Oleg Basovde899e02019-03-26 12:31:27 +0100580 scenBundle,
Oleg Basov1fa6c662019-03-05 22:04:01 +0100581 )
Oleg Basovde899e02019-03-26 12:31:27 +0100582 tags.add('stacklight')
583 cmd_rally_stacklight += "sed -i 's/grafana_password: .*/grafana_password: ${platform.stacklight.grafanaPass}/' " +
584 "${scenariosDir}/${tasks_args_file}; rally --log-file ${resultsDir}/tasks_stacklight.log task start --tag " + tags.join(' ') +
585 " --task ${scenBundle} ${cmd_rally_task_args} || true "
Oleg Basov20afb152018-06-10 03:09:25 +0200586 }
Oleg Basovaaeb51f2018-10-17 01:07:10 +0200587
Oleg Basovde899e02019-03-26 12:31:27 +0100588 // prepare scenarios and rally task cmd
589 if (scenarios) {
590 switch (platform['type']) {
591 case 'openstack':
592 def scenBundle = "${resultsDir}/scenarios_${platform.type}.yaml"
593 cmd_rally_start = bundle_up_scenarios(
594 scenariosDir + '/' + scenarios,
595 skip_list,
596 scenBundle,
597 )
598 cmd_rally_start += "rally --log-file ${resultsDir}/tasks_openstack.log task start --tag " + tags.join(' ') +
599 " --task ${scenBundle} ${cmd_rally_task_args} || true; "
600 break
601 // due to the bug in Rally threads, K8S plugin gets stuck on big all-in-one scenarios
602 // so we have to feed them separately for K8S case
603 case 'k8s':
604 cmd_rally_start = 'for task in $(' +
605 bundle_up_scenarios(scenariosDir + '/' + scenarios, skip_list) + '); do ' +
606 "rally --log-file ${resultsDir}/tasks_k8s.log task start --tag " + tags.join(' ') +
607 ' --task $task ' + cmd_rally_task_args + ' || true; done; '
608 break
609 }
610 } else {
611 if (! cmd_rally_stacklight) {
612 throw new Exception("No scenarios found to run Rally on")
613 }
Oleg Basov1fa6c662019-03-05 22:04:01 +0100614 }
615
Oleg Basovde899e02019-03-26 12:31:27 +0100616 // compile full rally cmd map
617 def full_cmd = [
618 '001_install_plugins': "sudo pip install --upgrade ${pluginsDir}",
619 '002_init_rally': cmd_rally_init,
620 '003_start_rally': cmd_rally_start ?: "echo no tasks to run",
621 '004_start_rally_stacklight': cmd_rally_stacklight ?: "echo no tasks to run",
Oleg Basov698bec72019-05-28 11:49:16 +0200622 '005_rally_report': cmd_rally_report ?: "echo no tasks to run",
Oleg Basovde899e02019-03-26 12:31:27 +0100623 ]
624
625 return full_cmd
626
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700627}
628
629/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500630 * DEPRECATED
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700631 * Generate test report
632 *
633 * @param target Host to run script from
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700634 * @param dockerImageLink Docker image link
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700635 * @param output_dir Directory for results
Sergey Galkind1068e22018-02-13 13:59:32 +0400636 * @param results The reports directory
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700637 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400638def generateTestReport(master, target, dockerImageLink, output_dir, results = '/root/qa_results') {
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700639 def report_file = 'jenkins_test_report.html'
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700640 def salt = new com.mirantis.mk.Salt()
641 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500642 common.errorMsg('You are using deprecated method! This method will be removed')
643 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700644 def dest_folder = '/opt/devops-qa-tools/generate_test_report/test_results'
645 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
646 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
647 def reports = ['report-tempest.json',
648 'report-rally.xml',
649 'report-k8s-e2e-tests.txt',
650 'report-ha.json',
651 'report-spt.txt']
652 for ( report in reports ) {
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700653 if ( fileExists("${output_dir}${report}") ) {
654 common.infoMsg("Copying ${report} to docker container")
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700655 def items = sh(script: "base64 -w0 ${output_dir}${report} > ${output_dir}${report}_encoded; " +
656 "split -b 100KB -d -a 4 ${output_dir}${report}_encoded ${output_dir}${report}__; " +
657 "rm ${output_dir}${report}_encoded; " +
658 "find ${output_dir} -type f -name ${report}__* -printf \'%f\\n\' | sort", returnStdout: true)
659 for ( item in items.tokenize() ) {
660 def content = sh(script: "cat ${output_dir}${item}", returnStdout: true)
661 salt.cmdRun(master, target, "echo \"${content}\" >> ${results}/${report}_encoded", false, null, false)
662 sh(script: "rm ${output_dir}${item}")
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700663 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700664 salt.cmdRun(master, target, "base64 -d ${results}/${report}_encoded > ${results}/${report}; " +
665 "rm ${results}/${report}_encoded", false, null, false)
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700666 }
667 }
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700668
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700669 def cmd = "jenkins_report.py --path /opt/devops-qa-tools/generate_test_report/; " +
670 "cp ${report_file} ${dest_folder}/${report_file}"
671 salt.cmdRun(master, target, "docker run -i --rm --net=host " +
672 "-v ${results}:${dest_folder} ${dockerImageLink} " +
673 "/bin/bash -c \"${cmd}\"")
674 def report_content = salt.getFileContent(master, target, "${results}/${report_file}")
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700675 writeFile file: "${output_dir}${report_file}", text: report_content
676}
677
678/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500679 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700680 * Execute SPT tests
681 *
682 * @param target Host to run tests
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700683 * @param dockerImageLink Docker image link
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700684 * @param output_dir Directory for results
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700685 * @param ext_variables The list of external variables
Sergey Galkind1068e22018-02-13 13:59:32 +0400686 * @param results The reports directory
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700687 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400688def runSptTests(master, target, dockerImageLink, output_dir, ext_variables = [], results = '/root/qa_results') {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700689 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500690 def common = new com.mirantis.mk.Common()
691 common.errorMsg('You are using deprecated method! This method will be removed')
692 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700693 def dest_folder = '/home/rally/qa_results'
694 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
695 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
696 def nodes = getNodeList(master)
697 def nodes_hw = getNodeList(master, 'G@virtual:physical')
698 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
699 def keystone = _pillar['return'][0].values()[0]
700 def ssh_key = salt.getFileContent(master, 'I@salt:master', '/root/.ssh/id_rsa')
701 def env_vars = ( ['tempest_version=15.0.0',
702 "OS_USERNAME=${keystone.admin_name}",
703 "OS_PASSWORD=${keystone.admin_password}",
704 "OS_TENANT_NAME=${keystone.admin_tenant}",
705 "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0",
706 "OS_REGION_NAME=${keystone.region}",
707 'OS_ENDPOINT_TYPE=admin'] + ext_variables ).join(' -e ')
708 salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes.json", nodes])
709 salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes_hw.json", nodes_hw])
710 def cmd = '/opt/devops-qa-tools/deployment/configure.sh; ' +
711 'sudo mkdir -p /root/.ssh; sudo chmod 700 /root/.ssh; ' +
712 "echo \\\"${ssh_key}\\\" | sudo tee /root/.ssh/id_rsa > /dev/null; " +
713 'sudo chmod 600 /root/.ssh/id_rsa; ' +
714 "sudo timmy -c simplified-performance-testing/config.yaml " +
715 "--nodes-json ${dest_folder}/nodes.json --log-file ${dest_folder}/docker-spt2.log; " +
716 "./simplified-performance-testing/SPT_parser.sh > ${dest_folder}/report-spt.txt; " +
717 "custom_spt_parser.sh ${dest_folder}/nodes_hw.json > ${dest_folder}/report-spt-hw.txt; " +
718 "cp /tmp/timmy/archives/general.tar.gz ${dest_folder}/results-spt.tar.gz"
719 salt.cmdRun(master, target, "docker run -i --rm --net=host -e ${env_vars} " +
720 "-v ${results}:${dest_folder} ${dockerImageLink} /bin/bash -c " +
721 "\"${cmd}\" > ${results}/docker-spt.log")
722 addFiles(master, target, results, output_dir)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700723}
724
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700725/**
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600726 * Configure docker container
727 *
728 * @param target Host to run container
729 * @param proxy Proxy for accessing github and pip
730 * @param testing_tools_repo Repo with testing tools: configuration script, skip-list, etc.
Oleksii Zhurba1579b972017-12-14 15:21:56 -0600731 * @param tempest_repo Tempest repo to clone. Can be upstream tempest (default, recommended), your customized tempest in local/remote repo or path inside container. If not specified, tempest will not be configured.
732 * @param tempest_endpoint_type internalURL or adminURL or publicURL to use in tests
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500733 * @param tempest_version Version of tempest to use. This value will be just passed to configure.sh script (cvp-configuration repo).
Oleksii Zhurba1579b972017-12-14 15:21:56 -0600734 * @param conf_script_path Path to configuration script.
735 * @param ext_variables Some custom extra variables to add into container
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500736 * @param container_name Name of container to use
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600737 */
738def configureContainer(master, target, proxy, testing_tools_repo, tempest_repo,
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500739 tempest_endpoint_type="internalURL", tempest_version="",
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500740 conf_script_path="", ext_variables = [], container_name="cvp") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600741 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500742 def common = new com.mirantis.mk.Common()
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600743 if (testing_tools_repo != "" ) {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500744 workdir = ''
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500745 if (testing_tools_repo.contains('http://') || testing_tools_repo.contains('https://')) {
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500746 salt.cmdRun(master, target, "docker exec ${container_name} git clone ${testing_tools_repo} cvp-configuration")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500747 configure_script = conf_script_path != "" ? conf_script_path : "cvp-configuration/configure.sh"
748 }
749 else {
750 configure_script = testing_tools_repo
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500751 workdir = ' -w /var/lib/'
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500752 }
753 ext_variables.addAll("PROXY=${proxy}", "TEMPEST_REPO=${tempest_repo}",
754 "TEMPEST_ENDPOINT_TYPE=${tempest_endpoint_type}",
755 "tempest_version=${tempest_version}")
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500756 salt.cmdRun(master, target, "docker exec -e " + ext_variables.join(' -e ') + " ${workdir} ${container_name} bash -c ${configure_script}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600757 }
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500758 else {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500759 common.infoMsg("TOOLS_REPO is empty, no configuration is needed for this container")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500760 }
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600761}
762
763/**
764 * Run Tempest
765 *
766 * @param target Host to run container
767 * @param test_pattern Test pattern to run
768 * @param skip_list Path to skip-list
769 * @param output_dir Directory on target host for storing results (containers is not a good place)
770 */
771def runCVPtempest(master, target, test_pattern="set=smoke", skip_list="", output_dir, output_filename="docker-tempest") {
772 def salt = new com.mirantis.mk.Salt()
773 def xml_file = "${output_filename}.xml"
Oleksii Zhurba44045312017-12-12 15:38:26 -0600774 def html_file = "${output_filename}.html"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600775 skip_list_cmd = ''
776 if (skip_list != '') {
777 skip_list_cmd = "--skip-list ${skip_list}"
778 }
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500779 salt.cmdRun(master, target, "docker exec cvp rally verify start --pattern ${test_pattern} ${skip_list_cmd} --detailed")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600780 salt.cmdRun(master, target, "docker exec cvp rally verify report --type junit-xml --to /home/rally/${xml_file}")
Oleksii Zhurba44045312017-12-12 15:38:26 -0600781 salt.cmdRun(master, target, "docker exec cvp rally verify report --type html --to /home/rally/${html_file}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600782 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${xml_file} ${output_dir}")
Oleksii Zhurba44045312017-12-12 15:38:26 -0600783 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500784 return salt.cmdRun(master, target, "docker exec cvp rally verify show | head -5 | tail -1 | " +
785 "awk '{print \$4}'")['return'][0].values()[0].split()[0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600786}
787
788/**
789 * Run Rally
790 *
791 * @param target Host to run container
792 * @param test_pattern Test pattern to run
793 * @param scenarios_path Path to Rally scenarios
794 * @param output_dir Directory on target host for storing results (containers is not a good place)
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500795 * @param container_name Name of container to use
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600796 */
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500797def runCVPrally(master, target, scenarios_path, output_dir, output_filename="docker-rally", container_name="cvp") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600798 def salt = new com.mirantis.mk.Salt()
799 def xml_file = "${output_filename}.xml"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600800 def html_file = "${output_filename}.html"
Oleksii Zhurba5efe0ea2019-05-20 14:25:49 -0500801 salt.cmdRun(master, target, "docker exec ${container_name} rally task start ${scenarios_path}", false)
802 salt.cmdRun(master, target, "docker exec ${container_name} rally task report --out /home/rally/${html_file}", false)
803 salt.cmdRun(master, target, "docker exec ${container_name} rally task report --junit --out /home/rally/${xml_file}", false)
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500804 salt.cmdRun(master, target, "docker cp ${container_name}:/home/rally/${xml_file} ${output_dir}")
805 salt.cmdRun(master, target, "docker cp ${container_name}:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600806}
807
808
809/**
810 * Shutdown node
811 *
812 * @param target Host to run command
813 * @param mode How to shutdown node
814 * @param retries # of retries to make to check node status
815 */
816def shutdown_vm_node(master, target, mode, retries=200) {
817 def salt = new com.mirantis.mk.Salt()
818 def common = new com.mirantis.mk.Common()
819 if (mode == 'reboot') {
820 try {
821 def out = salt.runSaltCommand(master, 'local', ['expression': target, 'type': 'compound'], 'cmd.run', null, ['reboot'], null, 3, 3)
822 } catch (Exception e) {
823 common.warningMsg('Timeout from minion: node must be rebooting now')
824 }
825 common.warningMsg("Checking that minion is down")
826 status = "True"
827 for (i = 0; i < retries; i++) {
828 status = salt.minionsReachable(master, 'I@salt:master', target, null, 5, 1)
829 if (status != "True") {
830 break
831 }
832 }
833 if (status == "True") {
834 throw new Exception("Tired to wait for minion ${target} to stop responding")
835 }
836 }
837 if (mode == 'hard_shutdown' || mode == 'soft_shutdown') {
838 kvm = locate_node_on_kvm(master, target)
839 if (mode == 'soft_shutdown') {
840 salt.cmdRun(master, target, "shutdown -h 0")
841 }
842 if (mode == 'hard_shutdown') {
843 salt.cmdRun(master, kvm, "virsh destroy ${target}")
844 }
845 common.warningMsg("Checking that vm on kvm is in power off state")
846 status = 'running'
847 for (i = 0; i < retries; i++) {
848 status = check_vm_status(master, target, kvm)
849 echo "Current status - ${status}"
850 if (status != 'running') {
851 break
852 }
853 sleep (1)
854 }
855 if (status == 'running') {
856 throw new Exception("Tired to wait for node ${target} to shutdown")
857 }
858 }
859}
860
861
862/**
863 * Locate kvm where target host is located
864 *
865 * @param target Host to check
866 */
867def locate_node_on_kvm(master, target) {
868 def salt = new com.mirantis.mk.Salt()
869 def list = salt.runSaltProcessStep(master, "I@salt:control", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
870 for (item in list.keySet()) {
871 if (list[item]) {
872 return item
873 }
874 }
875}
876
877/**
878 * Check target host status
879 *
880 * @param target Host to check
881 * @param kvm KVM node where target host is located
882 */
883def check_vm_status(master, target, kvm) {
884 def salt = new com.mirantis.mk.Salt()
885 def list = salt.runSaltProcessStep(master, "${kvm}", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
886 for (item in list.keySet()) {
887 if (list[item]) {
888 return list[item].split()[2]
889 }
890 }
891}
892
893/**
894 * Find vip on nodes
895 *
896 * @param target Pattern, e.g. ctl*
897 */
898def get_vip_node(master, target) {
899 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba5f73cf62018-08-03 16:11:10 -0500900 def list = salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["ip a | grep '/32'"])['return'][0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600901 for (item in list.keySet()) {
902 if (list[item]) {
903 return item
904 }
905 }
906}
907
908/**
909 * Find vip on nodes
910 *
911 * @param target Host with cvp container
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500912 * @param container_name Name of container
913 * @param script_path Path to cleanup script (inside container)
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600914 */
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500915def openstack_cleanup(master, target, container_name="cvp", script_path="/home/rally/cleanup.sh") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600916 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500917 salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["docker exec ${container_name} bash -c ${script_path}"])
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600918}
919
920
921/**
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700922 * Cleanup
923 *
924 * @param target Host to run commands
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500925 * @param name Name of container to remove
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700926 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500927def runCleanup(master, target, name='cvp') {
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700928 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500929 if ( salt.cmdRun(master, target, "docker ps -f name=${name} -q", false, null, false)['return'][0].values()[0] ) {
930 salt.cmdRun(master, target, "docker rm -f ${name}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600931 }
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700932}
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500933/**
934 * Prepare venv for any python project
935 * Note: <repo_name>\/requirements.txt content will be used
936 * for this venv
937 *
938 * @param repo_url Repository url to clone
939 * @param proxy Proxy address to use
940 */
dtsapikovf2e1bb12018-11-29 18:49:48 +0400941def prepareVenv(repo_url, proxy, useSystemPackages=false) {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500942 def python = new com.mirantis.mk.Python()
943 repo_name = "${repo_url}".tokenize("/").last()
Oleksii Zhurbae711ebb2018-06-15 16:36:38 -0500944 if (repo_url.tokenize().size() > 1){
945 if (repo_url.tokenize()[1] == '-b'){
946 repo_name = repo_url.tokenize()[0].tokenize("/").last()
947 }
948 }
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500949 path_venv = "${env.WORKSPACE}/venv"
950 path_req = "${env.WORKSPACE}/${repo_name}/requirements.txt"
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500951 sh "rm -rf ${repo_name}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500952 // this is temporary W/A for offline deployments
953 // Jenkins slave image has /opt/pip-mirror/ folder
954 // where pip wheels for cvp projects are located
955 if (proxy != 'offline') {
956 withEnv(["HTTPS_PROXY=${proxy}", "HTTP_PROXY=${proxy}", "https_proxy=${proxy}", "http_proxy=${proxy}"]) {
957 sh "git clone ${repo_url}"
dtsapikovf2e1bb12018-11-29 18:49:48 +0400958 python.setupVirtualenv(path_venv, "python2", [], path_req, true, useSystemPackages)
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500959 }
960 }
961 else {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500962 sh "git clone ${repo_url}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500963 sh "virtualenv ${path_venv} --python python2"
964 python.runVirtualenvCommand(path_venv, "pip install --no-index --find-links=/opt/pip-mirror/ -r ${path_req}", true)
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500965 }
966}
967
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700968/** Install docker if needed
969 *
970 * @param target Target node to install docker pkg
971 */
972def installDocker(master, target) {
973 def salt = new com.mirantis.mk.Salt()
974 if ( ! salt.runSaltProcessStep(master, target, 'pkg.version', ["docker-engine"]) ) {
975 salt.runSaltProcessStep(master, target, 'pkg.install', ["docker.io"])
976 }
977}