blob: 263a933ca05b2e197b3298c5c279faa99867e157 [file] [log] [blame]
Petr Lomakin47fee0a2017-08-01 10:46:05 -07001package com.mirantis.mcp
2
3/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -05004 * DEPRECATED
Petr Lomakin47fee0a2017-08-01 10:46:05 -07005 * Tests providing functions
6 *
7 */
8
9/**
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -060010 * Run docker container with basic (keystone) parameters
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050011 * For backward compatibility. Deprecated.
12 * Will be removed soon.
Petr Lomakin47fee0a2017-08-01 10:46:05 -070013 *
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -060014 * @param target Host to run container
15 * @param dockerImageLink Docker image link. May be custom or default rally image
Petr Lomakin47fee0a2017-08-01 10:46:05 -070016 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050017def runBasicContainer(master, target, dockerImageLink="xrally/xrally-openstack:0.10.1"){
Petr Lomakin47fee0a2017-08-01 10:46:05 -070018 def salt = new com.mirantis.mk.Salt()
19 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -050020 common.errorMsg('You are using deprecated method! Please migrate to validate.runContainer. This method will be removed')
21 error('You are using deprecated method! Please migrate to validate.runContainer. This method will be removed')
Sam Stoelinga28bdb722017-09-25 18:29:59 -070022 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
23 def keystone = _pillar['return'][0].values()[0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -060024 if ( salt.cmdRun(master, target, "docker ps -f name=cvp -q", false, null, false)['return'][0].values()[0] ) {
25 salt.cmdRun(master, target, "docker rm -f cvp")
26 }
27 salt.cmdRun(master, target, "docker run -tid --net=host --name=cvp " +
28 "-u root -e OS_USERNAME=${keystone.admin_name} " +
Petr Lomakin47fee0a2017-08-01 10:46:05 -070029 "-e OS_PASSWORD=${keystone.admin_password} -e OS_TENANT_NAME=${keystone.admin_tenant} " +
30 "-e OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0 " +
Oleksii Zhurba1bf9be12018-01-17 15:20:00 -060031 "-e OS_REGION_NAME=${keystone.region} -e OS_ENDPOINT_TYPE=admin --entrypoint /bin/bash ${dockerImageLink}")
Petr Lomakin47fee0a2017-08-01 10:46:05 -070032}
33
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050034
35/**
36 * Run docker container with parameters
37 *
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050038 * @param target Host to run container
39 * @param dockerImageLink Docker image link. May be custom or default rally image
40 * @param name Name for container
41 * @param env_var Environment variables to set in container
42 * @param entrypoint Set entrypoint to /bin/bash or leave default
43 * @param mounts Map with mounts for container
Sergey Galkin7137ad02019-11-07 14:52:13 +040044 * @param output_replacing Maps with regex with should be hide from output (passwords, etc)
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050045**/
46
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050047def runContainer(Map params){
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050048 def common = new com.mirantis.mk.Common()
Sergey Galkin7137ad02019-11-07 14:52:13 +040049 defaults = ["name": "cvp", "env_var": [], "entrypoint": true, "mounts": [:], "output_replacing": []]
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050050 params = defaults + params
51 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050052 def variables = ''
53 def entry_point = ''
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050054 def tempest_conf_mount = ''
55 def mounts = ''
56 def cluster_name = salt.getPillar(params.master, 'I@salt:master', '_param:cluster_name')['return'][0].values()[0]
57 default_mounts = ["/etc/ssl/certs/": "/etc/ssl/certs/",
58 "/srv/salt/pki/${cluster_name}/": "/etc/certs",
59 "/root/test/": "/root/tempest/",
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050060 "/etc/hosts": "/etc/hosts"]
61 params.mounts = default_mounts + params.mounts
Valeriy Sakharov703992d2022-05-16 19:06:42 +040062 if ( salt.cmdRun(params.master, params.target, "docker ps -a -f name=^${params.name}\$ -q", false, null, false)['return'][0].values()[0] ) {
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050063 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 }
Sergey Galkin7137ad02019-11-07 14:52:13 +040074 salt.cmdRun(params.master, params.target,
75 "docker run -tid --net=host --name=${params.name}" +
76 "${mounts} -u root ${entry_point} ${variables} ${params.dockerImageLink}",
77 true, null, true, [],
78 params.output_replacing)
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050079}
80
Oleksii Zhurbaf1138b22019-03-26 16:15:56 -050081def runContainer(master, target, dockerImageLink, name='cvp', env_var=[], entrypoint=true, mounts=[:]){
82 def common = new com.mirantis.mk.Common()
83 common.infoMsg("This method will be deprecated. Convert you method call to use Map as input parameter")
84 // Convert to Map
85 params = ['master': master, 'target': target, 'dockerImageLink': dockerImageLink, 'name': name, 'env_var': env_var,
86 'entrypoint': entrypoint, 'mounts': mounts]
87 // Call new method with Map as parameter
88 return runContainer(params)
89}
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -050090
Petr Lomakin47fee0a2017-08-01 10:46:05 -070091/**
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -050092 * Get v2 Keystone credentials from pillars
93 *
94 */
95def _get_keystone_creds_v2(master){
96 def salt = new com.mirantis.mk.Salt()
97 def common = new com.mirantis.mk.Common()
98 def keystone = []
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -050099 _pillar = false
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500100 common.infoMsg("Fetching Keystone v2 credentials")
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500101 _response = salt.runSaltProcessStep(master, 'I@keystone:server', 'pillar.get', 'keystone:server', null, false, 1)['return'][0]
102 for (i = 0; i < _response.keySet().size(); i++) {
103 if ( _response.values()[i] ) {
104 _pillar = _response.values()[i]
105 }
106 }
107 if (_pillar) {
108 keystone.add("OS_USERNAME=${_pillar.admin_name}")
109 keystone.add("OS_PASSWORD=${_pillar.admin_password}")
110 keystone.add("OS_TENANT_NAME=${_pillar.admin_tenant}")
111 keystone.add("OS_AUTH_URL=http://${_pillar.bind.private_address}:${_pillar.bind.private_port}/v2.0")
112 keystone.add("OS_REGION_NAME=${_pillar.region}")
113 keystone.add("OS_ENDPOINT_TYPE=admin")
114 return keystone
115 }
116 else {
117 throw new Exception("Cannot fetch Keystone v2 credentials. Response: ${_response}")
118 }
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500119}
120
121/**
122 * Get v3 Keystone credentials from pillars
123 *
124 */
125def _get_keystone_creds_v3(master){
126 def salt = new com.mirantis.mk.Salt()
127 def common = new com.mirantis.mk.Common()
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500128 _pillar = false
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500129 pillar_name = 'keystone:client:os_client_config:cfgs:root:content:clouds:admin_identity'
130 common.infoMsg("Fetching Keystone v3 credentials")
Oleksii Zhurba62ca88d2019-04-29 15:25:42 -0500131 _response = salt.runSaltProcessStep(master, 'I@keystone:server', 'pillar.get', pillar_name, null, false, 1)['return'][0]
132 for (i = 0; i < _response.keySet().size(); i++) {
133 if ( _response.values()[i] ) {
134 _pillar = _response.values()[i]
135 }
136 }
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500137 def keystone = []
138 if (_pillar) {
139 keystone.add("OS_USERNAME=${_pillar.auth.username}")
140 keystone.add("OS_PASSWORD=${_pillar.auth.password}")
141 keystone.add("OS_TENANT_NAME=${_pillar.auth.project_name}")
142 keystone.add("OS_PROJECT_NAME=${_pillar.auth.project_name}")
143 keystone.add("OS_AUTH_URL=${_pillar.auth.auth_url}/v3")
144 keystone.add("OS_REGION_NAME=${_pillar.region_name}")
145 keystone.add("OS_IDENTITY_API_VERSION=${_pillar.identity_api_version}")
Oleksii Zhurbafa885ed2019-02-13 18:27:31 -0600146 keystone.add("OS_ENDPOINT_TYPE=internal")
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500147 keystone.add("OS_PROJECT_DOMAIN_NAME=${_pillar.auth.project_domain_name}")
148 keystone.add("OS_USER_DOMAIN_NAME=${_pillar.auth.user_domain_name}")
Oleksii Zhurbafa885ed2019-02-13 18:27:31 -0600149 // we mount /srv/salt/pki/${cluster_name}/:/etc/certs with certs for cvp container
150 keystone.add("OS_CACERT='/etc/certs/proxy-with-chain.crt'")
Oleksii Zhurba4bcf07f2018-09-11 15:23:18 -0500151 return keystone
152 }
153 else {
154 common.warningMsg("Failed to fetch Keystone v3 credentials")
155 return false
156 }
157}
158
159/**
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700160 * Get file content (encoded). The content encoded by Base64.
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700161 *
162 * @param target Compound target (should target only one host)
163 * @param file File path to read
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700164 * @return The encoded content of the file
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700165 */
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700166def getFileContentEncoded(master, target, file) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700167 def salt = new com.mirantis.mk.Salt()
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700168 def file_content = ''
169 def cmd = "base64 -w0 ${file} > ${file}_encoded; " +
170 "split -b 1MB -d ${file}_encoded ${file}__; " +
171 "rm ${file}_encoded"
172 salt.cmdRun(master, target, cmd, false, null, false)
173 def filename = file.tokenize('/').last()
174 def folder = file - filename
175 def parts = salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f", "name=${filename}__*"])
176 for ( part in parts['return'][0].values()[0]) {
177 def _result = salt.cmdRun(master, target, "cat ${part}", false, null, false)
178 file_content = file_content + _result['return'][0].values()[0].replaceAll('Salt command execution success','')
179 }
180 salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f", "name=${filename}__*", "delete"])
181 return file_content
182}
183
184/**
185 * Copy files from remote to local directory. The content of files will be
186 * decoded by Base64.
187 *
188 * @param target Compound target (should target only one host)
189 * @param folder The path to remote folder.
190 * @param output_dir The path to local folder.
191 */
192def addFiles(master, target, folder, output_dir) {
193 def salt = new com.mirantis.mk.Salt()
194 def _result = salt.runSaltProcessStep(master, target, 'file.find', ["${folder}", "type=f"])
195 def files = _result['return'][0].values()[0]
196 for (file in files) {
197 def file_content = getFileContentEncoded(master, target, "${file}")
198 def fileName = file.tokenize('/').last()
199 writeFile file: "${output_dir}${fileName}_encoded", text: file_content
200 def cmd = "base64 -d ${output_dir}${fileName}_encoded > ${output_dir}${fileName}; " +
201 "rm ${output_dir}${fileName}_encoded"
202 sh(script: cmd)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700203 }
204}
205
206/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500207 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700208 * Get reclass value
209 *
210 * @param target The host for which the values will be provided
211 * @param filter Parameters divided by dots
212 * @return The pillar data
213 */
214def getReclassValue(master, target, filter) {
215 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500216 common.errorMsg('You are using deprecated method! This method will be removed')
217 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700218 def salt = new com.mirantis.mk.Salt()
219 def items = filter.tokenize('.')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700220 def _result = salt.cmdRun(master, 'I@salt:master', "reclass-salt -o json -p ${target}", false, null, false)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700221 _result = common.parseJSON(_result['return'][0].values()[0])
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700222 for (int k = 0; k < items.size(); k++) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700223 if ( _result ) {
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700224 _result = _result["${items[k]}"]
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700225 }
226 }
227 return _result
228}
229
230/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500231 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700232 * Create list of nodes in JSON format.
233 *
234 * @param filter The Salt's matcher
235 * @return JSON list of nodes
236 */
237def getNodeList(master, filter = null) {
238 def salt = new com.mirantis.mk.Salt()
239 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500240 common.errorMsg('You are using deprecated method! This method will be removed')
241 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700242 def nodes = []
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700243 def filtered_list = null
244 def controllers = salt.getMinions(master, 'I@nova:controller')
245 def hw_nodes = salt.getMinions(master, 'G@virtual:physical')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700246 if ( filter ) {
247 filtered_list = salt.getMinions(master, filter)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700248 }
249 def _result = salt.cmdRun(master, 'I@salt:master', "reclass-salt -o json -t", false, null, false)
250 def reclass_top = common.parseJSON(_result['return'][0].values()[0])
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700251 def nodesList = reclass_top['base'].keySet()
252 for (int i = 0; i < nodesList.size(); i++) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700253 if ( filtered_list ) {
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700254 if ( ! filtered_list.contains(nodesList[i]) ) {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700255 continue
256 }
257 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700258 def ip = getReclassValue(master, nodesList[i], '_param.linux_single_interface.address')
259 def network_data = [ip: ip, name: 'management']
260 def roles = [nodesList[i].tokenize('.')[0]]
261 if ( controllers.contains(nodesList[i]) ) {
262 roles.add('controller')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700263 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700264 if ( hw_nodes.contains(nodesList[i]) ) {
265 roles.add('hw_node')
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700266 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700267 nodes.add([id: i+1, ip: ip, roles: roles, network_data: [network_data]])
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700268 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700269 return common.prettify(nodes)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700270}
271
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500272/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500273 * DEPRECATED
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500274 * Execute mcp sanity tests
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500275 * Deprecated. Will be removed soon
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500276 *
277 * @param salt_url Salt master url
278 * @param salt_credentials Salt credentials
279 * @param test_set Test set for mcp sanity framework
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600280 * @param env_vars Additional environment variables for cvp-sanity-checks
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500281 * @param output_dir Directory for results
282 */
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600283def runSanityTests(salt_url, salt_credentials, test_set="", output_dir="validation_artifacts/", env_vars="") {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500284 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500285 common.errorMsg('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
286 error('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
Oleksii Zhurba0a7b0702017-11-10 16:02:16 -0600287 def creds = common.getCredentials(salt_credentials)
288 def username = creds.username
289 def password = creds.password
290 def settings = ""
291 if ( env_vars != "" ) {
292 for (var in env_vars.tokenize(";")) {
293 settings += "export ${var}; "
294 }
295 }
296 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${settings}" +
Ievgeniia Zadorozhnac2152172019-10-11 13:23:46 +0300297 "pytest --junitxml ${output_dir}cvp_sanity.xml --tb=short -rs -sv ${env.WORKSPACE}/cvp-sanity-checks/cvp_checks/tests/${test_set}"
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500298 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
299 def statusCode = sh script:script, returnStatus:true
300 }
301}
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700302
303/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500304 * DEPRECATED
Oleksii Zhurba4e366ff2018-02-16 20:06:52 -0600305 * Execute pytest framework tests
306 *
307 * @param salt_url Salt master url
308 * @param salt_credentials Salt credentials
309 * @param test_set Test set to run
310 * @param env_vars Additional environment variables for cvp-sanity-checks
311 * @param output_dir Directory for results
312 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500313def runPyTests(salt_url, salt_credentials, test_set="", env_vars="", name='cvp', container_node="", remote_dir='/root/qa_results/', artifacts_dir='validation_artifacts/') {
314 def xml_file = "${name}_report.xml"
315 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500316 common.errorMsg('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
317 error('You are using deprecated method! Please migrate to validate.runTests. This method will be removed')
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500318 def salt = new com.mirantis.mk.Salt()
319 def creds = common.getCredentials(salt_credentials)
320 def username = creds.username
321 def password = creds.password
322 if (container_node != "") {
323 def saltMaster
324 saltMaster = salt.connection(salt_url, salt_credentials)
325 def script = "pytest --junitxml ${xml_file} --tb=short -sv ${test_set}"
326 env_vars.addAll("SALT_USERNAME=${username}", "SALT_PASSWORD=${password}",
327 "SALT_URL=${salt_url}")
328 variables = ' -e ' + env_vars.join(' -e ')
329 salt.cmdRun(saltMaster, container_node, "docker exec ${variables} ${name} bash -c '${script}'", false)
330 salt.cmdRun(saltMaster, container_node, "docker cp ${name}:/var/lib/${xml_file} ${remote_dir}${xml_file}")
331 addFiles(saltMaster, container_node, remote_dir+xml_file, artifacts_dir)
332 }
333 else {
334 if (env_vars.size() > 0) {
335 variables = 'export ' + env_vars.join(';export ')
336 }
337 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${variables}; " +
338 "pytest --junitxml ${artifacts_dir}${xml_file} --tb=short -sv ${env.WORKSPACE}/${test_set}"
339 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
340 def statusCode = sh script:script, returnStatus:true
341 }
342 }
343}
344
345/**
346 * Execute pytest framework tests
347 * For backward compatibility
348 * Will be removed soon
349 *
350 * @param salt_url Salt master url
351 * @param salt_credentials Salt credentials
352 * @param test_set Test set to run
353 * @param env_vars Additional environment variables for cvp-sanity-checks
354 * @param output_dir Directory for results
355 */
Oleksii Zhurba4e366ff2018-02-16 20:06:52 -0600356def runTests(salt_url, salt_credentials, test_set="", output_dir="validation_artifacts/", env_vars="") {
357 def common = new com.mirantis.mk.Common()
358 def creds = common.getCredentials(salt_credentials)
359 def username = creds.username
360 def password = creds.password
361 def settings = ""
362 if ( env_vars != "" ) {
363 for (var in env_vars.tokenize(";")) {
364 settings += "export ${var}; "
365 }
366 }
367 def script = ". ${env.WORKSPACE}/venv/bin/activate; ${settings}" +
Ievgeniia Zadorozhnac2152172019-10-11 13:23:46 +0300368 "pytest --junitxml ${output_dir}report.xml --tb=short -rs -sv ${env.WORKSPACE}/${test_set}"
Oleksii Zhurba4e366ff2018-02-16 20:06:52 -0600369 withEnv(["SALT_USERNAME=${username}", "SALT_PASSWORD=${password}", "SALT_URL=${salt_url}"]) {
370 def statusCode = sh script:script, returnStatus:true
371 }
372}
373
374/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500375 * DEPRECATED
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700376 * Execute tempest tests
377 *
378 * @param target Host to run tests
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700379 * @param dockerImageLink Docker image link
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700380 * @param pattern If not false, will run only tests matched the pattern
381 * @param output_dir Directory for results
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800382 * @param confRepository Git repository with configuration files for Tempest
383 * @param confBranch Git branch which will be used during the checkout
384 * @param repository Git repository with Tempest
385 * @param version Version of Tempest (tag, branch or commit)
Sergey Galkind1068e22018-02-13 13:59:32 +0400386 * @param results The reports directory
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700387 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400388def runTempestTests(master, target, dockerImageLink, output_dir, confRepository, confBranch, repository, version, pattern = "false", results = '/root/qa_results') {
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700389 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500390 def common = new com.mirantis.mk.Common()
391 common.errorMsg('You are using deprecated method! This method will be removed')
392 error('You are using deprecated method! This method will be removed')
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700393 def output_file = 'docker-tempest.log'
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700394 def dest_folder = '/home/rally/qa_results'
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800395 def skip_list = '--skip-list /opt/devops-qa-tools/deployment/skip_contrail.list'
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700396 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
397 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
398 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
399 def keystone = _pillar['return'][0].values()[0]
Dmitry Tsapikovb6911922018-07-24 15:21:23 +0000400 def env_vars = ['tempest_version=15.0.0',
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700401 "OS_USERNAME=${keystone.admin_name}",
402 "OS_PASSWORD=${keystone.admin_password}",
403 "OS_TENANT_NAME=${keystone.admin_tenant}",
404 "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0",
405 "OS_REGION_NAME=${keystone.region}",
406 'OS_ENDPOINT_TYPE=admin'].join(' -e ')
407 def cmd = '/opt/devops-qa-tools/deployment/configure.sh; '
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800408 if (confRepository != '' ) {
409 cmd = "git clone -b ${confBranch ?: 'master'} ${confRepository} test_config; " +
410 'rally deployment create --fromenv --name=tempest; rally deployment config; ' +
411 'rally verify create-verifier --name tempest_verifier --type tempest ' +
Dmitry Tsapikovb6911922018-07-24 15:21:23 +0000412 "--source ${repository ?: '/tmp/tempest/'} --version ${version: '15.0.0'}; " +
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800413 'rally verify configure-verifier --extend test_config/tempest/tempest.conf --show; '
414 skip_list = '--skip-list test_config/tempest/skip-list.yaml'
415 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700416 if (pattern == 'false') {
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800417 cmd += "rally verify start --pattern set=full ${skip_list} --detailed; "
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700418 }
419 else {
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800420 cmd += "rally verify start --pattern set=${pattern} ${skip_list} --detailed; "
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700421 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700422 cmd += "rally verify report --type json --to ${dest_folder}/report-tempest.json; " +
423 "rally verify report --type html --to ${dest_folder}/report-tempest.html"
mkraynovd49daf52018-07-12 16:11:14 +0400424 salt.cmdRun(master, target, "docker run -w /home/rally -i --rm --net=host -e ${env_vars} " +
Sergey Galkin193ef872017-11-29 14:20:35 +0400425 "-v ${results}:${dest_folder} --entrypoint /bin/bash ${dockerImageLink} " +
426 "-c \"${cmd}\" > ${results}/${output_file}")
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700427 addFiles(master, target, results, output_dir)
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700428}
429
430/**
Oleg Basov40e502c2018-09-04 20:42:21 +0200431 * Make all-in-one scenario cmd for rally tests
432 *
433 * @param scenarios_path Path to scenarios folder/file
434 * @param skip_scenarios Comma-delimited list of scenarios names to skip
435 * @param bundle_file Bundle name to create
436*/
Oleg Basov06fce2a2018-11-09 21:39:03 +0100437def bundle_up_scenarios(scenarios_path, skip_scenarios, bundle_file = '' ) {
Oleg Basov40e502c2018-09-04 20:42:21 +0200438 def skip_names = ''
439 def skip_dirs = ''
440 def result = ''
441 if (skip_scenarios != ''){
442 for ( scen in skip_scenarios.split(',') ) {
443 if ( scen.contains('yaml')) {
444 skip_names += "! -name ${scen} "
445 }
446 else {
Oleg Basovde899e02019-03-26 12:31:27 +0100447 skip_dirs += "-path '${scenarios_path}/${scen}' -prune -o "
Oleg Basov40e502c2018-09-04 20:42:21 +0200448 }
449 }
450 }
Oleg Basov06fce2a2018-11-09 21:39:03 +0100451 if (bundle_file != '') {
452 result = "if [ -f ${scenarios_path} ]; then cp ${scenarios_path} ${bundle_file}; " +
Oleg Basov40e502c2018-09-04 20:42:21 +0200453 "else " +
454 "find -L ${scenarios_path} " + skip_dirs +
455 " -name '*.yaml' " + skip_names +
456 "-exec cat {} >> ${bundle_file} \\; ; " +
457 "sed -i '/---/d' ${bundle_file}; fi; "
Oleg Basov06fce2a2018-11-09 21:39:03 +0100458 } else {
459 result = "find -L ${scenarios_path} " + skip_dirs +
Oleg Basovde899e02019-03-26 12:31:27 +0100460 " -name '*.yaml' -print " + skip_names
Oleg Basov06fce2a2018-11-09 21:39:03 +0100461 }
Oleg Basov40e502c2018-09-04 20:42:21 +0200462
463 return result
464}
465
466/**
Oleg Basovde899e02019-03-26 12:31:27 +0100467 * Prepare setupDockerAndTest() commands to start Rally tests (optionally with K8S/Stacklight plugins)
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700468 *
Oleg Basovde899e02019-03-26 12:31:27 +0100469 * @param platform Map with underlay platform data
Oleg Basov20afb152018-06-10 03:09:25 +0200470 * @param scenarios Directory inside repo with specific scenarios
Oleg Basov40e502c2018-09-04 20:42:21 +0200471 * @param sl_scenarios Directory inside repo with specific scenarios for stacklight
Oleg Basov20afb152018-06-10 03:09:25 +0200472 * @param tasks_args_file Argument file that is used for throttling settings
Oleg Basov1fa6c662019-03-05 22:04:01 +0100473 * @param db_connection_str Rally-compliant external DB connection string
474 * @param tags Additional tags used for tagging tasks or building trends
475 * @param trends Build rally trends if enabled
Oleg Basovde899e02019-03-26 12:31:27 +0100476 *
477 * Returns: map
478 *
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700479 */
Oleg Basov1fa6c662019-03-05 22:04:01 +0100480def runRallyTests(
Oleg Basov698bec72019-05-28 11:49:16 +0200481 platform, scenarios = '', sl_scenarios = '',
482 tasks_args_file = '', db_connection_str = '', tags = [],
483 trends = false, skip_list = '', generateReport = true
Oleg Basovde899e02019-03-26 12:31:27 +0100484 ) {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100485
Oleg Basovde899e02019-03-26 12:31:27 +0100486 def dest_folder = '/home/rally'
487 def pluginsDir = "${dest_folder}/rally-plugins"
488 def scenariosDir = "${dest_folder}/rally-scenarios"
489 def resultsDir = "${dest_folder}/test_results"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100490 def date = new Date()
491 date = date.format("yyyyMMddHHmm")
Oleg Basovde899e02019-03-26 12:31:27 +0100492 // compile rally deployment name
493 deployment_name = "env=${platform.cluster_name}:platform=${platform.type}:" +
494 "date=${date}:cmp=${platform.cmp_count}"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100495
Oleg Basovde899e02019-03-26 12:31:27 +0100496 // set up Rally DB
497 def cmd_rally_init = ''
Oleg Basov1fa6c662019-03-05 22:04:01 +0100498 if (db_connection_str) {
499 cmd_rally_init = "sudo sed -i -e " +
500 "'s#connection=.*#connection=${db_connection_str}#' " +
501 "/etc/rally/rally.conf; "
502 }
Oleg Basovde899e02019-03-26 12:31:27 +0100503 cmd_rally_init += 'rally db ensure; '
504 // if several jobs are running in parallel (same deployment name),
505 // then try to find and use existing in db env
506 if (db_connection_str) {
507 cmd_rally_init += 'rally env use --env $(rally env list|awk \'/' +
508 deployment_name + '/ {print $2}\') ||'
509 }
510
511 def cmd_rally_start
512 def cmd_rally_stacklight
513 def cmd_rally_task_args = tasks_args_file ?: 'job-params-light.yaml'
Oleg Basov698bec72019-05-28 11:49:16 +0200514 def cmd_rally_report = ''
Oleg Basov1fa6c662019-03-05 22:04:01 +0100515 def cmd_filter_tags = ''
Oleg Basovde899e02019-03-26 12:31:27 +0100516 def trends_limit = 20
Oleg Basov1fa6c662019-03-05 22:04:01 +0100517
Oleg Basov698bec72019-05-28 11:49:16 +0200518 // generate html report if required
519 if (generateReport) {
520 cmd_rally_report = 'rally task export ' +
521 '--uuid $(rally task list --uuids-only --status finished) ' +
522 "--type junit-xml --to ${resultsDir}/report-rally.xml; " +
523 'rally task report --uuid $(rally task list --uuids-only --status finished) ' +
524 "--out ${resultsDir}/report-rally.html; "
525 }
526
Oleg Basov1fa6c662019-03-05 22:04:01 +0100527 // build rally trends if required
528 if (trends && db_connection_str) {
529 if (tags) {
530 cmd_filter_tags = "--tag " + tags.join(' ')
531 }
Oleg Basov698bec72019-05-28 11:49:16 +0200532 cmd_rally_report += 'rally task trends --tasks ' +
Oleg Basovde899e02019-03-26 12:31:27 +0100533 '$(rally task list ' + cmd_filter_tags +
534 ' --all-deployments --uuids-only --status finished ' +
535 "| head -${trends_limit} ) " +
536 "--out ${resultsDir}/trends-rally.html"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100537 }
538
539 // add default env tags for inserting into rally tasks
540 tags = tags + [
Oleg Basovde899e02019-03-26 12:31:27 +0100541 "env=${platform.cluster_name}",
Oleg Basov1fa6c662019-03-05 22:04:01 +0100542 "platform=${platform.type}",
Oleg Basovde899e02019-03-26 12:31:27 +0100543 "cmp=${platform.cmp_count}"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100544 ]
545
Oleg Basovde899e02019-03-26 12:31:27 +0100546 // set up rally deployment cmd
Oleg Basov40e502c2018-09-04 20:42:21 +0200547 if (platform['type'] == 'openstack') {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100548 cmd_rally_init += "rally deployment create --name='${deployment_name}' --fromenv; " +
549 "rally deployment check; "
Oleg Basov40e502c2018-09-04 20:42:21 +0200550 } else if (platform['type'] == 'k8s') {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100551 cmd_rally_init += "rally env create --name='${deployment_name}' --from-sysenv; " +
552 "rally env check; "
Oleg Basov20afb152018-06-10 03:09:25 +0200553 } else {
554 throw new Exception("Platform ${platform} is not supported yet")
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800555 }
Oleg Basov1fa6c662019-03-05 22:04:01 +0100556
557 // set up rally task args file
Oleg Basov06fce2a2018-11-09 21:39:03 +0100558 switch(tasks_args_file) {
559 case 'none':
Oleg Basovde899e02019-03-26 12:31:27 +0100560 cmd_rally_task_args = ''
Oleg Basov20afb152018-06-10 03:09:25 +0200561 break
Oleg Basov06fce2a2018-11-09 21:39:03 +0100562 case '':
Oleg Basovde899e02019-03-26 12:31:27 +0100563 cmd_rally_task_args = "--task-args-file ${scenariosDir}/job-params-light.yaml"
Oleg Basov06fce2a2018-11-09 21:39:03 +0100564 break
565 default:
Oleg Basovde899e02019-03-26 12:31:27 +0100566 cmd_rally_task_args = "--task-args-file ${scenariosDir}/${tasks_args_file}"
Oleg Basov06fce2a2018-11-09 21:39:03 +0100567 break
568 }
Oleg Basovde899e02019-03-26 12:31:27 +0100569
570 // configure Rally for Stacklight (only with Openstack for now)
571 if (platform['stacklight']['enabled'] && (platform['type'] == 'openstack')) {
572 if (! sl_scenarios) {
573 throw new Exception("There's no Stacklight scenarios to execute")
574 }
575 def scenBundle = "${resultsDir}/scenarios_${platform.type}_stacklight.yaml"
576 cmd_rally_stacklight = bundle_up_scenarios(
577 scenariosDir + '/' + sl_scenarios,
Oleg Basov1fa6c662019-03-05 22:04:01 +0100578 skip_list,
Oleg Basovde899e02019-03-26 12:31:27 +0100579 scenBundle,
Oleg Basov1fa6c662019-03-05 22:04:01 +0100580 )
Oleg Basovde899e02019-03-26 12:31:27 +0100581 tags.add('stacklight')
582 cmd_rally_stacklight += "sed -i 's/grafana_password: .*/grafana_password: ${platform.stacklight.grafanaPass}/' " +
583 "${scenariosDir}/${tasks_args_file}; rally --log-file ${resultsDir}/tasks_stacklight.log task start --tag " + tags.join(' ') +
584 " --task ${scenBundle} ${cmd_rally_task_args} || true "
Oleg Basov20afb152018-06-10 03:09:25 +0200585 }
Oleg Basovaaeb51f2018-10-17 01:07:10 +0200586
Oleg Basovde899e02019-03-26 12:31:27 +0100587 // prepare scenarios and rally task cmd
588 if (scenarios) {
589 switch (platform['type']) {
590 case 'openstack':
591 def scenBundle = "${resultsDir}/scenarios_${platform.type}.yaml"
592 cmd_rally_start = bundle_up_scenarios(
593 scenariosDir + '/' + scenarios,
594 skip_list,
595 scenBundle,
596 )
597 cmd_rally_start += "rally --log-file ${resultsDir}/tasks_openstack.log task start --tag " + tags.join(' ') +
598 " --task ${scenBundle} ${cmd_rally_task_args} || true; "
599 break
600 // due to the bug in Rally threads, K8S plugin gets stuck on big all-in-one scenarios
601 // so we have to feed them separately for K8S case
602 case 'k8s':
603 cmd_rally_start = 'for task in $(' +
604 bundle_up_scenarios(scenariosDir + '/' + scenarios, skip_list) + '); do ' +
605 "rally --log-file ${resultsDir}/tasks_k8s.log task start --tag " + tags.join(' ') +
606 ' --task $task ' + cmd_rally_task_args + ' || true; done; '
607 break
608 }
609 } else {
610 if (! cmd_rally_stacklight) {
611 throw new Exception("No scenarios found to run Rally on")
612 }
Oleg Basov1fa6c662019-03-05 22:04:01 +0100613 }
614
Oleg Basovde899e02019-03-26 12:31:27 +0100615 // compile full rally cmd map
616 def full_cmd = [
617 '001_install_plugins': "sudo pip install --upgrade ${pluginsDir}",
618 '002_init_rally': cmd_rally_init,
619 '003_start_rally': cmd_rally_start ?: "echo no tasks to run",
620 '004_start_rally_stacklight': cmd_rally_stacklight ?: "echo no tasks to run",
Oleg Basov698bec72019-05-28 11:49:16 +0200621 '005_rally_report': cmd_rally_report ?: "echo no tasks to run",
Oleg Basovde899e02019-03-26 12:31:27 +0100622 ]
623
624 return full_cmd
625
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700626}
627
628/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500629 * DEPRECATED
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700630 * Generate test report
631 *
632 * @param target Host to run script from
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700633 * @param dockerImageLink Docker image link
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700634 * @param output_dir Directory for results
Sergey Galkind1068e22018-02-13 13:59:32 +0400635 * @param results The reports directory
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700636 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400637def generateTestReport(master, target, dockerImageLink, output_dir, results = '/root/qa_results') {
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700638 def report_file = 'jenkins_test_report.html'
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700639 def salt = new com.mirantis.mk.Salt()
640 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500641 common.errorMsg('You are using deprecated method! This method will be removed')
642 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700643 def dest_folder = '/opt/devops-qa-tools/generate_test_report/test_results'
644 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
645 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
646 def reports = ['report-tempest.json',
647 'report-rally.xml',
648 'report-k8s-e2e-tests.txt',
649 'report-ha.json',
650 'report-spt.txt']
651 for ( report in reports ) {
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700652 if ( fileExists("${output_dir}${report}") ) {
653 common.infoMsg("Copying ${report} to docker container")
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700654 def items = sh(script: "base64 -w0 ${output_dir}${report} > ${output_dir}${report}_encoded; " +
655 "split -b 100KB -d -a 4 ${output_dir}${report}_encoded ${output_dir}${report}__; " +
656 "rm ${output_dir}${report}_encoded; " +
657 "find ${output_dir} -type f -name ${report}__* -printf \'%f\\n\' | sort", returnStdout: true)
658 for ( item in items.tokenize() ) {
659 def content = sh(script: "cat ${output_dir}${item}", returnStdout: true)
660 salt.cmdRun(master, target, "echo \"${content}\" >> ${results}/${report}_encoded", false, null, false)
661 sh(script: "rm ${output_dir}${item}")
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700662 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700663 salt.cmdRun(master, target, "base64 -d ${results}/${report}_encoded > ${results}/${report}; " +
664 "rm ${results}/${report}_encoded", false, null, false)
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700665 }
666 }
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700667
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700668 def cmd = "jenkins_report.py --path /opt/devops-qa-tools/generate_test_report/; " +
669 "cp ${report_file} ${dest_folder}/${report_file}"
670 salt.cmdRun(master, target, "docker run -i --rm --net=host " +
671 "-v ${results}:${dest_folder} ${dockerImageLink} " +
672 "/bin/bash -c \"${cmd}\"")
673 def report_content = salt.getFileContent(master, target, "${results}/${report_file}")
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700674 writeFile file: "${output_dir}${report_file}", text: report_content
675}
676
677/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500678 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700679 * Execute SPT tests
680 *
681 * @param target Host to run tests
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700682 * @param dockerImageLink Docker image link
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700683 * @param output_dir Directory for results
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700684 * @param ext_variables The list of external variables
Sergey Galkind1068e22018-02-13 13:59:32 +0400685 * @param results The reports directory
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700686 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400687def runSptTests(master, target, dockerImageLink, output_dir, ext_variables = [], results = '/root/qa_results') {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700688 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500689 def common = new com.mirantis.mk.Common()
690 common.errorMsg('You are using deprecated method! This method will be removed')
691 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700692 def dest_folder = '/home/rally/qa_results'
693 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
694 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
695 def nodes = getNodeList(master)
696 def nodes_hw = getNodeList(master, 'G@virtual:physical')
697 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
698 def keystone = _pillar['return'][0].values()[0]
699 def ssh_key = salt.getFileContent(master, 'I@salt:master', '/root/.ssh/id_rsa')
700 def env_vars = ( ['tempest_version=15.0.0',
701 "OS_USERNAME=${keystone.admin_name}",
702 "OS_PASSWORD=${keystone.admin_password}",
703 "OS_TENANT_NAME=${keystone.admin_tenant}",
704 "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0",
705 "OS_REGION_NAME=${keystone.region}",
706 'OS_ENDPOINT_TYPE=admin'] + ext_variables ).join(' -e ')
707 salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes.json", nodes])
708 salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes_hw.json", nodes_hw])
709 def cmd = '/opt/devops-qa-tools/deployment/configure.sh; ' +
710 'sudo mkdir -p /root/.ssh; sudo chmod 700 /root/.ssh; ' +
711 "echo \\\"${ssh_key}\\\" | sudo tee /root/.ssh/id_rsa > /dev/null; " +
712 'sudo chmod 600 /root/.ssh/id_rsa; ' +
713 "sudo timmy -c simplified-performance-testing/config.yaml " +
714 "--nodes-json ${dest_folder}/nodes.json --log-file ${dest_folder}/docker-spt2.log; " +
715 "./simplified-performance-testing/SPT_parser.sh > ${dest_folder}/report-spt.txt; " +
716 "custom_spt_parser.sh ${dest_folder}/nodes_hw.json > ${dest_folder}/report-spt-hw.txt; " +
717 "cp /tmp/timmy/archives/general.tar.gz ${dest_folder}/results-spt.tar.gz"
718 salt.cmdRun(master, target, "docker run -i --rm --net=host -e ${env_vars} " +
719 "-v ${results}:${dest_folder} ${dockerImageLink} /bin/bash -c " +
720 "\"${cmd}\" > ${results}/docker-spt.log")
721 addFiles(master, target, results, output_dir)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700722}
723
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700724/**
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600725 * Configure docker container
726 *
727 * @param target Host to run container
728 * @param proxy Proxy for accessing github and pip
729 * @param testing_tools_repo Repo with testing tools: configuration script, skip-list, etc.
Oleksii Zhurba1579b972017-12-14 15:21:56 -0600730 * @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.
731 * @param tempest_endpoint_type internalURL or adminURL or publicURL to use in tests
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500732 * @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 -0600733 * @param conf_script_path Path to configuration script.
734 * @param ext_variables Some custom extra variables to add into container
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500735 * @param container_name Name of container to use
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600736 */
737def configureContainer(master, target, proxy, testing_tools_repo, tempest_repo,
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500738 tempest_endpoint_type="internalURL", tempest_version="",
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500739 conf_script_path="", ext_variables = [], container_name="cvp") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600740 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500741 def common = new com.mirantis.mk.Common()
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600742 if (testing_tools_repo != "" ) {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500743 workdir = ''
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500744 if (testing_tools_repo.contains('http://') || testing_tools_repo.contains('https://')) {
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500745 salt.cmdRun(master, target, "docker exec ${container_name} git clone ${testing_tools_repo} cvp-configuration")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500746 configure_script = conf_script_path != "" ? conf_script_path : "cvp-configuration/configure.sh"
747 }
748 else {
749 configure_script = testing_tools_repo
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500750 workdir = ' -w /var/lib/'
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500751 }
752 ext_variables.addAll("PROXY=${proxy}", "TEMPEST_REPO=${tempest_repo}",
753 "TEMPEST_ENDPOINT_TYPE=${tempest_endpoint_type}",
754 "tempest_version=${tempest_version}")
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500755 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 -0600756 }
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500757 else {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500758 common.infoMsg("TOOLS_REPO is empty, no configuration is needed for this container")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500759 }
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600760}
761
762/**
763 * Run Tempest
764 *
765 * @param target Host to run container
766 * @param test_pattern Test pattern to run
767 * @param skip_list Path to skip-list
768 * @param output_dir Directory on target host for storing results (containers is not a good place)
769 */
770def runCVPtempest(master, target, test_pattern="set=smoke", skip_list="", output_dir, output_filename="docker-tempest") {
771 def salt = new com.mirantis.mk.Salt()
772 def xml_file = "${output_filename}.xml"
Oleksii Zhurba44045312017-12-12 15:38:26 -0600773 def html_file = "${output_filename}.html"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600774 skip_list_cmd = ''
775 if (skip_list != '') {
776 skip_list_cmd = "--skip-list ${skip_list}"
777 }
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500778 salt.cmdRun(master, target, "docker exec cvp rally verify start --pattern ${test_pattern} ${skip_list_cmd} --detailed")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600779 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 -0600780 salt.cmdRun(master, target, "docker exec cvp rally verify report --type html --to /home/rally/${html_file}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600781 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${xml_file} ${output_dir}")
Oleksii Zhurba44045312017-12-12 15:38:26 -0600782 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500783 return salt.cmdRun(master, target, "docker exec cvp rally verify show | head -5 | tail -1 | " +
784 "awk '{print \$4}'")['return'][0].values()[0].split()[0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600785}
786
787/**
788 * Run Rally
789 *
790 * @param target Host to run container
791 * @param test_pattern Test pattern to run
792 * @param scenarios_path Path to Rally scenarios
793 * @param output_dir Directory on target host for storing results (containers is not a good place)
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500794 * @param container_name Name of container to use
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600795 */
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500796def runCVPrally(master, target, scenarios_path, output_dir, output_filename="docker-rally", container_name="cvp") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600797 def salt = new com.mirantis.mk.Salt()
798 def xml_file = "${output_filename}.xml"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600799 def html_file = "${output_filename}.html"
Oleksii Zhurba5efe0ea2019-05-20 14:25:49 -0500800 salt.cmdRun(master, target, "docker exec ${container_name} rally task start ${scenarios_path}", false)
801 salt.cmdRun(master, target, "docker exec ${container_name} rally task report --out /home/rally/${html_file}", false)
802 salt.cmdRun(master, target, "docker exec ${container_name} rally task report --junit --out /home/rally/${xml_file}", false)
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500803 salt.cmdRun(master, target, "docker cp ${container_name}:/home/rally/${xml_file} ${output_dir}")
804 salt.cmdRun(master, target, "docker cp ${container_name}:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600805}
806
807
808/**
809 * Shutdown node
810 *
811 * @param target Host to run command
812 * @param mode How to shutdown node
813 * @param retries # of retries to make to check node status
814 */
815def shutdown_vm_node(master, target, mode, retries=200) {
816 def salt = new com.mirantis.mk.Salt()
817 def common = new com.mirantis.mk.Common()
818 if (mode == 'reboot') {
819 try {
820 def out = salt.runSaltCommand(master, 'local', ['expression': target, 'type': 'compound'], 'cmd.run', null, ['reboot'], null, 3, 3)
821 } catch (Exception e) {
822 common.warningMsg('Timeout from minion: node must be rebooting now')
823 }
824 common.warningMsg("Checking that minion is down")
825 status = "True"
826 for (i = 0; i < retries; i++) {
827 status = salt.minionsReachable(master, 'I@salt:master', target, null, 5, 1)
828 if (status != "True") {
829 break
830 }
831 }
832 if (status == "True") {
833 throw new Exception("Tired to wait for minion ${target} to stop responding")
834 }
835 }
836 if (mode == 'hard_shutdown' || mode == 'soft_shutdown') {
837 kvm = locate_node_on_kvm(master, target)
838 if (mode == 'soft_shutdown') {
839 salt.cmdRun(master, target, "shutdown -h 0")
840 }
841 if (mode == 'hard_shutdown') {
842 salt.cmdRun(master, kvm, "virsh destroy ${target}")
843 }
844 common.warningMsg("Checking that vm on kvm is in power off state")
845 status = 'running'
846 for (i = 0; i < retries; i++) {
847 status = check_vm_status(master, target, kvm)
848 echo "Current status - ${status}"
849 if (status != 'running') {
850 break
851 }
852 sleep (1)
853 }
854 if (status == 'running') {
855 throw new Exception("Tired to wait for node ${target} to shutdown")
856 }
857 }
858}
859
860
861/**
862 * Locate kvm where target host is located
863 *
864 * @param target Host to check
865 */
866def locate_node_on_kvm(master, target) {
867 def salt = new com.mirantis.mk.Salt()
868 def list = salt.runSaltProcessStep(master, "I@salt:control", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
869 for (item in list.keySet()) {
870 if (list[item]) {
871 return item
872 }
873 }
874}
875
876/**
877 * Check target host status
878 *
879 * @param target Host to check
880 * @param kvm KVM node where target host is located
881 */
882def check_vm_status(master, target, kvm) {
883 def salt = new com.mirantis.mk.Salt()
884 def list = salt.runSaltProcessStep(master, "${kvm}", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
885 for (item in list.keySet()) {
886 if (list[item]) {
887 return list[item].split()[2]
888 }
889 }
890}
891
892/**
893 * Find vip on nodes
894 *
895 * @param target Pattern, e.g. ctl*
896 */
897def get_vip_node(master, target) {
898 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba5f73cf62018-08-03 16:11:10 -0500899 def list = salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["ip a | grep '/32'"])['return'][0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600900 for (item in list.keySet()) {
901 if (list[item]) {
902 return item
903 }
904 }
905}
906
907/**
908 * Find vip on nodes
909 *
910 * @param target Host with cvp container
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500911 * @param container_name Name of container
912 * @param script_path Path to cleanup script (inside container)
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600913 */
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500914def openstack_cleanup(master, target, container_name="cvp", script_path="/home/rally/cleanup.sh") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600915 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba81fef102019-05-20 21:40:25 -0500916 salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["docker exec ${container_name} bash -c ${script_path}"])
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600917}
918
919
920/**
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700921 * Cleanup
922 *
923 * @param target Host to run commands
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500924 * @param name Name of container to remove
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700925 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500926def runCleanup(master, target, name='cvp') {
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700927 def salt = new com.mirantis.mk.Salt()
Valeriy Sakharov703992d2022-05-16 19:06:42 +0400928 if ( salt.cmdRun(master, target, "docker ps -a -f name=^${name}\$ -q", false, null, false)['return'][0].values()[0] ) {
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500929 salt.cmdRun(master, target, "docker rm -f ${name}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600930 }
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700931}
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500932/**
933 * Prepare venv for any python project
934 * Note: <repo_name>\/requirements.txt content will be used
935 * for this venv
936 *
937 * @param repo_url Repository url to clone
938 * @param proxy Proxy address to use
939 */
dtsapikovf2e1bb12018-11-29 18:49:48 +0400940def prepareVenv(repo_url, proxy, useSystemPackages=false) {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500941 def python = new com.mirantis.mk.Python()
942 repo_name = "${repo_url}".tokenize("/").last()
Oleksii Zhurbae711ebb2018-06-15 16:36:38 -0500943 if (repo_url.tokenize().size() > 1){
944 if (repo_url.tokenize()[1] == '-b'){
945 repo_name = repo_url.tokenize()[0].tokenize("/").last()
946 }
947 }
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500948 path_venv = "${env.WORKSPACE}/venv"
949 path_req = "${env.WORKSPACE}/${repo_name}/requirements.txt"
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500950 sh "rm -rf ${repo_name}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500951 // this is temporary W/A for offline deployments
952 // Jenkins slave image has /opt/pip-mirror/ folder
953 // where pip wheels for cvp projects are located
954 if (proxy != 'offline') {
955 withEnv(["HTTPS_PROXY=${proxy}", "HTTP_PROXY=${proxy}", "https_proxy=${proxy}", "http_proxy=${proxy}"]) {
956 sh "git clone ${repo_url}"
dtsapikovf2e1bb12018-11-29 18:49:48 +0400957 python.setupVirtualenv(path_venv, "python2", [], path_req, true, useSystemPackages)
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500958 }
959 }
960 else {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500961 sh "git clone ${repo_url}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500962 sh "virtualenv ${path_venv} --python python2"
963 python.runVirtualenvCommand(path_venv, "pip install --no-index --find-links=/opt/pip-mirror/ -r ${path_req}", true)
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500964 }
965}
966
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700967/** Install docker if needed
968 *
969 * @param target Target node to install docker pkg
970 */
971def installDocker(master, target) {
972 def salt = new com.mirantis.mk.Salt()
973 if ( ! salt.runSaltProcessStep(master, target, 'pkg.version', ["docker-engine"]) ) {
974 salt.runSaltProcessStep(master, target, 'pkg.install', ["docker.io"])
975 }
976}