blob: 8f5271bf88be30b02d038aef701bd585f92aee7b [file] [log] [blame]
Sergey Kolekonovba203982016-12-21 18:32:17 +04001package com.mirantis.mk
2
3/**
4 *
5 * Openstack functions
6 *
7 */
8
9/**
Tomáš Kukrálc3964e52017-02-22 14:07:37 +010010 * Convert maps
11 *
12 */
13
14@NonCPS def entries(m) {
15 return m.collect {k, v -> [k, v]}
16}
17
18/**
Sergey Kolekonovba203982016-12-21 18:32:17 +040019 * Install OpenStack service clients in isolated environment
20 *
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000021 * @param path Path where virtualenv is created
22 * @param version Version of the OpenStack clients
Sergey Kolekonovba203982016-12-21 18:32:17 +040023 */
24
Vasyl Saienko9a2bd372020-01-13 10:00:04 +020025def setupOpenstackVirtualenv(path, version = 'latest', python="python2") {
26 def pythonLib = new com.mirantis.mk.Python()
27 pythonLib.setupDocutilsVirtualenv(path)
Sergey Kolekonovba203982016-12-21 18:32:17 +040028
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000029 def openstack_kilo_packages = [
30 //XXX: hack to fix https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1635463
31 'cliff==2.8',
32 'python-cinderclient>=1.3.1,<1.4.0',
33 'python-glanceclient>=0.19.0,<0.20.0',
34 'python-heatclient>=0.6.0,<0.7.0',
35 'python-keystoneclient>=1.6.0,<1.7.0',
36 'python-neutronclient>=2.2.6,<2.3.0',
37 'python-novaclient>=2.19.0,<2.20.0',
38 'python-swiftclient>=2.5.0,<2.6.0',
39 'python-openstackclient>=1.7.0,<1.8.0',
40 'oslo.config>=2.2.0,<2.3.0',
41 'oslo.i18n>=2.3.0,<2.4.0',
42 'oslo.serialization>=1.8.0,<1.9.0',
43 'oslo.utils>=1.4.0,<1.5.0',
Denis Egorenko97ef0fb2020-01-13 14:22:49 +040044 'docutils==0.16'
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000045 ]
Sergey Kolekonovba203982016-12-21 18:32:17 +040046
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000047 def openstack_latest_packages = [
48 //XXX: hack to fix https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1635463
49 'cliff==2.8',
50 // NOTE(vsaienko): cmd2 is dependency for cliff, since we don't using upper-contstraints
51 // we have to pin cmd2 < 0.9.0 as later versions are not compatible with python2.
52 // the same for warlock package due: https://github.com/bcwaldon/warlock/commit/4241a7a9fbccfce7eb3298c2abdf00ca2dede64a
53 // TODO(vsaienko): use upper-constraints here, as in requirements we set only lowest library
54 // versions.
55 'cmd2<0.9.0;python_version=="2.7"',
56 'cmd2>=0.9.1;python_version=="3.4"',
57 'cmd2>=0.9.1;python_version=="3.5"',
58 'warlock<=1.3.1;python_version=="2.7"',
59 'warlock>1.3.1;python_version=="3.4"',
60 'warlock>1.3.1;python_version=="3.5"',
Denis Egorenko97ef0fb2020-01-13 14:22:49 +040061 // NOTE: pin client packages to current latest to prevent
62 // downloading packages which are not support Python 2.7
63 'python-openstackclient==4.0.0',
Mykyta Karpin4ed4a812020-03-26 16:31:26 +020064 'openstacksdk<0.44.0',
Denis Egorenko97ef0fb2020-01-13 14:22:49 +040065 'python-octaviaclient==1.11.0',
Vasyl Saienkof5df2022020-01-13 18:25:44 +020066 'python-heatclient==1.18.0',
Mykyta Karpine7c78612020-09-09 11:24:41 +030067 'docutils==0.16',
68 'pyrsistent<0.17.1',
Mykyta Karpin1bdfbd22021-04-02 10:28:55 +030069 'decorator<5.0.0',
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000070 ]
Sergey Kolekonovba203982016-12-21 18:32:17 +040071
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000072 if (version == 'kilo') {
73 requirements = openstack_kilo_packages
74 } else if (version == 'liberty') {
75 requirements = openstack_kilo_packages
76 } else if (version == 'mitaka') {
77 requirements = openstack_kilo_packages
Tomáš Kukrál381a8c92017-06-21 09:01:52 +020078 } else {
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000079 requirements = openstack_latest_packages
Sergey Kolekonovba203982016-12-21 18:32:17 +040080 }
Vasyl Saienko9a2bd372020-01-13 10:00:04 +020081 pythonLib.setupVirtualenv(path, python, requirements, null, true)
Sergey Kolekonovba203982016-12-21 18:32:17 +040082}
83
84/**
85 * create connection to OpenStack API endpoint
86 *
Jakub Josef6c963762018-01-18 16:02:22 +010087 * @param path Path to created venv
Sergey Kolekonovba203982016-12-21 18:32:17 +040088 * @param url OpenStack API endpoint address
89 * @param credentialsId Credentials to the OpenStack API
90 * @param project OpenStack project to connect to
91 */
Jakub Josef6c963762018-01-18 16:02:22 +010092def createOpenstackEnv(path, url, credentialsId, project, project_domain="default",
Tomáš Kukrál381a8c92017-06-21 09:01:52 +020093 project_id="", user_domain="default", api_ver="2", cacert="/etc/ssl/certs/ca-certificates.crt") {
iberezovskiyd4240b52017-02-20 17:18:28 +040094 def common = new com.mirantis.mk.Common()
Jakub Josef6c963762018-01-18 16:02:22 +010095 rcFile = "${path}/keystonerc"
Sergey Kolekonovba203982016-12-21 18:32:17 +040096 creds = common.getPasswordCredentials(credentialsId)
Alexander Tivelkovf89a1882017-01-11 13:29:35 +030097 rc = """set +x
98export OS_USERNAME=${creds.username}
Ales Komarek0e558ee2016-12-23 13:02:55 +010099export OS_PASSWORD=${creds.password.toString()}
100export OS_TENANT_NAME=${project}
101export OS_AUTH_URL=${url}
102export OS_AUTH_STRATEGY=keystone
kairat_kushaev0a26bf72017-05-18 13:20:09 +0400103export OS_PROJECT_NAME=${project}
Jakub Josefbd927322017-05-30 13:20:27 +0000104export OS_PROJECT_ID=${project_id}
kairat_kushaev0a26bf72017-05-18 13:20:09 +0400105export OS_PROJECT_DOMAIN_ID=${project_domain}
Jakub Josefbd927322017-05-30 13:20:27 +0000106export OS_USER_DOMAIN_NAME=${user_domain}
Kirill Mashchenko234708f2017-07-20 17:00:01 +0300107export OS_IDENTITY_API_VERSION=${api_ver}
Tomáš Kukrál381a8c92017-06-21 09:01:52 +0200108export OS_CACERT=${cacert}
Alexander Tivelkovf89a1882017-01-11 13:29:35 +0300109set -x
Ales Komarek0e558ee2016-12-23 13:02:55 +0100110"""
111 writeFile file: rcFile, text: rc
112 return rcFile
Sergey Kolekonovba203982016-12-21 18:32:17 +0400113}
114
115/**
116 * Run command with OpenStack env params and optional python env
117 *
118 * @param cmd Command to be executed
119 * @param env Environmental parameters with endpoint credentials
120 * @param path Optional path to virtualenv with specific clients
121 */
122def runOpenstackCommand(cmd, venv, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400123 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400124 openstackCmd = ". ${venv}; ${cmd}"
125 if (path) {
126 output = python.runVirtualenvCommand(path, openstackCmd)
127 }
128 else {
129 echo("[Command]: ${openstackCmd}")
130 output = sh (
131 script: openstackCmd,
132 returnStdout: true
133 ).trim()
134 }
135 return output
136}
137
138/**
139 * Get OpenStack Keystone token for current credentials
140 *
141 * @param env Connection parameters for OpenStack API endpoint
142 * @param path Optional path to the custom virtualenv
143 */
144def getKeystoneToken(client, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400145 def python = new com.mirantis.mk.Python()
Jakub Josefbd927322017-05-30 13:20:27 +0000146 cmd = "openstack token issue"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400147 outputTable = runOpenstackCommand(cmd, client, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100148 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400149 return output
150}
151
152/**
Ales Komarek51b7b152017-06-27 11:14:50 +0200153 * Create OpenStack environment file
Sergey Kolekonovba203982016-12-21 18:32:17 +0400154 *
155 * @param env Connection parameters for OpenStack API endpoint
156 * @param path Optional path to the custom virtualenv
157 */
158def createHeatEnv(file, environment = [], original_file = null) {
159 if (original_file) {
160 envString = readFile file: original_file
Tomáš Kukrál03029442017-02-21 17:14:29 +0100161 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400162 envString = "parameters:\n"
163 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100164
Tomáš Kukrálc3964e52017-02-22 14:07:37 +0100165 p = entries(environment)
Tomáš Kukrálb1fe9642017-02-22 11:21:17 +0100166 for (int i = 0; i < p.size(); i++) {
167 envString = "${envString} ${p.get(i)[0]}: ${p.get(i)[1]}\n"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400168 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100169
Tomáš Kukrále19ddea2017-02-21 11:09:40 +0100170 echo("writing to env file:\n${envString}")
Sergey Kolekonovba203982016-12-21 18:32:17 +0400171 writeFile file: file, text: envString
172}
173
174/**
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200175 * Create new OpenStack Heat stack. Will wait for action to be complited in
176 * specified amount of time (by default 120min)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400177 *
178 * @param env Connection parameters for OpenStack API endpoint
179 * @param template HOT template for the new Heat stack
180 * @param environment Environmentale parameters of the new Heat stack
181 * @param name Name of the new Heat stack
182 * @param path Optional path to the custom virtualenv
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200183 * @param timeout Optional number in minutes to wait for stack action is applied.
Sergey Kolekonovba203982016-12-21 18:32:17 +0400184 */
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200185def createHeatStack(client, name, template, params = [], environment = null, path = null, action="create", timeout=120) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400186 def python = new com.mirantis.mk.Python()
Jakub Josef0a898762017-08-11 16:27:44 +0200187 def templateFile = "${env.WORKSPACE}/template/template/${template}.hot"
188 def envFile
189 def envSource
Sergey Kolekonovba203982016-12-21 18:32:17 +0400190 if (environment) {
Tomáš Kukrála1152742017-08-22 16:21:50 +0200191 envFile = "${env.WORKSPACE}/template/env/${name}.env"
192 if (environment.contains("/")) {
193 //init() returns all elements but the last in a collection.
194 def envPath = environment.tokenize("/").init().join("/")
195 if (envPath) {
196 envFile = "${env.WORKSPACE}/template/env/${envPath}/${name}.env"
197 }
Ales Komarek51b7b152017-06-27 11:14:50 +0200198 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200199 envSource = "${env.WORKSPACE}/template/env/${environment}.env"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400200 createHeatEnv(envFile, params, envSource)
Jakub Josef9a59aeb2017-08-11 15:50:20 +0200201 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400202 envFile = "${env.WORKSPACE}/template/${name}.env"
203 createHeatEnv(envFile, params)
204 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200205
Mykyta Karpincf44f812017-08-28 14:45:21 +0300206 def cmd
Vasyl Saienkob91df802019-01-23 17:22:57 +0200207 def cmd_args = "-t ${templateFile} -e ${envFile} --timeout ${timeout} --wait ${name}"
Mykyta Karpincf44f812017-08-28 14:45:21 +0300208
Tomáš Kukrála1152742017-08-22 16:21:50 +0200209 if (action == "create") {
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200210 cmd = "openstack stack create ${cmd_args}"
Tomáš Kukrála1152742017-08-22 16:21:50 +0200211 } else {
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200212 cmd = "openstack stack update ${cmd_args}"
Tomáš Kukrála1152742017-08-22 16:21:50 +0200213 }
214
Sergey Kolekonovba203982016-12-21 18:32:17 +0400215 dir("${env.WORKSPACE}/template/template") {
Vasyl Saienkod4254192019-01-23 18:02:01 +0200216 def out = runOpenstackCommand(cmd, client, path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400217 }
Sergey Kolekonovba203982016-12-21 18:32:17 +0400218}
219
220/**
Jakub Josefdb4baf22017-05-10 15:16:09 +0200221 * Returns list of stacks for stack name filter
222 *
223 * @param client Connection parameters for OpenStack API endpoint
224 * @param filter Stack name filter
225 * @param path Optional path to the custom virtualenv
226 */
227def getStacksForNameContains(client, filter, path = null){
Jakub Josef6465fca2017-05-10 16:09:20 +0200228 cmd = 'heat stack-list | awk \'NR>3 {print $4}\' | sed \'$ d\' | grep ' + filter + '|| true'
Jakub Josefdb4baf22017-05-10 15:16:09 +0200229 return runOpenstackCommand(cmd, client, path).trim().tokenize("\n")
230}
231
232
233/**
Jakub Josef5e238a22017-04-19 16:35:15 +0200234 * Get list of stack names with given stack status
235 *
Jakub Josefdb4baf22017-05-10 15:16:09 +0200236 * @param client Connection parameters for OpenStack API endpoint
Jakub Josef5e238a22017-04-19 16:35:15 +0200237 * @param status Stack status
238 * @param path Optional path to the custom virtualenv
239 */
240 def getStacksWithStatus(client, status, path = null) {
241 cmd = 'heat stack-list -f stack_status='+status+' | awk \'NR>3 {print $4}\' | sed \'$ d\''
242 return runOpenstackCommand(cmd, client, path).trim().tokenize("\n")
243 }
244
245/**
Sergey Kolekonovba203982016-12-21 18:32:17 +0400246 * Get life cycle status for existing OpenStack Heat stack
247 *
248 * @param env Connection parameters for OpenStack API endpoint
249 * @param name Name of the managed Heat stack instance
250 * @param path Optional path to the custom virtualenv
251 */
252def getHeatStackStatus(client, name, path = null) {
253 cmd = 'heat stack-list | awk -v stack='+name+' \'{if ($4==stack) print $6}\''
254 return runOpenstackCommand(cmd, client, path)
255}
256
257/**
258 * Get info about existing OpenStack Heat stack
259 *
260 * @param env Connection parameters for OpenStack API endpoint
261 * @param name Name of the managed Heat stack instance
262 * @param path Optional path to the custom virtualenv
263 */
264def getHeatStackInfo(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400265 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400266 cmd = "heat stack-show ${name}"
267 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100268 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400269 return output
270}
271
272/**
273 * Get existing OpenStack Heat stack output parameter
274 *
275 * @param env Connection parameters for OpenStack API endpoint
276 * @param name Name of the managed Heat stack
277 * @param parameter Name of the output parameter
278 * @param path Optional path to the custom virtualenv
279 */
280def getHeatStackOutputParam(env, name, outputParam, path = null) {
Vasyl Saienkoea4b2812017-07-10 10:36:03 +0000281 cmd = "heat output-show ${name} ${outputParam}"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400282 output = runOpenstackCommand(cmd, env, path)
Ales Komarekeedc2222017-01-03 10:10:03 +0100283 echo("${cmd}: ${output}")
Vasyl Saienko2a1c2de2017-07-11 11:41:53 +0300284 // NOTE(vsaienko) heatclient 1.5.1 returns output in "", while later
285 // versions returns string without "".
286 // TODO Use openstack 'stack output show' when all jobs using at least Mitaka heatclient
287 return "${output}".replaceAll('"', '')
Sergey Kolekonovba203982016-12-21 18:32:17 +0400288}
289
290/**
291 * List all resources from existing OpenStack Heat stack
292 *
293 * @param env Connection parameters for OpenStack API endpoint
294 * @param name Name of the managed Heat stack instance
295 * @param path Optional path to the custom virtualenv
Mykyta Karpin72306362018-02-08 16:40:43 +0200296 * @param depth Optional depth of stack for listing resources,
297 * 0 - do not list nested resources
Sergey Kolekonovba203982016-12-21 18:32:17 +0400298 */
Mykyta Karpin72306362018-02-08 16:40:43 +0200299def getHeatStackResources(env, name, path = null, depth = 0) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400300 def python = new com.mirantis.mk.Python()
Mykyta Karpin72306362018-02-08 16:40:43 +0200301 cmd = "heat resource-list --nested-depth ${depth} ${name}"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400302 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100303 output = python.parseTextTable(outputTable, 'list', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400304 return output
305}
306
307/**
308 * Get info about resource from existing OpenStack Heat stack
309 *
310 * @param env Connection parameters for OpenStack API endpoint
311 * @param name Name of the managed Heat stack instance
312 * @param path Optional path to the custom virtualenv
313 */
314def getHeatStackResourceInfo(env, name, resource, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400315 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400316 cmd = "heat resource-show ${name} ${resource}"
317 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100318 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400319 return output
320}
321
322/**
323 * Update existing OpenStack Heat stack
324 *
325 * @param env Connection parameters for OpenStack API endpoint
326 * @param name Name of the managed Heat stack instance
327 * @param path Optional path to the custom virtualenv
328 */
329def updateHeatStack(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400330 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400331 cmd = "heat stack-update ${name}"
332 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100333 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400334 return output
335}
336
337/**
338 * Delete existing OpenStack Heat stack
339 *
340 * @param env Connection parameters for OpenStack API endpoint
341 * @param name Name of the managed Heat stack instance
342 * @param path Optional path to the custom virtualenv
343 */
344def deleteHeatStack(env, name, path = null) {
345 cmd = "heat stack-delete ${name}"
346 outputTable = runOpenstackCommand(cmd, env, path)
347}
348
349/**
Mykyta Karpin72306362018-02-08 16:40:43 +0200350 * Return hashmap of hashes server_id:server_name of servers from OpenStack Heat stack
Sergey Kolekonovba203982016-12-21 18:32:17 +0400351 *
352 * @param env Connection parameters for OpenStack API endpoint
353 * @param name Name of the managed Heat stack instance
354 * @param path Optional path to the custom virtualenv
355 */
356def getHeatStackServers(env, name, path = null) {
Mykyta Karpin72306362018-02-08 16:40:43 +0200357 // set depth to 1000 to ensure all nested resources are shown
358 resources = getHeatStackResources(env, name, path, 1000)
359 servers = [:]
Sergey Kolekonovba203982016-12-21 18:32:17 +0400360 for (resource in resources) {
361 if (resource.resource_type == 'OS::Nova::Server') {
Mykyta Karpin67978112018-02-22 11:16:45 +0200362 server = getHeatStackResourceInfo(env, resource.stack_name, resource.resource_name, path)
Mykyta Karpin72306362018-02-08 16:40:43 +0200363 servers[server.attributes.id] = server.attributes.name
Sergey Kolekonovba203982016-12-21 18:32:17 +0400364 }
365 }
366 echo("[Stack ${name}] Servers: ${servers}")
367 return servers
368}
Jiri Broulikf8f96942018-02-15 10:03:42 +0100369
370/**
Mykyta Karpin8306a9d2018-07-27 11:34:10 +0300371 * Delete nova key pair
372 *
373 * @param env Connection parameters for OpenStack API endpoint
374 * @param name Name of the key pair to delete
375 * @param path Optional path to the custom virtualenv
376 */
377def deleteKeyPair(env, name, path = null) {
378 def common = new com.mirantis.mk.Common()
379 common.infoMsg("Removing key pair ${name}")
380 def cmd = "openstack keypair delete ${name}"
381 runOpenstackCommand(cmd, env, path)
382}
383
384/**
Oleksii Grudev69382ce2020-01-03 15:31:57 +0200385 * Check if Nova keypair exists and delete it.
386 *
387 * @param env Connection parameters for OpenStack API endpoint
388 * @param name Name of the key pair to delete
389 * @param path Path to virtualenv
390**/
391def ensureKeyPairRemoved(String name, env, path) {
392 def common = new com.mirantis.mk.Common()
393 def keypairs = runOpenstackCommand("openstack keypair list -f value -c Name", env, path).tokenize('\n')
394 if (name in keypairs) {
395 deleteKeyPair(env, name, path)
396 common.infoMsg("Keypair ${name} has been deleted")
397 } else {
398 common.warningMsg("Keypair ${name} not found")
399 }
400}
401
402/**
Mykyta Karpin8306a9d2018-07-27 11:34:10 +0300403 * Get nova key pair
404 *
405 * @param env Connection parameters for OpenStack API endpoint
406 * @param name Name of the key pair to show
407 * @param path Optional path to the custom virtualenv
408 */
409
410def getKeyPair(env, name, path = null) {
411 def common = new com.mirantis.mk.Common()
412 def cmd = "openstack keypair show ${name}"
413 def outputTable
414 try {
415 outputTable = runOpenstackCommand(cmd, env, path)
416 } catch (Exception e) {
417 common.infoMsg("Key pair ${name} not found")
418 }
419 return outputTable
420}
421
422/**
Jiri Broulikf8f96942018-02-15 10:03:42 +0100423 * Stops all services that contain specific string (for example nova,heat, etc.)
424 * @param env Salt Connection object or pepperEnv
425 * @param probe single node on which to list service names
426 * @param target all targeted nodes
427 * @param services lists of type of services to be stopped
Jiri Broulikf6daac62018-03-08 13:17:53 +0100428 * @param confirm enable/disable manual service stop confirmation
Jiri Broulikf8f96942018-02-15 10:03:42 +0100429 * @return output of salt commands
430 */
Jiri Broulik27e83052018-03-06 11:37:29 +0100431def stopServices(env, probe, target, services=[], confirm=false) {
Jiri Broulikf8f96942018-02-15 10:03:42 +0100432 def salt = new com.mirantis.mk.Salt()
Jiri Broulikf6daac62018-03-08 13:17:53 +0100433 def common = new com.mirantis.mk.Common()
Jiri Broulikf8f96942018-02-15 10:03:42 +0100434 for (s in services) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400435 def outputServicesStr = salt.getReturnValues(salt.cmdRun(env, probe, "service --status-all | grep ${s} | awk \'{print \$4}\'"))
Jiri Broulikf6daac62018-03-08 13:17:53 +0100436 def servicesList = outputServicesStr.tokenize("\n").init()
Jiri Broulik27e83052018-03-06 11:37:29 +0100437 if (confirm) {
Jiri Broulikf6daac62018-03-08 13:17:53 +0100438 if (servicesList) {
439 try {
440 input message: "Click PROCEED to stop ${servicesList}. Otherwise click ABORT to skip stopping them."
441 for (name in servicesList) {
442 if (!name.contains('Salt command')) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400443 salt.runSaltProcessStep(env, target, 'service.stop', ["${name}"])
Jiri Broulikf6daac62018-03-08 13:17:53 +0100444 }
445 }
446 } catch (Exception er) {
447 common.infoMsg("skipping stopping ${servicesList} services")
448 }
449 }
450 } else {
451 if (servicesList) {
Jiri Broulik27e83052018-03-06 11:37:29 +0100452 for (name in servicesList) {
453 if (!name.contains('Salt command')) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400454 salt.runSaltProcessStep(env, target, 'service.stop', ["${name}"])
Jiri Broulik27e83052018-03-06 11:37:29 +0100455 }
456 }
Jiri Broulikf8f96942018-02-15 10:03:42 +0100457 }
458 }
459 }
460}
461
462/**
Vasyl Saienko4129e102018-09-03 10:15:52 +0300463 * Return intersection of globally installed services and those are
464 * defined on specific target according to theirs priorities.
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200465 * By default services are added to the result list only if
466 * <service>.upgrade.enabled pillar is set to "True". However if it
467 * is needed to obtain list of upgrade services regardless of
468 * <service>.upgrade.enabled pillar value it is needed to set
469 * "upgrade_condition" param to "False".
Vasyl Saienko4129e102018-09-03 10:15:52 +0300470 *
471 * @param env Salt Connection object or env
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200472 * @param target The target node to get list of apps for
473 * @param upgrade_condition Whether to take "upgrade:enabled"
474 * service pillar into consideration
475 * when obtaining list of upgrade services
Vasyl Saienko4129e102018-09-03 10:15:52 +0300476**/
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200477def getOpenStackUpgradeServices(env, target, upgrade_condition=true){
Vasyl Saienko4129e102018-09-03 10:15:52 +0300478 def salt = new com.mirantis.mk.Salt()
479 def common = new com.mirantis.mk.Common()
480
481 def global_apps = salt.getConfig(env, 'I@salt:master:enabled:true', 'orchestration.upgrade.applications')
482 def node_apps = salt.getPillar(env, target, '__reclass__:applications')['return'][0].values()[0]
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200483 if (upgrade_condition) {
484 node_pillar = salt.getPillar(env, target)
485 }
Vasyl Saienko4129e102018-09-03 10:15:52 +0300486 def node_sorted_apps = []
487 if ( !global_apps['return'][0].values()[0].isEmpty() ) {
488 Map<String,Integer> _sorted_apps = [:]
489 for (k in global_apps['return'][0].values()[0].keySet()) {
490 if (k in node_apps) {
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200491 if (upgrade_condition) {
492 if (node_pillar['return'][0].values()[k]['upgrade']['enabled'][0] != null) {
493 if (node_pillar['return'][0].values()[k]['upgrade']['enabled'][0].toBoolean()) {
494 _sorted_apps[k] = global_apps['return'][0].values()[0][k].values()[0].toInteger()
495 }
Oleksii Grudev3116a732019-02-14 18:16:05 +0200496 }
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200497 } else {
498 _sorted_apps[k] = global_apps['return'][0].values()[0][k].values()[0].toInteger()
Oleksii Grudev3116a732019-02-14 18:16:05 +0200499 }
Vasyl Saienko4129e102018-09-03 10:15:52 +0300500 }
501 }
502 node_sorted_apps = common.SortMapByValueAsc(_sorted_apps).keySet()
503 common.infoMsg("Applications are placed in following order:"+node_sorted_apps)
504 } else {
505 common.errorMsg("No applications found.")
506 }
507
508 return node_sorted_apps
509}
510
Vasyl Saienko4129e102018-09-03 10:15:52 +0300511/**
512 * Run specified upgrade phase for all services on given node.
513 *
514 * @param env Salt Connection object or env
515 * @param target The target node to run states on.
516 * @param phase The phase name to run.
517**/
518def runOpenStackUpgradePhase(env, target, phase){
519 def salt = new com.mirantis.mk.Salt()
520 def common = new com.mirantis.mk.Common()
521
522 services = getOpenStackUpgradeServices(env, target)
523 def st
524
525 for (service in services){
526 st = "${service}.upgrade.${phase}".trim()
527 common.infoMsg("Running ${phase} for service ${st} on ${target}")
528 salt.enforceState(env, target, st)
529 }
530}
531
532
533/**
534 * Run OpenStack states on specified node.
535 *
536 * @param env Salt Connection object or env
537 * @param target The target node to run states on.
538**/
539def applyOpenstackAppsStates(env, target){
540 def salt = new com.mirantis.mk.Salt()
541 def common = new com.mirantis.mk.Common()
542
543 services = getOpenStackUpgradeServices(env, target)
544 def st
545
546 for (service in services){
547 st = "${service}".trim()
548 common.infoMsg("Running ${st} on ${target}")
549 salt.enforceState(env, target, st)
550 }
551}
552
Martin Polreich232ad902019-01-21 14:31:00 +0100553def verifyGaleraStatus(env, slave=false, checkTimeSync=false) {
Martin Polreich65864b02018-12-05 10:42:50 +0100554 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100555 def galera = new com.mirantis.mk.Galera()
556 common.warningMsg("verifyGaleraStatus method was moved to Galera class. Please change your calls accordingly.")
557 return galera.verifyGaleraStatus(env, slave, checkTimeSync)
Martin Polreich65864b02018-12-05 10:42:50 +0100558}
559
Martin Polreich9a5d6682018-12-21 16:42:06 +0100560def validateAndPrintGaleraStatusReport(env, out, minion) {
Martin Polreich65864b02018-12-05 10:42:50 +0100561 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100562 def galera = new com.mirantis.mk.Galera()
563 common.warningMsg("validateAndPrintGaleraStatusReport method was moved to Galera class. Please change your calls accordingly.")
564 return galera.validateAndPrintGaleraStatusReport(env, out, minion)
Martin Polreich65864b02018-12-05 10:42:50 +0100565}
566
Martin Polreich9a5d6682018-12-21 16:42:06 +0100567def getGaleraLastShutdownNode(env) {
Martin Polreich9a5d6682018-12-21 16:42:06 +0100568 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100569 def galera = new com.mirantis.mk.Galera()
570 common.warningMsg("getGaleraLastShutdownNode method was moved to Galera class. Please change your calls accordingly.")
571 return galera.getGaleraLastShutdownNode(env)
Martin Polreich9a5d6682018-12-21 16:42:06 +0100572}
573
Ivan Berezovskiy004cac22019-02-01 17:03:28 +0400574def restoreGaleraDb(env) {
Jiri Broulikf8f96942018-02-15 10:03:42 +0100575 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100576 def galera = new com.mirantis.mk.Galera()
577 common.warningMsg("restoreGaleraDb method was moved to Galera class. Please change your calls accordingly.")
578 return galera.restoreGaleraDb(env)
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200579}