blob: 36db40e518c9f4d3ead32aa2bbcec77c910b7164 [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
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050044**/
45
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050046def runContainer(Map params){
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050047 def common = new com.mirantis.mk.Common()
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050048 defaults = ["name": "cvp", "env_var": [], "entrypoint": true]
49 params = defaults + params
50 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050051 def variables = ''
52 def entry_point = ''
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050053 def tempest_conf_mount = ''
54 def mounts = ''
55 def cluster_name = salt.getPillar(params.master, 'I@salt:master', '_param:cluster_name')['return'][0].values()[0]
56 default_mounts = ["/etc/ssl/certs/": "/etc/ssl/certs/",
57 "/srv/salt/pki/${cluster_name}/": "/etc/certs",
58 "/root/test/": "/root/tempest/",
59 "/tmp/": "/tmp/",
60 "/etc/hosts": "/etc/hosts"]
61 params.mounts = default_mounts + params.mounts
62 if ( salt.cmdRun(params.master, params.target, "docker ps -f name=${params.name} -q", false, null, false)['return'][0].values()[0] ) {
63 salt.cmdRun(params.master, params.target, "docker rm -f ${params.name}")
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050064 }
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050065 if (params.env_var.size() > 0) {
66 variables = ' -e ' + params.env_var.join(' -e ')
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050067 }
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050068 if (params.entrypoint) {
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050069 entry_point = '--entrypoint /bin/bash'
70 }
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050071 params.mounts.each { local, container ->
72 mounts = mounts + " -v ${local}:${container}"
73 }
74 salt.cmdRun(params.master, params.target, "docker run -tid --net=host --name=${params.name}" +
75 "${mounts} -u root ${entry_point} ${variables} ${params.dockerImageLink}")
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050076}
77
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050078def runContainer(master, target, dockerImageLink, name='cvp', env_var=[], entrypoint=true, mounts=[:]){
79 def common = new com.mirantis.mk.Common()
80 common.infoMsg("This method will be deprecated. Convert you method call to use Map as input parameter")
81 // Convert to Map
82 params = ['master': master, 'target': target, 'dockerImageLink': dockerImageLink, 'name': name, 'env_var': env_var,
83 'entrypoint': entrypoint, 'mounts': mounts]
84 // Call new method with Map as parameter
85 return runContainer(params)
86}
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050087
Petr Lomakin47fee0a2017-08-01 10:46:05 -070088/**
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -050089 * Get v2 Keystone credentials from pillars
90 *
91 */
92def _get_keystone_creds_v2(master){
93 def salt = new com.mirantis.mk.Salt()
94 def common = new com.mirantis.mk.Common()
95 def keystone = []
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -050096 _pillar = false
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -050097 common.infoMsg("Fetching Keystone v2 credentials")
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -050098 _response = salt.runSaltProcessStep(master, 'I@keystone:server', 'pillar.get', 'keystone:server', null, false, 1)['return'][0]
99 for (i = 0; i < _response.keySet().size(); i++) {
100 if ( _response.values()[i] ) {
101 _pillar = _response.values()[i]
102 }
103 }
104 if (_pillar) {
105 keystone.add("OS_USERNAME=${_pillar.admin_name}")
106 keystone.add("OS_PASSWORD=${_pillar.admin_password}")
107 keystone.add("OS_TENANT_NAME=${_pillar.admin_tenant}")
108 keystone.add("OS_AUTH_URL=http://${_pillar.bind.private_address}:${_pillar.bind.private_port}/v2.0")
109 keystone.add("OS_REGION_NAME=${_pillar.region}")
110 keystone.add("OS_ENDPOINT_TYPE=admin")
111 return keystone
112 }
113 else {
114 throw new Exception("Cannot fetch Keystone v2 credentials. Response: ${_response}")
115 }
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500116}
117
118/**
119 * Get v3 Keystone credentials from pillars
120 *
121 */
122def _get_keystone_creds_v3(master){
123 def salt = new com.mirantis.mk.Salt()
124 def common = new com.mirantis.mk.Common()
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500125 _pillar = false
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500126 pillar_name = 'keystone:client:os_client_config:cfgs:root:content:clouds:admin_identity'
127 common.infoMsg("Fetching Keystone v3 credentials")
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500128 _response = salt.runSaltProcessStep(master, 'I@keystone:server', 'pillar.get', pillar_name, null, false, 1)['return'][0]
129 for (i = 0; i < _response.keySet().size(); i++) {
130 if ( _response.values()[i] ) {
131 _pillar = _response.values()[i]
132 }
133 }
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500134 def keystone = []
135 if (_pillar) {
136 keystone.add("OS_USERNAME=${_pillar.auth.username}")
137 keystone.add("OS_PASSWORD=${_pillar.auth.password}")
138 keystone.add("OS_TENANT_NAME=${_pillar.auth.project_name}")
139 keystone.add("OS_PROJECT_NAME=${_pillar.auth.project_name}")
140 keystone.add("OS_AUTH_URL=${_pillar.auth.auth_url}/v3")
141 keystone.add("OS_REGION_NAME=${_pillar.region_name}")
142 keystone.add("OS_IDENTITY_API_VERSION=${_pillar.identity_api_version}")
Oleksii Zhurbafa885ed2019-02-13 18:27:31 -0600143 keystone.add("OS_ENDPOINT_TYPE=internal")
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500144 keystone.add("OS_PROJECT_DOMAIN_NAME=${_pillar.auth.project_domain_name}")
145 keystone.add("OS_USER_DOMAIN_NAME=${_pillar.auth.user_domain_name}")
Oleksii Zhurbafa885ed2019-02-13 18:27:31 -0600146 // we mount /srv/salt/pki/${cluster_name}/:/etc/certs with certs for cvp container
147 keystone.add("OS_CACERT='/etc/certs/proxy-with-chain.crt'")
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500148 return keystone
149 }
150 else {
151 common.warningMsg("Failed to fetch Keystone v3 credentials")
152 return false
153 }
154}
155
156/**
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700157 * Get file content (encoded). The content encoded by Base64.
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700158 *
159 * @param target Compound target (should target only one host)
160 * @param file File path to read
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700161 * @return The encoded content of the file
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700162 */
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700163def getFileContentEncoded(master, target, file) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700164 def salt = new com.mirantis.mk.Salt()
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700165 def file_content = ''
166 def cmd = "base64 -w0 ${file} > ${file}_encoded; " +
167 "split -b 1MB -d ${file}_encoded ${file}__; " +
168 "rm ${file}_encoded"
169 salt.cmdRun(master, target, cmd, false, null, false)
170 def filename = file.tokenize('/').last()
171 def folder = file - filename
172 def parts = salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f", "name=${filename}__*"])
173 for ( part in parts['return'][0].values()[0]) {
174 def _result = salt.cmdRun(master, target, "cat ${part}", false, null, false)
175 file_content = file_content + _result['return'][0].values()[0].replaceAll('Salt command execution success','')
176 }
177 salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f", "name=${filename}__*", "delete"])
178 return file_content
179}
180
181/**
182 * Copy files from remote to local directory. The content of files will be
183 * decoded by Base64.
184 *
185 * @param target Compound target (should target only one host)
186 * @param folder The path to remote folder.
187 * @param output_dir The path to local folder.
188 */
189def addFiles(master, target, folder, output_dir) {
190 def salt = new com.mirantis.mk.Salt()
191 def _result = salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f"])
192 def files = _result['return'][0].values()[0]
193 for (file in files) {
194 def file_content = getFileContentEncoded(master, target, "${file}")
195 def fileName = file.tokenize('/').last()
196 writeFile file: "${output_dir}${fileName}_encoded", text: file_content
197 def cmd = "base64 -d ${output_dir}${fileName}_encoded > ${output_dir}${fileName}; " +
198 "rm ${output_dir}${fileName}_encoded"
199 sh(script: cmd)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700200 }
201}
202
203/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500204 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700205 * Get reclass value
206 *
207 * @param target The host for which the values will be provided
208 * @param filter Parameters divided by dots
209 * @return The pillar data
210 */
211def getReclassValue(master, target, filter) {
212 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500213 common.errorMsg('You are using deprecated method! This method will be removed')
214 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700215 def salt = new com.mirantis.mk.Salt()
216 def items = filter.tokenize('.')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700217 def _result = salt.cmdRun(master, 'I@salt:master', "reclass-salt -o json -p ${target}", false, null, false)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700218 _result = common.parseJSON(_result['return'][0].values()[0])
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700219 for (int k = 0; k < items.size(); k++) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700220 if ( _result ) {
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700221 _result = _result["${items[k]}"]
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700222 }
223 }
224 return _result
225}
226
227/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500228 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700229 * Create list of nodes in JSON format.
230 *
231 * @param filter The Salt's matcher
232 * @return JSON list of nodes
233 */
234def getNodeList(master, filter = null) {
235 def salt = new com.mirantis.mk.Salt()
236 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500237 common.errorMsg('You are using deprecated method! This method will be removed')
238 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700239 def nodes = []
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700240 def filtered_list = null
241 def controllers = salt.getMinions(master, 'I@nova:controller')
242 def hw_nodes = salt.getMinions(master, 'G@virtual:physical')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700243 if ( filter ) {
244 filtered_list = salt.getMinions(master, filter)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700245 }
246 def _result = salt.cmdRun(master, 'I@salt:master', "reclass-salt -o json -t", false, null, false)
247 def reclass_top = common.parseJSON(_result['return'][0].values()[0])
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700248 def nodesList = reclass_top['base'].keySet()
249 for (int i = 0; i < nodesList.size(); i++) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700250 if ( filtered_list ) {
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700251 if ( ! filtered_list.contains(nodesList[i]) ) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700252 continue
253 }
254 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700255 def ip = getReclassValue(master, nodesList[i], '_param.linux_single_interface.address')
256 def network_data = [ip: ip, name: 'management']
257 def roles = [nodesList[i].tokenize('.')[0]]
258 if ( controllers.contains(nodesList[i]) ) {
259 roles.add('controller')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700260 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700261 if ( hw_nodes.contains(nodesList[i]) ) {
262 roles.add('hw_node')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700263 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700264 nodes.add([id: i+1, ip: ip, roles: roles, network_data: [network_data]])
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700265 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700266 return common.prettify(nodes)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700267}
268
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500269/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500270 * DEPRECATED
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500271 * Execute mcp sanity tests
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500272 * Deprecated. Will be removed soon
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500273 *
274 * @param salt_url Salt master url
275 * @param salt_credentials Salt credentials
276 * @param test_set Test set for mcp sanity framework
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600277 * @param env_vars Additional environment variables for cvp-sanity-checks
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500278 * @param output_dir Directory for results
279 */
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600280def runSanityTests(salt_url, salt_credentials, test_set="", output_dir="validation_artifacts/", env_vars="") {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500281 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500282 common.errorMsg('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
283 error('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600284 def creds = common.getCredentials(salt_credentials)
285 def username = creds.username
286 def password = creds.password
287 def settings = ""
288 if ( env_vars != "" ) {
289 for (var in env_vars.tokenize(";")) {
290 settings += "export ${var}; "
291 }
292 }
293 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${settings}" +
Oleksii Zhurba5250a9c2018-03-21 15:47:03 -0500294 "pytest --junitxml ${output_dir}cvp_sanity.xml --tb=short -sv ${env.WORKSPACE}/cvp-sanity-checks/cvp_checks/tests/${test_set}"
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500295 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
296 def statusCode = sh script:script, returnStatus:true
297 }
298}
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700299
300/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500301 * DEPRECATED
Oleksii Zhurba4e366ff2018-02-16 20:06:52 -0600302 * Execute pytest framework tests
303 *
304 * @param salt_url Salt master url
305 * @param salt_credentials Salt credentials
306 * @param test_set Test set to run
307 * @param env_vars Additional environment variables for cvp-sanity-checks
308 * @param output_dir Directory for results
309 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500310def runPyTests(salt_url, salt_credentials, test_set="", env_vars="", name='cvp', container_node="", remote_dir='/root/qa_results/', artifacts_dir='validation_artifacts/') {
311 def xml_file = "${name}_report.xml"
312 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500313 common.errorMsg('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
314 error('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500315 def salt = new com.mirantis.mk.Salt()
316 def creds = common.getCredentials(salt_credentials)
317 def username = creds.username
318 def password = creds.password
319 if (container_node != "") {
320 def saltMaster
321 saltMaster = salt.connection(salt_url, salt_credentials)
322 def script = "pytest --junitxml ${xml_file} --tb=short -sv ${test_set}"
323 env_vars.addAll("SALT_USERNAME=${username}", "SALT_PASSWORD=${password}",
324 "SALT_URL=${salt_url}")
325 variables = ' -e ' + env_vars.join(' -e ')
326 salt.cmdRun(saltMaster, container_node, "docker exec ${variables} ${name} bash -c '${script}'", false)
327 salt.cmdRun(saltMaster, container_node, "docker cp ${name}:/var/lib/${xml_file} ${remote_dir}${xml_file}")
328 addFiles(saltMaster, container_node, remote_dir+xml_file, artifacts_dir)
329 }
330 else {
331 if (env_vars.size() > 0) {
332 variables = 'export ' + env_vars.join(';export ')
333 }
334 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${variables}; " +
335 "pytest --junitxml ${artifacts_dir}${xml_file} --tb=short -sv ${env.WORKSPACE}/${test_set}"
336 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
337 def statusCode = sh script:script, returnStatus:true
338 }
339 }
340}
341
342/**
343 * Execute pytest framework tests
344 * For backward compatibility
345 * Will be removed soon
346 *
347 * @param salt_url Salt master url
348 * @param salt_credentials Salt credentials
349 * @param test_set Test set to run
350 * @param env_vars Additional environment variables for cvp-sanity-checks
351 * @param output_dir Directory for results
352 */
Oleksii Zhurba4e366ff2018-02-16 20:06:52 -0600353def runTests(salt_url, salt_credentials, test_set="", output_dir="validation_artifacts/", env_vars="") {
354 def common = new com.mirantis.mk.Common()
355 def creds = common.getCredentials(salt_credentials)
356 def username = creds.username
357 def password = creds.password
358 def settings = ""
359 if ( env_vars != "" ) {
360 for (var in env_vars.tokenize(";")) {
361 settings += "export ${var}; "
362 }
363 }
364 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${settings}" +
365 "pytest --junitxml ${output_dir}report.xml --tb=short -sv ${env.WORKSPACE}/${test_set}"
366 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
367 def statusCode = sh script:script, returnStatus:true
368 }
369}
370
371/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500372 * DEPRECATED
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700373 * Execute tempest tests
374 *
375 * @param target Host to run tests
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700376 * @param dockerImageLink Docker image link
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700377 * @param pattern If not false, will run only tests matched the pattern
378 * @param output_dir Directory for results
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800379 * @param confRepository Git repository with configuration files for Tempest
380 * @param confBranch Git branch which will be used during the checkout
381 * @param repository Git repository with Tempest
382 * @param version Version of Tempest (tag, branch or commit)
Sergey Galkind1068e22018-02-13 13:59:32 +0400383 * @param results The reports directory
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700384 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400385def runTempestTests(master, target, dockerImageLink, output_dir, confRepository, confBranch, repository, version, pattern = "false", results = '/root/qa_results') {
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700386 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500387 def common = new com.mirantis.mk.Common()
388 common.errorMsg('You are using deprecated method! This method will be removed')
389 error('You are using deprecated method! This method will be removed')
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700390 def output_file = 'docker-tempest.log'
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700391 def dest_folder = '/home/rally/qa_results'
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800392 def skip_list = '--skip-list /opt/devops-qa-tools/deployment/skip_contrail.list'
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700393 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
394 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
395 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
396 def keystone = _pillar['return'][0].values()[0]
Dmitry Tsapikovb6911922018-07-24 15:21:23 +0000397 def env_vars = ['tempest_version=15.0.0',
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700398 "OS_USERNAME=${keystone.admin_name}",
399 "OS_PASSWORD=${keystone.admin_password}",
400 "OS_TENANT_NAME=${keystone.admin_tenant}",
401 "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0",
402 "OS_REGION_NAME=${keystone.region}",
403 'OS_ENDPOINT_TYPE=admin'].join(' -e ')
404 def cmd = '/opt/devops-qa-tools/deployment/configure.sh; '
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800405 if (confRepository != '' ) {
406 cmd = "git clone -b ${confBranch ?: 'master'} ${confRepository} test_config; " +
407 'rally deployment create --fromenv --name=tempest; rally deployment config; ' +
408 'rally verify create-verifier --name tempest_verifier --type tempest ' +
Dmitry Tsapikovb6911922018-07-24 15:21:23 +0000409 "--source ${repository ?: '/tmp/tempest/'} --version ${version: '15.0.0'}; " +
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800410 'rally verify configure-verifier --extend test_config/tempest/tempest.conf --show; '
411 skip_list = '--skip-list test_config/tempest/skip-list.yaml'
412 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700413 if (pattern == 'false') {
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800414 cmd += "rally verify start --pattern set=full ${skip_list} --detailed; "
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700415 }
416 else {
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800417 cmd += "rally verify start --pattern set=${pattern} ${skip_list} --detailed; "
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700418 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700419 cmd += "rally verify report --type json --to ${dest_folder}/report-tempest.json; " +
420 "rally verify report --type html --to ${dest_folder}/report-tempest.html"
mkraynovd49daf52018-07-12 16:11:14 +0400421 salt.cmdRun(master, target, "docker run -w /home/rally -i --rm --net=host -e ${env_vars} " +
Sergey Galkin193ef872017-11-29 14:20:35 +0400422 "-v ${results}:${dest_folder} --entrypoint /bin/bash ${dockerImageLink} " +
423 "-c \"${cmd}\" > ${results}/${output_file}")
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700424 addFiles(master, target, results, output_dir)
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700425}
426
427/**
Oleg Basov40e502c2018-09-04 20:42:21 +0200428 * Make all-in-one scenario cmd for rally tests
429 *
430 * @param scenarios_path Path to scenarios folder/file
431 * @param skip_scenarios Comma-delimited list of scenarios names to skip
432 * @param bundle_file Bundle name to create
433*/
Oleg Basov06fce2a2018-11-09 21:39:03 +0100434def bundle_up_scenarios(scenarios_path, skip_scenarios, bundle_file = '' ) {
Oleg Basov40e502c2018-09-04 20:42:21 +0200435 def skip_names = ''
436 def skip_dirs = ''
437 def result = ''
438 if (skip_scenarios != ''){
439 for ( scen in skip_scenarios.split(',') ) {
440 if ( scen.contains('yaml')) {
441 skip_names += "! -name ${scen} "
442 }
443 else {
Oleg Basovde899e02019-03-26 12:31:27 +0100444 skip_dirs += "-path '${scenarios_path}/${scen}' -prune -o "
Oleg Basov40e502c2018-09-04 20:42:21 +0200445 }
446 }
447 }
Oleg Basov06fce2a2018-11-09 21:39:03 +0100448 if (bundle_file != '') {
449 result = "if [ -f ${scenarios_path} ]; then cp ${scenarios_path} ${bundle_file}; " +
Oleg Basov40e502c2018-09-04 20:42:21 +0200450 "else " +
451 "find -L ${scenarios_path} " + skip_dirs +
452 " -name '*.yaml' " + skip_names +
453 "-exec cat {} >> ${bundle_file} \\; ; " +
454 "sed -i '/---/d' ${bundle_file}; fi; "
Oleg Basov06fce2a2018-11-09 21:39:03 +0100455 } else {
456 result = "find -L ${scenarios_path} " + skip_dirs +
Oleg Basovde899e02019-03-26 12:31:27 +0100457 " -name '*.yaml' -print " + skip_names
Oleg Basov06fce2a2018-11-09 21:39:03 +0100458 }
Oleg Basov40e502c2018-09-04 20:42:21 +0200459
460 return result
461}
462
463/**
Oleg Basovde899e02019-03-26 12:31:27 +0100464 * Prepare setupDockerAndTest() commands to start Rally tests (optionally with K8S/Stacklight plugins)
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700465 *
Oleg Basovde899e02019-03-26 12:31:27 +0100466 * @param platform Map with underlay platform data
Oleg Basov20afb152018-06-10 03:09:25 +0200467 * @param scenarios Directory inside repo with specific scenarios
Oleg Basov40e502c2018-09-04 20:42:21 +0200468 * @param sl_scenarios Directory inside repo with specific scenarios for stacklight
Oleg Basov20afb152018-06-10 03:09:25 +0200469 * @param tasks_args_file Argument file that is used for throttling settings
Oleg Basov1fa6c662019-03-05 22:04:01 +0100470 * @param db_connection_str Rally-compliant external DB connection string
471 * @param tags Additional tags used for tagging tasks or building trends
472 * @param trends Build rally trends if enabled
Oleg Basovde899e02019-03-26 12:31:27 +0100473 *
474 * Returns: map
475 *
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700476 */
Oleg Basov1fa6c662019-03-05 22:04:01 +0100477def runRallyTests(
Oleg Basov698bec72019-05-28 11:49:16 +0200478 platform, scenarios = '', sl_scenarios = '',
479 tasks_args_file = '', db_connection_str = '', tags = [],
480 trends = false, skip_list = '', generateReport = true
Oleg Basovde899e02019-03-26 12:31:27 +0100481 ) {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100482
Oleg Basovde899e02019-03-26 12:31:27 +0100483 def dest_folder = '/home/rally'
484 def pluginsDir = "${dest_folder}/rally-plugins"
485 def scenariosDir = "${dest_folder}/rally-scenarios"
486 def resultsDir = "${dest_folder}/test_results"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100487 def date = new Date()
488 date = date.format("yyyyMMddHHmm")
Oleg Basovde899e02019-03-26 12:31:27 +0100489 // compile rally deployment name
490 deployment_name = "env=${platform.cluster_name}:platform=${platform.type}:" +
491 "date=${date}:cmp=${platform.cmp_count}"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100492
Oleg Basovde899e02019-03-26 12:31:27 +0100493 // set up Rally DB
494 def cmd_rally_init = ''
Oleg Basov1fa6c662019-03-05 22:04:01 +0100495 if (db_connection_str) {
496 cmd_rally_init = "sudo sed -i -e " +
497 "'s#connection=.*#connection=${db_connection_str}#' " +
498 "/etc/rally/rally.conf; "
499 }
Oleg Basovde899e02019-03-26 12:31:27 +0100500 cmd_rally_init += 'rally db ensure; '
501 // if several jobs are running in parallel (same deployment name),
502 // then try to find and use existing in db env
503 if (db_connection_str) {
504 cmd_rally_init += 'rally env use --env $(rally env list|awk \'/' +
505 deployment_name + '/ {print $2}\') ||'
506 }
507
508 def cmd_rally_start
509 def cmd_rally_stacklight
510 def cmd_rally_task_args = tasks_args_file ?: 'job-params-light.yaml'
Oleg Basov698bec72019-05-28 11:49:16 +0200511 def cmd_rally_report = ''
Oleg Basov1fa6c662019-03-05 22:04:01 +0100512 def cmd_filter_tags = ''
Oleg Basovde899e02019-03-26 12:31:27 +0100513 def trends_limit = 20
Oleg Basov1fa6c662019-03-05 22:04:01 +0100514
Oleg Basov698bec72019-05-28 11:49:16 +0200515 // generate html report if required
516 if (generateReport) {
517 cmd_rally_report = 'rally task export ' +
518 '--uuid $(rally task list --uuids-only --status finished) ' +
519 "--type junit-xml --to ${resultsDir}/report-rally.xml; " +
520 'rally task report --uuid $(rally task list --uuids-only --status finished) ' +
521 "--out ${resultsDir}/report-rally.html; "
522 }
523
Oleg Basov1fa6c662019-03-05 22:04:01 +0100524 // build rally trends if required
525 if (trends && db_connection_str) {
526 if (tags) {
527 cmd_filter_tags = "--tag " + tags.join(' ')
528 }
Oleg Basov698bec72019-05-28 11:49:16 +0200529 cmd_rally_report += 'rally task trends --tasks ' +
Oleg Basovde899e02019-03-26 12:31:27 +0100530 '$(rally task list ' + cmd_filter_tags +
531 ' --all-deployments --uuids-only --status finished ' +
532 "| head -${trends_limit} ) " +
533 "--out ${resultsDir}/trends-rally.html"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100534 }
535
536 // add default env tags for inserting into rally tasks
537 tags = tags + [
Oleg Basovde899e02019-03-26 12:31:27 +0100538 "env=${platform.cluster_name}",
Oleg Basov1fa6c662019-03-05 22:04:01 +0100539 "platform=${platform.type}",
Oleg Basovde899e02019-03-26 12:31:27 +0100540 "cmp=${platform.cmp_count}"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100541 ]
542
Oleg Basovde899e02019-03-26 12:31:27 +0100543 // set up rally deployment cmd
Oleg Basov40e502c2018-09-04 20:42:21 +0200544 if (platform['type'] == 'openstack') {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100545 cmd_rally_init += "rally deployment create --name='${deployment_name}' --fromenv; " +
546 "rally deployment check; "
Oleg Basov40e502c2018-09-04 20:42:21 +0200547 } else if (platform['type'] == 'k8s') {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100548 cmd_rally_init += "rally env create --name='${deployment_name}' --from-sysenv; " +
549 "rally env check; "
Oleg Basov20afb152018-06-10 03:09:25 +0200550 } else {
551 throw new Exception("Platform ${platform} is not supported yet")
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800552 }
Oleg Basov1fa6c662019-03-05 22:04:01 +0100553
554 // set up rally task args file
Oleg Basov06fce2a2018-11-09 21:39:03 +0100555 switch(tasks_args_file) {
556 case 'none':
Oleg Basovde899e02019-03-26 12:31:27 +0100557 cmd_rally_task_args = ''
Oleg Basov20afb152018-06-10 03:09:25 +0200558 break
Oleg Basov06fce2a2018-11-09 21:39:03 +0100559 case '':
Oleg Basovde899e02019-03-26 12:31:27 +0100560 cmd_rally_task_args = "--task-args-file ${scenariosDir}/job-params-light.yaml"
Oleg Basov06fce2a2018-11-09 21:39:03 +0100561 break
562 default:
Oleg Basovde899e02019-03-26 12:31:27 +0100563 cmd_rally_task_args = "--task-args-file ${scenariosDir}/${tasks_args_file}"
Oleg Basov06fce2a2018-11-09 21:39:03 +0100564 break
565 }
Oleg Basovde899e02019-03-26 12:31:27 +0100566
567 // configure Rally for Stacklight (only with Openstack for now)
568 if (platform['stacklight']['enabled'] && (platform['type'] == 'openstack')) {
569 if (! sl_scenarios) {
570 throw new Exception("There's no Stacklight scenarios to execute")
571 }
572 def scenBundle = "${resultsDir}/scenarios_${platform.type}_stacklight.yaml"
573 cmd_rally_stacklight = bundle_up_scenarios(
574 scenariosDir + '/' + sl_scenarios,
Oleg Basov1fa6c662019-03-05 22:04:01 +0100575 skip_list,
Oleg Basovde899e02019-03-26 12:31:27 +0100576 scenBundle,
Oleg Basov1fa6c662019-03-05 22:04:01 +0100577 )
Oleg Basovde899e02019-03-26 12:31:27 +0100578 tags.add('stacklight')
579 cmd_rally_stacklight += "sed -i 's/grafana_password: .*/grafana_password: ${platform.stacklight.grafanaPass}/' " +
580 "${scenariosDir}/${tasks_args_file}; rally --log-file ${resultsDir}/tasks_stacklight.log task start --tag " + tags.join(' ') +
581 " --task ${scenBundle} ${cmd_rally_task_args} || true "
Oleg Basov20afb152018-06-10 03:09:25 +0200582 }
Oleg Basovaaeb51f2018-10-17 01:07:10 +0200583
Oleg Basovde899e02019-03-26 12:31:27 +0100584 // prepare scenarios and rally task cmd
585 if (scenarios) {
586 switch (platform['type']) {
587 case 'openstack':
588 def scenBundle = "${resultsDir}/scenarios_${platform.type}.yaml"
589 cmd_rally_start = bundle_up_scenarios(
590 scenariosDir + '/' + scenarios,
591 skip_list,
592 scenBundle,
593 )
594 cmd_rally_start += "rally --log-file ${resultsDir}/tasks_openstack.log task start --tag " + tags.join(' ') +
595 " --task ${scenBundle} ${cmd_rally_task_args} || true; "
596 break
597 // due to the bug in Rally threads, K8S plugin gets stuck on big all-in-one scenarios
598 // so we have to feed them separately for K8S case
599 case 'k8s':
600 cmd_rally_start = 'for task in $(' +
601 bundle_up_scenarios(scenariosDir + '/' + scenarios, skip_list) + '); do ' +
602 "rally --log-file ${resultsDir}/tasks_k8s.log task start --tag " + tags.join(' ') +
603 ' --task $task ' + cmd_rally_task_args + ' || true; done; '
604 break
605 }
606 } else {
607 if (! cmd_rally_stacklight) {
608 throw new Exception("No scenarios found to run Rally on")
609 }
Oleg Basov1fa6c662019-03-05 22:04:01 +0100610 }
611
Oleg Basovde899e02019-03-26 12:31:27 +0100612 // compile full rally cmd map
613 def full_cmd = [
614 '001_install_plugins': "sudo pip install --upgrade ${pluginsDir}",
615 '002_init_rally': cmd_rally_init,
616 '003_start_rally': cmd_rally_start ?: "echo no tasks to run",
617 '004_start_rally_stacklight': cmd_rally_stacklight ?: "echo no tasks to run",
Oleg Basov698bec72019-05-28 11:49:16 +0200618 '005_rally_report': cmd_rally_report ?: "echo no tasks to run",
Oleg Basovde899e02019-03-26 12:31:27 +0100619 ]
620
621 return full_cmd
622
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700623}
624
625/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500626 * DEPRECATED
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700627 * Generate test report
628 *
629 * @param target Host to run script from
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700630 * @param dockerImageLink Docker image link
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700631 * @param output_dir Directory for results
Sergey Galkind1068e22018-02-13 13:59:32 +0400632 * @param results The reports directory
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700633 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400634def generateTestReport(master, target, dockerImageLink, output_dir, results = '/root/qa_results') {
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700635 def report_file = 'jenkins_test_report.html'
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700636 def salt = new com.mirantis.mk.Salt()
637 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500638 common.errorMsg('You are using deprecated method! This method will be removed')
639 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700640 def dest_folder = '/opt/devops-qa-tools/generate_test_report/test_results'
641 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
642 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
643 def reports = ['report-tempest.json',
644 'report-rally.xml',
645 'report-k8s-e2e-tests.txt',
646 'report-ha.json',
647 'report-spt.txt']
648 for ( report in reports ) {
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700649 if ( fileExists("${output_dir}${report}") ) {
650 common.infoMsg("Copying ${report} to docker container")
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700651 def items = sh(script: "base64 -w0 ${output_dir}${report} > ${output_dir}${report}_encoded; " +
652 "split -b 100KB -d -a 4 ${output_dir}${report}_encoded ${output_dir}${report}__; " +
653 "rm ${output_dir}${report}_encoded; " +
654 "find ${output_dir} -type f -name ${report}__* -printf \'%f\\n\' | sort", returnStdout: true)
655 for ( item in items.tokenize() ) {
656 def content = sh(script: "cat ${output_dir}${item}", returnStdout: true)
657 salt.cmdRun(master, target, "echo \"${content}\" >> ${results}/${report}_encoded", false, null, false)
658 sh(script: "rm ${output_dir}${item}")
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700659 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700660 salt.cmdRun(master, target, "base64 -d ${results}/${report}_encoded > ${results}/${report}; " +
661 "rm ${results}/${report}_encoded", false, null, false)
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700662 }
663 }
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700664
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700665 def cmd = "jenkins_report.py --path /opt/devops-qa-tools/generate_test_report/; " +
666 "cp ${report_file} ${dest_folder}/${report_file}"
667 salt.cmdRun(master, target, "docker run -i --rm --net=host " +
668 "-v ${results}:${dest_folder} ${dockerImageLink} " +
669 "/bin/bash -c \"${cmd}\"")
670 def report_content = salt.getFileContent(master, target, "${results}/${report_file}")
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700671 writeFile file: "${output_dir}${report_file}", text: report_content
672}
673
674/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500675 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700676 * Execute SPT tests
677 *
678 * @param target Host to run tests
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700679 * @param dockerImageLink Docker image link
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700680 * @param output_dir Directory for results
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700681 * @param ext_variables The list of external variables
Sergey Galkind1068e22018-02-13 13:59:32 +0400682 * @param results The reports directory
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700683 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400684def runSptTests(master, target, dockerImageLink, output_dir, ext_variables = [], results = '/root/qa_results') {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700685 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500686 def common = new com.mirantis.mk.Common()
687 common.errorMsg('You are using deprecated method! This method will be removed')
688 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700689 def dest_folder = '/home/rally/qa_results'
690 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
691 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
692 def nodes = getNodeList(master)
693 def nodes_hw = getNodeList(master, 'G@virtual:physical')
694 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
695 def keystone = _pillar['return'][0].values()[0]
696 def ssh_key = salt.getFileContent(master, 'I@salt:master', '/root/.ssh/id_rsa')
697 def env_vars = ( ['tempest_version=15.0.0',
698 "OS_USERNAME=${keystone.admin_name}",
699 "OS_PASSWORD=${keystone.admin_password}",
700 "OS_TENANT_NAME=${keystone.admin_tenant}",
701 "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0",
702 "OS_REGION_NAME=${keystone.region}",
703 'OS_ENDPOINT_TYPE=admin'] + ext_variables ).join(' -e ')
704 salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes.json", nodes])
705 salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes_hw.json", nodes_hw])
706 def cmd = '/opt/devops-qa-tools/deployment/configure.sh; ' +
707 'sudo mkdir -p /root/.ssh; sudo chmod 700 /root/.ssh; ' +
708 "echo \\\"${ssh_key}\\\" | sudo tee /root/.ssh/id_rsa > /dev/null; " +
709 'sudo chmod 600 /root/.ssh/id_rsa; ' +
710 "sudo timmy -c simplified-performance-testing/config.yaml " +
711 "--nodes-json ${dest_folder}/nodes.json --log-file ${dest_folder}/docker-spt2.log; " +
712 "./simplified-performance-testing/SPT_parser.sh > ${dest_folder}/report-spt.txt; " +
713 "custom_spt_parser.sh ${dest_folder}/nodes_hw.json > ${dest_folder}/report-spt-hw.txt; " +
714 "cp /tmp/timmy/archives/general.tar.gz ${dest_folder}/results-spt.tar.gz"
715 salt.cmdRun(master, target, "docker run -i --rm --net=host -e ${env_vars} " +
716 "-v ${results}:${dest_folder} ${dockerImageLink} /bin/bash -c " +
717 "\"${cmd}\" > ${results}/docker-spt.log")
718 addFiles(master, target, results, output_dir)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700719}
720
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700721/**
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600722 * Configure docker container
723 *
724 * @param target Host to run container
725 * @param proxy Proxy for accessing github and pip
726 * @param testing_tools_repo Repo with testing tools: configuration script, skip-list, etc.
Oleksii Zhurba1579b972017-12-14 15:21:56 -0600727 * @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.
728 * @param tempest_endpoint_type internalURL or adminURL or publicURL to use in tests
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500729 * @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 -0600730 * @param conf_script_path Path to configuration script.
731 * @param ext_variables Some custom extra variables to add into container
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600732 */
733def configureContainer(master, target, proxy, testing_tools_repo, tempest_repo,
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500734 tempest_endpoint_type="internalURL", tempest_version="",
Oleksii Zhurba1579b972017-12-14 15:21:56 -0600735 conf_script_path="", ext_variables = []) {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600736 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500737 def common = new com.mirantis.mk.Common()
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600738 if (testing_tools_repo != "" ) {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500739 workdir = ''
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500740 if (testing_tools_repo.contains('http://') || testing_tools_repo.contains('https://')) {
741 salt.cmdRun(master, target, "docker exec cvp git clone ${testing_tools_repo} cvp-configuration")
742 configure_script = conf_script_path != "" ? conf_script_path : "cvp-configuration/configure.sh"
743 }
744 else {
745 configure_script = testing_tools_repo
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500746 workdir = ' -w /var/lib/'
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500747 }
748 ext_variables.addAll("PROXY=${proxy}", "TEMPEST_REPO=${tempest_repo}",
749 "TEMPEST_ENDPOINT_TYPE=${tempest_endpoint_type}",
750 "tempest_version=${tempest_version}")
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500751 salt.cmdRun(master, target, "docker exec -e " + ext_variables.join(' -e ') + " ${workdir} cvp bash -c ${configure_script}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600752 }
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500753 else {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500754 common.infoMsg("TOOLS_REPO is empty, no configuration is needed for this container")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500755 }
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600756}
757
758/**
759 * Run Tempest
760 *
761 * @param target Host to run container
762 * @param test_pattern Test pattern to run
763 * @param skip_list Path to skip-list
764 * @param output_dir Directory on target host for storing results (containers is not a good place)
765 */
766def runCVPtempest(master, target, test_pattern="set=smoke", skip_list="", output_dir, output_filename="docker-tempest") {
767 def salt = new com.mirantis.mk.Salt()
768 def xml_file = "${output_filename}.xml"
Oleksii Zhurba44045312017-12-12 15:38:26 -0600769 def html_file = "${output_filename}.html"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600770 skip_list_cmd = ''
771 if (skip_list != '') {
772 skip_list_cmd = "--skip-list ${skip_list}"
773 }
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500774 salt.cmdRun(master, target, "docker exec cvp rally verify start --pattern ${test_pattern} ${skip_list_cmd} --detailed")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600775 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 -0600776 salt.cmdRun(master, target, "docker exec cvp rally verify report --type html --to /home/rally/${html_file}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600777 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${xml_file} ${output_dir}")
Oleksii Zhurba44045312017-12-12 15:38:26 -0600778 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500779 return salt.cmdRun(master, target, "docker exec cvp rally verify show | head -5 | tail -1 | " +
780 "awk '{print \$4}'")['return'][0].values()[0].split()[0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600781}
782
783/**
784 * Run Rally
785 *
786 * @param target Host to run container
787 * @param test_pattern Test pattern to run
788 * @param scenarios_path Path to Rally scenarios
789 * @param output_dir Directory on target host for storing results (containers is not a good place)
790 */
791def runCVPrally(master, target, scenarios_path, output_dir, output_filename="docker-rally") {
792 def salt = new com.mirantis.mk.Salt()
793 def xml_file = "${output_filename}.xml"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600794 def html_file = "${output_filename}.html"
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500795 salt.cmdRun(master, target, "docker exec cvp rally task start ${scenarios_path}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600796 salt.cmdRun(master, target, "docker exec cvp rally task report --out ${html_file}")
Oleksii Zhurba1bf9be12018-01-17 15:20:00 -0600797 salt.cmdRun(master, target, "docker exec cvp rally task report --junit --out ${xml_file}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600798 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${xml_file} ${output_dir}")
799 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${html_file} ${output_dir}")
800}
801
802
803/**
804 * Shutdown node
805 *
806 * @param target Host to run command
807 * @param mode How to shutdown node
808 * @param retries # of retries to make to check node status
809 */
810def shutdown_vm_node(master, target, mode, retries=200) {
811 def salt = new com.mirantis.mk.Salt()
812 def common = new com.mirantis.mk.Common()
813 if (mode == 'reboot') {
814 try {
815 def out = salt.runSaltCommand(master, 'local', ['expression': target, 'type': 'compound'], 'cmd.run', null, ['reboot'], null, 3, 3)
816 } catch (Exception e) {
817 common.warningMsg('Timeout from minion: node must be rebooting now')
818 }
819 common.warningMsg("Checking that minion is down")
820 status = "True"
821 for (i = 0; i < retries; i++) {
822 status = salt.minionsReachable(master, 'I@salt:master', target, null, 5, 1)
823 if (status != "True") {
824 break
825 }
826 }
827 if (status == "True") {
828 throw new Exception("Tired to wait for minion ${target} to stop responding")
829 }
830 }
831 if (mode == 'hard_shutdown' || mode == 'soft_shutdown') {
832 kvm = locate_node_on_kvm(master, target)
833 if (mode == 'soft_shutdown') {
834 salt.cmdRun(master, target, "shutdown -h 0")
835 }
836 if (mode == 'hard_shutdown') {
837 salt.cmdRun(master, kvm, "virsh destroy ${target}")
838 }
839 common.warningMsg("Checking that vm on kvm is in power off state")
840 status = 'running'
841 for (i = 0; i < retries; i++) {
842 status = check_vm_status(master, target, kvm)
843 echo "Current status - ${status}"
844 if (status != 'running') {
845 break
846 }
847 sleep (1)
848 }
849 if (status == 'running') {
850 throw new Exception("Tired to wait for node ${target} to shutdown")
851 }
852 }
853}
854
855
856/**
857 * Locate kvm where target host is located
858 *
859 * @param target Host to check
860 */
861def locate_node_on_kvm(master, target) {
862 def salt = new com.mirantis.mk.Salt()
863 def list = salt.runSaltProcessStep(master, "I@salt:control", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
864 for (item in list.keySet()) {
865 if (list[item]) {
866 return item
867 }
868 }
869}
870
871/**
872 * Check target host status
873 *
874 * @param target Host to check
875 * @param kvm KVM node where target host is located
876 */
877def check_vm_status(master, target, kvm) {
878 def salt = new com.mirantis.mk.Salt()
879 def list = salt.runSaltProcessStep(master, "${kvm}", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
880 for (item in list.keySet()) {
881 if (list[item]) {
882 return list[item].split()[2]
883 }
884 }
885}
886
887/**
888 * Find vip on nodes
889 *
890 * @param target Pattern, e.g. ctl*
891 */
892def get_vip_node(master, target) {
893 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba5f73cf62018-08-03 16:11:10 -0500894 def list = salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["ip a | grep '/32'"])['return'][0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600895 for (item in list.keySet()) {
896 if (list[item]) {
897 return item
898 }
899 }
900}
901
902/**
903 * Find vip on nodes
904 *
905 * @param target Host with cvp container
906 */
Oleksii Zhurba5250a9c2018-03-21 15:47:03 -0500907def openstack_cleanup(master, target, script_path="/home/rally/cvp-configuration/cleanup.sh") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600908 def salt = new com.mirantis.mk.Salt()
909 salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["docker exec cvp bash -c ${script_path}"])
910}
911
912
913/**
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700914 * Cleanup
915 *
916 * @param target Host to run commands
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500917 * @param name Name of container to remove
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700918 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500919def runCleanup(master, target, name='cvp') {
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700920 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500921 if ( salt.cmdRun(master, target, "docker ps -f name=${name} -q", false, null, false)['return'][0].values()[0] ) {
922 salt.cmdRun(master, target, "docker rm -f ${name}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600923 }
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700924}
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500925/**
926 * Prepare venv for any python project
927 * Note: <repo_name>\/requirements.txt content will be used
928 * for this venv
929 *
930 * @param repo_url Repository url to clone
931 * @param proxy Proxy address to use
932 */
dtsapikovf2e1bb12018-11-29 18:49:48 +0400933def prepareVenv(repo_url, proxy, useSystemPackages=false) {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500934 def python = new com.mirantis.mk.Python()
935 repo_name = "${repo_url}".tokenize("/").last()
Oleksii Zhurbae711ebb2018-06-15 16:36:38 -0500936 if (repo_url.tokenize().size() > 1){
937 if (repo_url.tokenize()[1] == '-b'){
938 repo_name = repo_url.tokenize()[0].tokenize("/").last()
939 }
940 }
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500941 path_venv = "${env.WORKSPACE}/venv"
942 path_req = "${env.WORKSPACE}/${repo_name}/requirements.txt"
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500943 sh "rm -rf ${repo_name}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500944 // this is temporary W/A for offline deployments
945 // Jenkins slave image has /opt/pip-mirror/ folder
946 // where pip wheels for cvp projects are located
947 if (proxy != 'offline') {
948 withEnv(["HTTPS_PROXY=${proxy}", "HTTP_PROXY=${proxy}", "https_proxy=${proxy}", "http_proxy=${proxy}"]) {
949 sh "git clone ${repo_url}"
dtsapikovf2e1bb12018-11-29 18:49:48 +0400950 python.setupVirtualenv(path_venv, "python2", [], path_req, true, useSystemPackages)
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500951 }
952 }
953 else {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500954 sh "git clone ${repo_url}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500955 sh "virtualenv ${path_venv} --python python2"
956 python.runVirtualenvCommand(path_venv, "pip install --no-index --find-links=/opt/pip-mirror/ -r ${path_req}", true)
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500957 }
958}
959
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700960/** Install docker if needed
961 *
962 * @param target Target node to install docker pkg
963 */
964def installDocker(master, target) {
965 def salt = new com.mirantis.mk.Salt()
966 if ( ! salt.runSaltProcessStep(master, target, 'pkg.version', ["docker-engine"]) ) {
967 salt.runSaltProcessStep(master, target, 'pkg.install', ["docker.io"])
968 }
969}