blob: a1079ca25a4b6c839e92ed1ab9672e85e151c483 [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 Basovde899e02019-03-26 12:31:27 +0100478 platform, scenarios = '',
479 sl_scenarios = '', tasks_args_file = '',
Oleg Basov1fa6c662019-03-05 22:04:01 +0100480 db_connection_str = '', tags = [],
Oleg Basovde899e02019-03-26 12:31:27 +0100481 trends = false, skip_list = ''
482 ) {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100483
Oleg Basovde899e02019-03-26 12:31:27 +0100484 def dest_folder = '/home/rally'
485 def pluginsDir = "${dest_folder}/rally-plugins"
486 def scenariosDir = "${dest_folder}/rally-scenarios"
487 def resultsDir = "${dest_folder}/test_results"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100488 def date = new Date()
489 date = date.format("yyyyMMddHHmm")
Oleg Basovde899e02019-03-26 12:31:27 +0100490 // compile rally deployment name
491 deployment_name = "env=${platform.cluster_name}:platform=${platform.type}:" +
492 "date=${date}:cmp=${platform.cmp_count}"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100493
Oleg Basovde899e02019-03-26 12:31:27 +0100494 // set up Rally DB
495 def cmd_rally_init = ''
Oleg Basov1fa6c662019-03-05 22:04:01 +0100496 if (db_connection_str) {
497 cmd_rally_init = "sudo sed -i -e " +
498 "'s#connection=.*#connection=${db_connection_str}#' " +
499 "/etc/rally/rally.conf; "
500 }
Oleg Basovde899e02019-03-26 12:31:27 +0100501 cmd_rally_init += 'rally db ensure; '
502 // if several jobs are running in parallel (same deployment name),
503 // then try to find and use existing in db env
504 if (db_connection_str) {
505 cmd_rally_init += 'rally env use --env $(rally env list|awk \'/' +
506 deployment_name + '/ {print $2}\') ||'
507 }
508
509 def cmd_rally_start
510 def cmd_rally_stacklight
511 def cmd_rally_task_args = tasks_args_file ?: 'job-params-light.yaml'
512 def cmd_rally_report = 'rally task export ' +
513 '--uuid $(rally task list --uuids-only --status finished) ' +
514 "--type junit-xml --to ${resultsDir}/report-rally.xml; " +
515 'rally task report --uuid $(rally task list --uuids-only --status finished) ' +
516 "--out ${resultsDir}/report-rally.html"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100517 def cmd_filter_tags = ''
Oleg Basovde899e02019-03-26 12:31:27 +0100518 def trends_limit = 20
Oleg Basov1fa6c662019-03-05 22:04:01 +0100519
520 // build rally trends if required
521 if (trends && db_connection_str) {
522 if (tags) {
523 cmd_filter_tags = "--tag " + tags.join(' ')
524 }
Oleg Basovde899e02019-03-26 12:31:27 +0100525 cmd_rally_report += '; rally task trends --tasks ' +
526 '$(rally task list ' + cmd_filter_tags +
527 ' --all-deployments --uuids-only --status finished ' +
528 "| head -${trends_limit} ) " +
529 "--out ${resultsDir}/trends-rally.html"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100530 }
531
532 // add default env tags for inserting into rally tasks
533 tags = tags + [
Oleg Basovde899e02019-03-26 12:31:27 +0100534 "env=${platform.cluster_name}",
Oleg Basov1fa6c662019-03-05 22:04:01 +0100535 "platform=${platform.type}",
Oleg Basovde899e02019-03-26 12:31:27 +0100536 "cmp=${platform.cmp_count}"
Oleg Basov1fa6c662019-03-05 22:04:01 +0100537 ]
538
Oleg Basovde899e02019-03-26 12:31:27 +0100539 // set up rally deployment cmd
Oleg Basov40e502c2018-09-04 20:42:21 +0200540 if (platform['type'] == 'openstack') {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100541 cmd_rally_init += "rally deployment create --name='${deployment_name}' --fromenv; " +
542 "rally deployment check; "
Oleg Basov40e502c2018-09-04 20:42:21 +0200543 } else if (platform['type'] == 'k8s') {
Oleg Basov1fa6c662019-03-05 22:04:01 +0100544 cmd_rally_init += "rally env create --name='${deployment_name}' --from-sysenv; " +
545 "rally env check; "
Oleg Basov20afb152018-06-10 03:09:25 +0200546 } else {
547 throw new Exception("Platform ${platform} is not supported yet")
Dmitrii Kabanov999fda92017-11-10 00:18:30 -0800548 }
Oleg Basov1fa6c662019-03-05 22:04:01 +0100549
550 // set up rally task args file
Oleg Basov06fce2a2018-11-09 21:39:03 +0100551 switch(tasks_args_file) {
552 case 'none':
Oleg Basovde899e02019-03-26 12:31:27 +0100553 cmd_rally_task_args = ''
Oleg Basov20afb152018-06-10 03:09:25 +0200554 break
Oleg Basov06fce2a2018-11-09 21:39:03 +0100555 case '':
Oleg Basovde899e02019-03-26 12:31:27 +0100556 cmd_rally_task_args = "--task-args-file ${scenariosDir}/job-params-light.yaml"
Oleg Basov06fce2a2018-11-09 21:39:03 +0100557 break
558 default:
Oleg Basovde899e02019-03-26 12:31:27 +0100559 cmd_rally_task_args = "--task-args-file ${scenariosDir}/${tasks_args_file}"
Oleg Basov06fce2a2018-11-09 21:39:03 +0100560 break
561 }
Oleg Basovde899e02019-03-26 12:31:27 +0100562
563 // configure Rally for Stacklight (only with Openstack for now)
564 if (platform['stacklight']['enabled'] && (platform['type'] == 'openstack')) {
565 if (! sl_scenarios) {
566 throw new Exception("There's no Stacklight scenarios to execute")
567 }
568 def scenBundle = "${resultsDir}/scenarios_${platform.type}_stacklight.yaml"
569 cmd_rally_stacklight = bundle_up_scenarios(
570 scenariosDir + '/' + sl_scenarios,
Oleg Basov1fa6c662019-03-05 22:04:01 +0100571 skip_list,
Oleg Basovde899e02019-03-26 12:31:27 +0100572 scenBundle,
Oleg Basov1fa6c662019-03-05 22:04:01 +0100573 )
Oleg Basovde899e02019-03-26 12:31:27 +0100574 tags.add('stacklight')
575 cmd_rally_stacklight += "sed -i 's/grafana_password: .*/grafana_password: ${platform.stacklight.grafanaPass}/' " +
576 "${scenariosDir}/${tasks_args_file}; rally --log-file ${resultsDir}/tasks_stacklight.log task start --tag " + tags.join(' ') +
577 " --task ${scenBundle} ${cmd_rally_task_args} || true "
Oleg Basov20afb152018-06-10 03:09:25 +0200578 }
Oleg Basovaaeb51f2018-10-17 01:07:10 +0200579
Oleg Basovde899e02019-03-26 12:31:27 +0100580 // prepare scenarios and rally task cmd
581 if (scenarios) {
582 switch (platform['type']) {
583 case 'openstack':
584 def scenBundle = "${resultsDir}/scenarios_${platform.type}.yaml"
585 cmd_rally_start = bundle_up_scenarios(
586 scenariosDir + '/' + scenarios,
587 skip_list,
588 scenBundle,
589 )
590 cmd_rally_start += "rally --log-file ${resultsDir}/tasks_openstack.log task start --tag " + tags.join(' ') +
591 " --task ${scenBundle} ${cmd_rally_task_args} || true; "
592 break
593 // due to the bug in Rally threads, K8S plugin gets stuck on big all-in-one scenarios
594 // so we have to feed them separately for K8S case
595 case 'k8s':
596 cmd_rally_start = 'for task in $(' +
597 bundle_up_scenarios(scenariosDir + '/' + scenarios, skip_list) + '); do ' +
598 "rally --log-file ${resultsDir}/tasks_k8s.log task start --tag " + tags.join(' ') +
599 ' --task $task ' + cmd_rally_task_args + ' || true; done; '
600 break
601 }
602 } else {
603 if (! cmd_rally_stacklight) {
604 throw new Exception("No scenarios found to run Rally on")
605 }
Oleg Basov1fa6c662019-03-05 22:04:01 +0100606 }
607
Oleg Basovde899e02019-03-26 12:31:27 +0100608 // compile full rally cmd map
609 def full_cmd = [
610 '001_install_plugins': "sudo pip install --upgrade ${pluginsDir}",
611 '002_init_rally': cmd_rally_init,
612 '003_start_rally': cmd_rally_start ?: "echo no tasks to run",
613 '004_start_rally_stacklight': cmd_rally_stacklight ?: "echo no tasks to run",
614 '005_rally_report': cmd_rally_report,
615 ]
616
617 return full_cmd
618
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700619}
620
621/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500622 * DEPRECATED
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700623 * Generate test report
624 *
625 * @param target Host to run script from
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700626 * @param dockerImageLink Docker image link
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700627 * @param output_dir Directory for results
Sergey Galkind1068e22018-02-13 13:59:32 +0400628 * @param results The reports directory
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700629 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400630def generateTestReport(master, target, dockerImageLink, output_dir, results = '/root/qa_results') {
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700631 def report_file = 'jenkins_test_report.html'
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700632 def salt = new com.mirantis.mk.Salt()
633 def common = new com.mirantis.mk.Common()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500634 common.errorMsg('You are using deprecated method! This method will be removed')
635 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700636 def dest_folder = '/opt/devops-qa-tools/generate_test_report/test_results'
637 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
638 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
639 def reports = ['report-tempest.json',
640 'report-rally.xml',
641 'report-k8s-e2e-tests.txt',
642 'report-ha.json',
643 'report-spt.txt']
644 for ( report in reports ) {
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700645 if ( fileExists("${output_dir}${report}") ) {
646 common.infoMsg("Copying ${report} to docker container")
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700647 def items = sh(script: "base64 -w0 ${output_dir}${report} > ${output_dir}${report}_encoded; " +
648 "split -b 100KB -d -a 4 ${output_dir}${report}_encoded ${output_dir}${report}__; " +
649 "rm ${output_dir}${report}_encoded; " +
650 "find ${output_dir} -type f -name ${report}__* -printf \'%f\\n\' | sort", returnStdout: true)
651 for ( item in items.tokenize() ) {
652 def content = sh(script: "cat ${output_dir}${item}", returnStdout: true)
653 salt.cmdRun(master, target, "echo \"${content}\" >> ${results}/${report}_encoded", false, null, false)
654 sh(script: "rm ${output_dir}${item}")
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700655 }
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700656 salt.cmdRun(master, target, "base64 -d ${results}/${report}_encoded > ${results}/${report}; " +
657 "rm ${results}/${report}_encoded", false, null, false)
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700658 }
659 }
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700660
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700661 def cmd = "jenkins_report.py --path /opt/devops-qa-tools/generate_test_report/; " +
662 "cp ${report_file} ${dest_folder}/${report_file}"
663 salt.cmdRun(master, target, "docker run -i --rm --net=host " +
664 "-v ${results}:${dest_folder} ${dockerImageLink} " +
665 "/bin/bash -c \"${cmd}\"")
666 def report_content = salt.getFileContent(master, target, "${results}/${report_file}")
Tetiana Korchak3383cc92017-08-25 09:36:19 -0700667 writeFile file: "${output_dir}${report_file}", text: report_content
668}
669
670/**
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500671 * DEPRECATED
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700672 * Execute SPT tests
673 *
674 * @param target Host to run tests
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700675 * @param dockerImageLink Docker image link
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700676 * @param output_dir Directory for results
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700677 * @param ext_variables The list of external variables
Sergey Galkind1068e22018-02-13 13:59:32 +0400678 * @param results The reports directory
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700679 */
Sergey Galkind1068e22018-02-13 13:59:32 +0400680def runSptTests(master, target, dockerImageLink, output_dir, ext_variables = [], results = '/root/qa_results') {
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700681 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba9c456a72019-03-26 18:05:34 -0500682 def common = new com.mirantis.mk.Common()
683 common.errorMsg('You are using deprecated method! This method will be removed')
684 error('You are using deprecated method! This method will be removed')
Dmitrii Kabanov23901c22017-10-20 10:25:36 -0700685 def dest_folder = '/home/rally/qa_results'
686 salt.runSaltProcessStep(master, target, 'file.remove', ["${results}"])
687 salt.runSaltProcessStep(master, target, 'file.mkdir', ["${results}", "mode=777"])
688 def nodes = getNodeList(master)
689 def nodes_hw = getNodeList(master, 'G@virtual:physical')
690 def _pillar = salt.getPillar(master, 'I@keystone:server', 'keystone:server')
691 def keystone = _pillar['return'][0].values()[0]
692 def ssh_key = salt.getFileContent(master, 'I@salt:master', '/root/.ssh/id_rsa')
693 def env_vars = ( ['tempest_version=15.0.0',
694 "OS_USERNAME=${keystone.admin_name}",
695 "OS_PASSWORD=${keystone.admin_password}",
696 "OS_TENANT_NAME=${keystone.admin_tenant}",
697 "OS_AUTH_URL=http://${keystone.bind.private_address}:${keystone.bind.private_port}/v2.0",
698 "OS_REGION_NAME=${keystone.region}",
699 'OS_ENDPOINT_TYPE=admin'] + ext_variables ).join(' -e ')
700 salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes.json", nodes])
701 salt.runSaltProcessStep(master, target, 'file.write', ["${results}/nodes_hw.json", nodes_hw])
702 def cmd = '/opt/devops-qa-tools/deployment/configure.sh; ' +
703 'sudo mkdir -p /root/.ssh; sudo chmod 700 /root/.ssh; ' +
704 "echo \\\"${ssh_key}\\\" | sudo tee /root/.ssh/id_rsa > /dev/null; " +
705 'sudo chmod 600 /root/.ssh/id_rsa; ' +
706 "sudo timmy -c simplified-performance-testing/config.yaml " +
707 "--nodes-json ${dest_folder}/nodes.json --log-file ${dest_folder}/docker-spt2.log; " +
708 "./simplified-performance-testing/SPT_parser.sh > ${dest_folder}/report-spt.txt; " +
709 "custom_spt_parser.sh ${dest_folder}/nodes_hw.json > ${dest_folder}/report-spt-hw.txt; " +
710 "cp /tmp/timmy/archives/general.tar.gz ${dest_folder}/results-spt.tar.gz"
711 salt.cmdRun(master, target, "docker run -i --rm --net=host -e ${env_vars} " +
712 "-v ${results}:${dest_folder} ${dockerImageLink} /bin/bash -c " +
713 "\"${cmd}\" > ${results}/docker-spt.log")
714 addFiles(master, target, results, output_dir)
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700715}
716
Dmitrii Kabanovd5f1c5f2017-08-30 14:51:41 -0700717/**
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600718 * Configure docker container
719 *
720 * @param target Host to run container
721 * @param proxy Proxy for accessing github and pip
722 * @param testing_tools_repo Repo with testing tools: configuration script, skip-list, etc.
Oleksii Zhurba1579b972017-12-14 15:21:56 -0600723 * @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.
724 * @param tempest_endpoint_type internalURL or adminURL or publicURL to use in tests
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500725 * @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 -0600726 * @param conf_script_path Path to configuration script.
727 * @param ext_variables Some custom extra variables to add into container
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500728 * @param container_name Name of container to use
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600729 */
730def configureContainer(master, target, proxy, testing_tools_repo, tempest_repo,
Oleksii Zhurba198dd682018-09-07 18:16:59 -0500731 tempest_endpoint_type="internalURL", tempest_version="",
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500732 conf_script_path="", ext_variables = [], container_name="cvp") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600733 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500734 def common = new com.mirantis.mk.Common()
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600735 if (testing_tools_repo != "" ) {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500736 workdir = ''
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500737 if (testing_tools_repo.contains('http://') || testing_tools_repo.contains('https://')) {
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500738 salt.cmdRun(master, target, "docker exec ${container_name} git clone ${testing_tools_repo} cvp-configuration")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500739 configure_script = conf_script_path != "" ? conf_script_path : "cvp-configuration/configure.sh"
740 }
741 else {
742 configure_script = testing_tools_repo
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500743 workdir = ' -w /var/lib/'
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500744 }
745 ext_variables.addAll("PROXY=${proxy}", "TEMPEST_REPO=${tempest_repo}",
746 "TEMPEST_ENDPOINT_TYPE=${tempest_endpoint_type}",
747 "tempest_version=${tempest_version}")
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500748 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 -0600749 }
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500750 else {
Oleksii Zhurba95c98852019-05-15 15:51:30 -0500751 common.infoMsg("TOOLS_REPO is empty, no configuration is needed for this container")
Oleksii Zhurba0cda6e02018-06-20 14:53:19 -0500752 }
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600753}
754
755/**
756 * Run Tempest
757 *
758 * @param target Host to run container
759 * @param test_pattern Test pattern to run
760 * @param skip_list Path to skip-list
761 * @param output_dir Directory on target host for storing results (containers is not a good place)
762 */
763def runCVPtempest(master, target, test_pattern="set=smoke", skip_list="", output_dir, output_filename="docker-tempest") {
764 def salt = new com.mirantis.mk.Salt()
765 def xml_file = "${output_filename}.xml"
Oleksii Zhurba44045312017-12-12 15:38:26 -0600766 def html_file = "${output_filename}.html"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600767 skip_list_cmd = ''
768 if (skip_list != '') {
769 skip_list_cmd = "--skip-list ${skip_list}"
770 }
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500771 salt.cmdRun(master, target, "docker exec cvp rally verify start --pattern ${test_pattern} ${skip_list_cmd} --detailed")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600772 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 -0600773 salt.cmdRun(master, target, "docker exec cvp rally verify report --type html --to /home/rally/${html_file}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600774 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${xml_file} ${output_dir}")
Oleksii Zhurba44045312017-12-12 15:38:26 -0600775 salt.cmdRun(master, target, "docker cp cvp:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba77896d42018-05-25 18:11:30 -0500776 return salt.cmdRun(master, target, "docker exec cvp rally verify show | head -5 | tail -1 | " +
777 "awk '{print \$4}'")['return'][0].values()[0].split()[0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600778}
779
780/**
781 * Run Rally
782 *
783 * @param target Host to run container
784 * @param test_pattern Test pattern to run
785 * @param scenarios_path Path to Rally scenarios
786 * @param output_dir Directory on target host for storing results (containers is not a good place)
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500787 * @param container_name Name of container to use
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600788 */
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500789def runCVPrally(master, target, scenarios_path, output_dir, output_filename="docker-rally", container_name="cvp") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600790 def salt = new com.mirantis.mk.Salt()
791 def xml_file = "${output_filename}.xml"
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600792 def html_file = "${output_filename}.html"
Oleksii Zhurba1fbc9562019-05-15 12:20:28 -0500793 salt.cmdRun(master, target, "docker exec ${container_name} rally task start ${scenarios_path}")
794 salt.cmdRun(master, target, "docker exec ${container_name} rally task report --out ${html_file}")
795 salt.cmdRun(master, target, "docker exec ${container_name} rally task report --junit --out ${xml_file}")
796 salt.cmdRun(master, target, "docker cp ${container_name}:/home/rally/${xml_file} ${output_dir}")
797 salt.cmdRun(master, target, "docker cp ${container_name}:/home/rally/${html_file} ${output_dir}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600798}
799
800
801/**
802 * Shutdown node
803 *
804 * @param target Host to run command
805 * @param mode How to shutdown node
806 * @param retries # of retries to make to check node status
807 */
808def shutdown_vm_node(master, target, mode, retries=200) {
809 def salt = new com.mirantis.mk.Salt()
810 def common = new com.mirantis.mk.Common()
811 if (mode == 'reboot') {
812 try {
813 def out = salt.runSaltCommand(master, 'local', ['expression': target, 'type': 'compound'], 'cmd.run', null, ['reboot'], null, 3, 3)
814 } catch (Exception e) {
815 common.warningMsg('Timeout from minion: node must be rebooting now')
816 }
817 common.warningMsg("Checking that minion is down")
818 status = "True"
819 for (i = 0; i < retries; i++) {
820 status = salt.minionsReachable(master, 'I@salt:master', target, null, 5, 1)
821 if (status != "True") {
822 break
823 }
824 }
825 if (status == "True") {
826 throw new Exception("Tired to wait for minion ${target} to stop responding")
827 }
828 }
829 if (mode == 'hard_shutdown' || mode == 'soft_shutdown') {
830 kvm = locate_node_on_kvm(master, target)
831 if (mode == 'soft_shutdown') {
832 salt.cmdRun(master, target, "shutdown -h 0")
833 }
834 if (mode == 'hard_shutdown') {
835 salt.cmdRun(master, kvm, "virsh destroy ${target}")
836 }
837 common.warningMsg("Checking that vm on kvm is in power off state")
838 status = 'running'
839 for (i = 0; i < retries; i++) {
840 status = check_vm_status(master, target, kvm)
841 echo "Current status - ${status}"
842 if (status != 'running') {
843 break
844 }
845 sleep (1)
846 }
847 if (status == 'running') {
848 throw new Exception("Tired to wait for node ${target} to shutdown")
849 }
850 }
851}
852
853
854/**
855 * Locate kvm where target host is located
856 *
857 * @param target Host to check
858 */
859def locate_node_on_kvm(master, target) {
860 def salt = new com.mirantis.mk.Salt()
861 def list = salt.runSaltProcessStep(master, "I@salt:control", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
862 for (item in list.keySet()) {
863 if (list[item]) {
864 return item
865 }
866 }
867}
868
869/**
870 * Check target host status
871 *
872 * @param target Host to check
873 * @param kvm KVM node where target host is located
874 */
875def check_vm_status(master, target, kvm) {
876 def salt = new com.mirantis.mk.Salt()
877 def list = salt.runSaltProcessStep(master, "${kvm}", 'cmd.run', ["virsh list --all | grep ' ${target}'"])['return'][0]
878 for (item in list.keySet()) {
879 if (list[item]) {
880 return list[item].split()[2]
881 }
882 }
883}
884
885/**
886 * Find vip on nodes
887 *
888 * @param target Pattern, e.g. ctl*
889 */
890def get_vip_node(master, target) {
891 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba5f73cf62018-08-03 16:11:10 -0500892 def list = salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["ip a | grep '/32'"])['return'][0]
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600893 for (item in list.keySet()) {
894 if (list[item]) {
895 return item
896 }
897 }
898}
899
900/**
901 * Find vip on nodes
902 *
903 * @param target Host with cvp container
904 */
Oleksii Zhurba5250a9c2018-03-21 15:47:03 -0500905def openstack_cleanup(master, target, script_path="/home/rally/cvp-configuration/cleanup.sh") {
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600906 def salt = new com.mirantis.mk.Salt()
907 salt.runSaltProcessStep(master, "${target}", 'cmd.run', ["docker exec cvp bash -c ${script_path}"])
908}
909
910
911/**
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700912 * Cleanup
913 *
914 * @param target Host to run commands
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500915 * @param name Name of container to remove
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700916 */
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500917def runCleanup(master, target, name='cvp') {
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700918 def salt = new com.mirantis.mk.Salt()
Oleksii Zhurba1f4a6ff2018-06-27 16:45:17 -0500919 if ( salt.cmdRun(master, target, "docker ps -f name=${name} -q", false, null, false)['return'][0].values()[0] ) {
920 salt.cmdRun(master, target, "docker rm -f ${name}")
Oleksii Zhurba7b44ef12017-11-13 17:50:16 -0600921 }
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700922}
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500923/**
924 * Prepare venv for any python project
925 * Note: <repo_name>\/requirements.txt content will be used
926 * for this venv
927 *
928 * @param repo_url Repository url to clone
929 * @param proxy Proxy address to use
930 */
dtsapikovf2e1bb12018-11-29 18:49:48 +0400931def prepareVenv(repo_url, proxy, useSystemPackages=false) {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500932 def python = new com.mirantis.mk.Python()
933 repo_name = "${repo_url}".tokenize("/").last()
Oleksii Zhurbae711ebb2018-06-15 16:36:38 -0500934 if (repo_url.tokenize().size() > 1){
935 if (repo_url.tokenize()[1] == '-b'){
936 repo_name = repo_url.tokenize()[0].tokenize("/").last()
937 }
938 }
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500939 path_venv = "${env.WORKSPACE}/venv"
940 path_req = "${env.WORKSPACE}/${repo_name}/requirements.txt"
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500941 sh "rm -rf ${repo_name}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500942 // this is temporary W/A for offline deployments
943 // Jenkins slave image has /opt/pip-mirror/ folder
944 // where pip wheels for cvp projects are located
945 if (proxy != 'offline') {
946 withEnv(["HTTPS_PROXY=${proxy}", "HTTP_PROXY=${proxy}", "https_proxy=${proxy}", "http_proxy=${proxy}"]) {
947 sh "git clone ${repo_url}"
dtsapikovf2e1bb12018-11-29 18:49:48 +0400948 python.setupVirtualenv(path_venv, "python2", [], path_req, true, useSystemPackages)
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500949 }
950 }
951 else {
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500952 sh "git clone ${repo_url}"
Oleksii Zhurba83e3e5c2018-06-27 16:59:29 -0500953 sh "virtualenv ${path_venv} --python python2"
954 python.runVirtualenvCommand(path_venv, "pip install --no-index --find-links=/opt/pip-mirror/ -r ${path_req}", true)
Oleksii Zhurbabcb97e22017-10-05 14:10:39 -0500955 }
956}
957
Petr Lomakin47fee0a2017-08-01 10:46:05 -0700958/** Install docker if needed
959 *
960 * @param target Target node to install docker pkg
961 */
962def installDocker(master, target) {
963 def salt = new com.mirantis.mk.Salt()
964 if ( ! salt.runSaltProcessStep(master, target, 'pkg.version', ["docker-engine"]) ) {
965 salt.runSaltProcessStep(master, target, 'pkg.install', ["docker.io"])
966 }
967}