blob: 1947c76ac40a59e917dae18ad25034351469e631 [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 Zhurba1fbc9562019-05-15 12:20:28 -0500732 * @param container_name Name of container to use
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600733 */
734def configureContainer(master, target, proxy, testing_tools_repo, tempest_repo,
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500735 tempest_endpoint_type="internalURL", tempest_version="",
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500736 conf_script_path="", ext_variables = [], container_name="cvp") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600737 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500738 def common = new com.mirantis.mk.Common()
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600739 if (testing_tools_repo != "" ) {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500740 workdir = ''
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500741 if (testing_tools_repo.contains('http://') || testing_tools_repo.contains('https://')) {
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500742 salt.cmdRun(master, target, "docker exec ${container_name} git clone ${testing_tools_repo} cvp-configuration")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500743 configure_script = conf_script_path != "" ? conf_script_path : "cvp-configuration/configure.sh"
744 }
745 else {
746 configure_script = testing_tools_repo
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500747 workdir = ' -w /var/lib/'
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500748 }
749 ext_variables.addAll("PROXY=${proxy}", "TEMPEST_REPO=${tempest_repo}",
750 "TEMPEST_ENDPOINT_TYPE=${tempest_endpoint_type}",
751 "tempest_version=${tempest_version}")
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500752 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 -0600753 }
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500754 else {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500755 common.infoMsg("TOOLS_REPO is empty, no configuration is needed for this container")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500756 }
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600757}
758
759/**
760 * Run Tempest
761 *
762 * @param target Host to run container
763 * @param test_pattern Test pattern to run
764 * @param skip_list Path to skip-list
765 * @param output_dir Directory on target host for storing results (containers is not a good place)
766 */
767def runCVPtempest(master, target, test_pattern="set=smoke", skip_list="", output_dir, output_filename="docker-tempest") {
768 def salt = new com.mirantis.mk.Salt()
769 def xml_file = "${output_filename}.xml"
Oleksii Zhurba44045312017-12-12 15:38:26 -0600770 def html_file = "${output_filename}.html"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600771 skip_list_cmd = ''
772 if (skip_list != '') {
773 skip_list_cmd = "--skip-list ${skip_list}"
774 }
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500775 salt.cmdRun(master, target, "docker exec cvp rally verify start --pattern ${test_pattern} ${skip_list_cmd} --detailed")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600776 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 -0600777 salt.cmdRun(master, target, "docker exec cvp rally verify report --type html --to /home/rally/${html_file}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600778 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${xml_file} ${output_dir}")
Oleksii Zhurba44045312017-12-12 15:38:26 -0600779 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500780 return salt.cmdRun(master, target, "docker exec cvp rally verify show | head -5 | tail -1 | " +
781 "awk '{print \$4}'")['return'][0].values()[0].split()[0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600782}
783
784/**
785 * Run Rally
786 *
787 * @param target Host to run container
788 * @param test_pattern Test pattern to run
789 * @param scenarios_path Path to Rally scenarios
790 * @param output_dir Directory on target host for storing results (containers is not a good place)
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500791 * @param container_name Name of container to use
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600792 */
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500793def runCVPrally(master, target, scenarios_path, output_dir, output_filename="docker-rally", container_name="cvp") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600794 def salt = new com.mirantis.mk.Salt()
795 def xml_file = "${output_filename}.xml"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600796 def html_file = "${output_filename}.html"
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500797 salt.cmdRun(master, target, "docker exec ${container_name} rally task start ${scenarios_path}")
798 salt.cmdRun(master, target, "docker exec ${container_name} rally task report --out ${html_file}")
799 salt.cmdRun(master, target, "docker exec ${container_name} rally task report --junit --out ${xml_file}")
800 salt.cmdRun(master, target, "docker cp ${container_name}:/home/rally/${xml_file} ${output_dir}")
801 salt.cmdRun(master, target, "docker cp ${container_name}:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600802}
803
804
805/**
806 * Shutdown node
807 *
808 * @param target Host to run command
809 * @param mode How to shutdown node
810 * @param retries # of retries to make to check node status
811 */
812def shutdown_vm_node(master, target, mode, retries=200) {
813 def salt = new com.mirantis.mk.Salt()
814 def common = new com.mirantis.mk.Common()
815 if (mode == 'reboot') {
816 try {
817 def out = salt.runSaltCommand(master, 'local', ['expression': target, 'type': 'compound'], 'cmd.run', null, ['reboot'], null, 3, 3)
818 } catch (Exception e) {
819 common.warningMsg('Timeout from minion: node must be rebooting now')
820 }
821 common.warningMsg("Checking that minion is down")
822 status = "True"
823 for (i = 0; i < retries; i++) {
824 status = salt.minionsReachable(master, 'I@salt:master', target, null, 5, 1)
825 if (status != "True") {
826 break
827 }
828 }
829 if (status == "True") {
830 throw new Exception("Tired to wait for minion ${target} to stop responding")
831 }
832 }
833 if (mode == 'hard_shutdown' || mode == 'soft_shutdown') {
834 kvm = locate_node_on_kvm(master, target)
835 if (mode == 'soft_shutdown') {
836 salt.cmdRun(master, target, "shutdown -h 0")
837 }
838 if (mode == 'hard_shutdown') {
839 salt.cmdRun(master, kvm, "virsh destroy ${target}")
840 }
841 common.warningMsg("Checking that vm on kvm is in power off state")
842 status = 'running'
843 for (i = 0; i < retries; i++) {
844 status = check_vm_status(master, target, kvm)
845 echo "Current status - ${status}"
846 if (status != 'running') {
847 break
848 }
849 sleep (1)
850 }
851 if (status == 'running') {
852 throw new Exception("Tired to wait for node ${target} to shutdown")
853 }
854 }
855}
856
857
858/**
859 * Locate kvm where target host is located
860 *
861 * @param target Host to check
862 */
863def locate_node_on_kvm(master, target) {
864 def salt = new com.mirantis.mk.Salt()
865 def list = salt.runSaltProcessStep(master, "I@salt:control", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
866 for (item in list.keySet()) {
867 if (list[item]) {
868 return item
869 }
870 }
871}
872
873/**
874 * Check target host status
875 *
876 * @param target Host to check
877 * @param kvm KVM node where target host is located
878 */
879def check_vm_status(master, target, kvm) {
880 def salt = new com.mirantis.mk.Salt()
881 def list = salt.runSaltProcessStep(master, "${kvm}", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
882 for (item in list.keySet()) {
883 if (list[item]) {
884 return list[item].split()[2]
885 }
886 }
887}
888
889/**
890 * Find vip on nodes
891 *
892 * @param target Pattern, e.g. ctl*
893 */
894def get_vip_node(master, target) {
895 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba5f73cf62018-08-03 16:11:10 -0500896 def list = salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["ip a | grep '/32'"])['return'][0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600897 for (item in list.keySet()) {
898 if (list[item]) {
899 return item
900 }
901 }
902}
903
904/**
905 * Find vip on nodes
906 *
907 * @param target Host with cvp container
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500908 * @param container_name Name of container
909 * @param script_path Path to cleanup script (inside container)
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600910 */
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500911def openstack_cleanup(master, target, container_name="cvp", script_path="/home/rally/cleanup.sh") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600912 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500913 salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["docker exec ${container_name} bash -c ${script_path}"])
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600914}
915
916
917/**
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700918 * Cleanup
919 *
920 * @param target Host to run commands
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500921 * @param name Name of container to remove
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700922 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500923def runCleanup(master, target, name='cvp') {
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700924 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500925 if ( salt.cmdRun(master, target, "docker ps -f name=${name} -q", false, null, false)['return'][0].values()[0] ) {
926 salt.cmdRun(master, target, "docker rm -f ${name}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600927 }
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700928}
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500929/**
930 * Prepare venv for any python project
931 * Note: <repo_name>\/requirements.txt content will be used
932 * for this venv
933 *
934 * @param repo_url Repository url to clone
935 * @param proxy Proxy address to use
936 */
dtsapikovf2e1bb12018-11-29 18:49:48 +0400937def prepareVenv(repo_url, proxy, useSystemPackages=false) {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500938 def python = new com.mirantis.mk.Python()
939 repo_name = "${repo_url}".tokenize("/").last()
Oleksii Zhurbae711ebb2018-06-15 16:36:38 -0500940 if (repo_url.tokenize().size() > 1){
941 if (repo_url.tokenize()[1] == '-b'){
942 repo_name = repo_url.tokenize()[0].tokenize("/").last()
943 }
944 }
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500945 path_venv = "${env.WORKSPACE}/venv"
946 path_req = "${env.WORKSPACE}/${repo_name}/requirements.txt"
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500947 sh "rm -rf ${repo_name}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500948 // this is temporary W/A for offline deployments
949 // Jenkins slave image has /opt/pip-mirror/ folder
950 // where pip wheels for cvp projects are located
951 if (proxy != 'offline') {
952 withEnv(["HTTPS_PROXY=${proxy}", "HTTP_PROXY=${proxy}", "https_proxy=${proxy}", "http_proxy=${proxy}"]) {
953 sh "git clone ${repo_url}"
dtsapikovf2e1bb12018-11-29 18:49:48 +0400954 python.setupVirtualenv(path_venv, "python2", [], path_req, true, useSystemPackages)
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500955 }
956 }
957 else {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500958 sh "git clone ${repo_url}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500959 sh "virtualenv ${path_venv} --python python2"
960 python.runVirtualenvCommand(path_venv, "pip install --no-index --find-links=/opt/pip-mirror/ -r ${path_req}", true)
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500961 }
962}
963
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700964/** Install docker if needed
965 *
966 * @param target Target node to install docker pkg
967 */
968def installDocker(master, target) {
969 def salt = new com.mirantis.mk.Salt()
970 if ( ! salt.runSaltProcessStep(master, target, 'pkg.version', ["docker-engine"]) ) {
971 salt.runSaltProcessStep(master, target, 'pkg.install', ["docker.io"])
972 }
973}