blob: 8568ad4259adfd5ec2daa2a189735e9956e99807 [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',
Vasyl Saienkoefd68d92021-09-21 11:56:52 +030064 'python-ironicclient==3.1.2',
Mykyta Karpin4ed4a812020-03-26 16:31:26 +020065 'openstacksdk<0.44.0',
Denis Egorenko97ef0fb2020-01-13 14:22:49 +040066 'python-octaviaclient==1.11.0',
Vasyl Saienkof5df2022020-01-13 18:25:44 +020067 'python-heatclient==1.18.0',
Mykyta Karpine7c78612020-09-09 11:24:41 +030068 'docutils==0.16',
69 'pyrsistent<0.17.1',
Mykyta Karpin1bdfbd22021-04-02 10:28:55 +030070 'decorator<5.0.0',
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000071 ]
Sergey Kolekonovba203982016-12-21 18:32:17 +040072
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000073 if (version == 'kilo') {
74 requirements = openstack_kilo_packages
75 } else if (version == 'liberty') {
76 requirements = openstack_kilo_packages
77 } else if (version == 'mitaka') {
78 requirements = openstack_kilo_packages
Tomáš Kukrál381a8c92017-06-21 09:01:52 +020079 } else {
Aleksey Zvyagintsevde345a92019-07-30 11:32:45 +000080 requirements = openstack_latest_packages
Sergey Kolekonovba203982016-12-21 18:32:17 +040081 }
Vasyl Saienko9a2bd372020-01-13 10:00:04 +020082 pythonLib.setupVirtualenv(path, python, requirements, null, true)
Sergey Kolekonovba203982016-12-21 18:32:17 +040083}
84
85/**
86 * create connection to OpenStack API endpoint
87 *
Jakub Josef6c963762018-01-18 16:02:22 +010088 * @param path Path to created venv
Sergey Kolekonovba203982016-12-21 18:32:17 +040089 * @param url OpenStack API endpoint address
90 * @param credentialsId Credentials to the OpenStack API
91 * @param project OpenStack project to connect to
92 */
Jakub Josef6c963762018-01-18 16:02:22 +010093def createOpenstackEnv(path, url, credentialsId, project, project_domain="default",
Tomáš Kukrál381a8c92017-06-21 09:01:52 +020094 project_id="", user_domain="default", api_ver="2", cacert="/etc/ssl/certs/ca-certificates.crt") {
iberezovskiyd4240b52017-02-20 17:18:28 +040095 def common = new com.mirantis.mk.Common()
Jakub Josef6c963762018-01-18 16:02:22 +010096 rcFile = "${path}/keystonerc"
Sergey Kolekonovba203982016-12-21 18:32:17 +040097 creds = common.getPasswordCredentials(credentialsId)
Alexander Tivelkovf89a1882017-01-11 13:29:35 +030098 rc = """set +x
99export OS_USERNAME=${creds.username}
Ales Komarek0e558ee2016-12-23 13:02:55 +0100100export OS_PASSWORD=${creds.password.toString()}
101export OS_TENANT_NAME=${project}
102export OS_AUTH_URL=${url}
103export OS_AUTH_STRATEGY=keystone
kairat_kushaev0a26bf72017-05-18 13:20:09 +0400104export OS_PROJECT_NAME=${project}
Jakub Josefbd927322017-05-30 13:20:27 +0000105export OS_PROJECT_ID=${project_id}
kairat_kushaev0a26bf72017-05-18 13:20:09 +0400106export OS_PROJECT_DOMAIN_ID=${project_domain}
Jakub Josefbd927322017-05-30 13:20:27 +0000107export OS_USER_DOMAIN_NAME=${user_domain}
Kirill Mashchenko234708f2017-07-20 17:00:01 +0300108export OS_IDENTITY_API_VERSION=${api_ver}
Tomáš Kukrál381a8c92017-06-21 09:01:52 +0200109export OS_CACERT=${cacert}
Alexander Tivelkovf89a1882017-01-11 13:29:35 +0300110set -x
Ales Komarek0e558ee2016-12-23 13:02:55 +0100111"""
112 writeFile file: rcFile, text: rc
113 return rcFile
Sergey Kolekonovba203982016-12-21 18:32:17 +0400114}
115
116/**
117 * Run command with OpenStack env params and optional python env
118 *
119 * @param cmd Command to be executed
120 * @param env Environmental parameters with endpoint credentials
121 * @param path Optional path to virtualenv with specific clients
122 */
123def runOpenstackCommand(cmd, venv, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400124 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400125 openstackCmd = ". ${venv}; ${cmd}"
126 if (path) {
127 output = python.runVirtualenvCommand(path, openstackCmd)
128 }
129 else {
130 echo("[Command]: ${openstackCmd}")
131 output = sh (
132 script: openstackCmd,
133 returnStdout: true
134 ).trim()
135 }
136 return output
137}
138
139/**
140 * Get OpenStack Keystone token for current credentials
141 *
142 * @param env Connection parameters for OpenStack API endpoint
143 * @param path Optional path to the custom virtualenv
144 */
145def getKeystoneToken(client, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400146 def python = new com.mirantis.mk.Python()
Jakub Josefbd927322017-05-30 13:20:27 +0000147 cmd = "openstack token issue"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400148 outputTable = runOpenstackCommand(cmd, client, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100149 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400150 return output
151}
152
153/**
Ales Komarek51b7b152017-06-27 11:14:50 +0200154 * Create OpenStack environment file
Sergey Kolekonovba203982016-12-21 18:32:17 +0400155 *
156 * @param env Connection parameters for OpenStack API endpoint
157 * @param path Optional path to the custom virtualenv
158 */
159def createHeatEnv(file, environment = [], original_file = null) {
160 if (original_file) {
161 envString = readFile file: original_file
Tomáš Kukrál03029442017-02-21 17:14:29 +0100162 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400163 envString = "parameters:\n"
164 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100165
Tomáš Kukrálc3964e52017-02-22 14:07:37 +0100166 p = entries(environment)
Tomáš Kukrálb1fe9642017-02-22 11:21:17 +0100167 for (int i = 0; i < p.size(); i++) {
168 envString = "${envString} ${p.get(i)[0]}: ${p.get(i)[1]}\n"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400169 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100170
Tomáš Kukrále19ddea2017-02-21 11:09:40 +0100171 echo("writing to env file:\n${envString}")
Sergey Kolekonovba203982016-12-21 18:32:17 +0400172 writeFile file: file, text: envString
173}
174
175/**
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200176 * Create new OpenStack Heat stack. Will wait for action to be complited in
177 * specified amount of time (by default 120min)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400178 *
179 * @param env Connection parameters for OpenStack API endpoint
180 * @param template HOT template for the new Heat stack
181 * @param environment Environmentale parameters of the new Heat stack
182 * @param name Name of the new Heat stack
183 * @param path Optional path to the custom virtualenv
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200184 * @param timeout Optional number in minutes to wait for stack action is applied.
Sergey Kolekonovba203982016-12-21 18:32:17 +0400185 */
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200186def createHeatStack(client, name, template, params = [], environment = null, path = null, action="create", timeout=120) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400187 def python = new com.mirantis.mk.Python()
Jakub Josef0a898762017-08-11 16:27:44 +0200188 def templateFile = "${env.WORKSPACE}/template/template/${template}.hot"
189 def envFile
190 def envSource
Sergey Kolekonovba203982016-12-21 18:32:17 +0400191 if (environment) {
Tomáš Kukrála1152742017-08-22 16:21:50 +0200192 envFile = "${env.WORKSPACE}/template/env/${name}.env"
193 if (environment.contains("/")) {
194 //init() returns all elements but the last in a collection.
195 def envPath = environment.tokenize("/").init().join("/")
196 if (envPath) {
197 envFile = "${env.WORKSPACE}/template/env/${envPath}/${name}.env"
198 }
Ales Komarek51b7b152017-06-27 11:14:50 +0200199 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200200 envSource = "${env.WORKSPACE}/template/env/${environment}.env"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400201 createHeatEnv(envFile, params, envSource)
Jakub Josef9a59aeb2017-08-11 15:50:20 +0200202 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400203 envFile = "${env.WORKSPACE}/template/${name}.env"
204 createHeatEnv(envFile, params)
205 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200206
Mykyta Karpincf44f812017-08-28 14:45:21 +0300207 def cmd
Vasyl Saienkob91df802019-01-23 17:22:57 +0200208 def cmd_args = "-t ${templateFile} -e ${envFile} --timeout ${timeout} --wait ${name}"
Mykyta Karpincf44f812017-08-28 14:45:21 +0300209
Tomáš Kukrála1152742017-08-22 16:21:50 +0200210 if (action == "create") {
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200211 cmd = "openstack stack create ${cmd_args}"
Tomáš Kukrála1152742017-08-22 16:21:50 +0200212 } else {
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200213 cmd = "openstack stack update ${cmd_args}"
Tomáš Kukrála1152742017-08-22 16:21:50 +0200214 }
215
Sergey Kolekonovba203982016-12-21 18:32:17 +0400216 dir("${env.WORKSPACE}/template/template") {
Vasyl Saienkod4254192019-01-23 18:02:01 +0200217 def out = runOpenstackCommand(cmd, client, path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400218 }
Sergey Kolekonovba203982016-12-21 18:32:17 +0400219}
220
221/**
Jakub Josefdb4baf22017-05-10 15:16:09 +0200222 * Returns list of stacks for stack name filter
223 *
224 * @param client Connection parameters for OpenStack API endpoint
225 * @param filter Stack name filter
226 * @param path Optional path to the custom virtualenv
227 */
228def getStacksForNameContains(client, filter, path = null){
Jakub Josef6465fca2017-05-10 16:09:20 +0200229 cmd = 'heat stack-list | awk \'NR>3 {print $4}\' | sed \'$ d\' | grep ' + filter + '|| true'
Jakub Josefdb4baf22017-05-10 15:16:09 +0200230 return runOpenstackCommand(cmd, client, path).trim().tokenize("\n")
231}
232
233
234/**
Jakub Josef5e238a22017-04-19 16:35:15 +0200235 * Get list of stack names with given stack status
236 *
Jakub Josefdb4baf22017-05-10 15:16:09 +0200237 * @param client Connection parameters for OpenStack API endpoint
Jakub Josef5e238a22017-04-19 16:35:15 +0200238 * @param status Stack status
239 * @param path Optional path to the custom virtualenv
240 */
241 def getStacksWithStatus(client, status, path = null) {
242 cmd = 'heat stack-list -f stack_status='+status+' | awk \'NR>3 {print $4}\' | sed \'$ d\''
243 return runOpenstackCommand(cmd, client, path).trim().tokenize("\n")
244 }
245
246/**
Sergey Kolekonovba203982016-12-21 18:32:17 +0400247 * Get life cycle status for existing OpenStack Heat stack
248 *
249 * @param env Connection parameters for OpenStack API endpoint
250 * @param name Name of the managed Heat stack instance
251 * @param path Optional path to the custom virtualenv
252 */
253def getHeatStackStatus(client, name, path = null) {
254 cmd = 'heat stack-list | awk -v stack='+name+' \'{if ($4==stack) print $6}\''
255 return runOpenstackCommand(cmd, client, path)
256}
257
258/**
259 * Get info about existing OpenStack Heat stack
260 *
261 * @param env Connection parameters for OpenStack API endpoint
262 * @param name Name of the managed Heat stack instance
263 * @param path Optional path to the custom virtualenv
264 */
265def getHeatStackInfo(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400266 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400267 cmd = "heat stack-show ${name}"
268 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100269 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400270 return output
271}
272
273/**
274 * Get existing OpenStack Heat stack output parameter
275 *
276 * @param env Connection parameters for OpenStack API endpoint
277 * @param name Name of the managed Heat stack
278 * @param parameter Name of the output parameter
279 * @param path Optional path to the custom virtualenv
280 */
281def getHeatStackOutputParam(env, name, outputParam, path = null) {
Vasyl Saienkoea4b2812017-07-10 10:36:03 +0000282 cmd = "heat output-show ${name} ${outputParam}"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400283 output = runOpenstackCommand(cmd, env, path)
Ales Komarekeedc2222017-01-03 10:10:03 +0100284 echo("${cmd}: ${output}")
Vasyl Saienko2a1c2de2017-07-11 11:41:53 +0300285 // NOTE(vsaienko) heatclient 1.5.1 returns output in "", while later
286 // versions returns string without "".
287 // TODO Use openstack 'stack output show' when all jobs using at least Mitaka heatclient
288 return "${output}".replaceAll('"', '')
Sergey Kolekonovba203982016-12-21 18:32:17 +0400289}
290
291/**
292 * List all resources from existing OpenStack Heat stack
293 *
294 * @param env Connection parameters for OpenStack API endpoint
295 * @param name Name of the managed Heat stack instance
296 * @param path Optional path to the custom virtualenv
Mykyta Karpin72306362018-02-08 16:40:43 +0200297 * @param depth Optional depth of stack for listing resources,
298 * 0 - do not list nested resources
Sergey Kolekonovba203982016-12-21 18:32:17 +0400299 */
Mykyta Karpin72306362018-02-08 16:40:43 +0200300def getHeatStackResources(env, name, path = null, depth = 0) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400301 def python = new com.mirantis.mk.Python()
Mykyta Karpin72306362018-02-08 16:40:43 +0200302 cmd = "heat resource-list --nested-depth ${depth} ${name}"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400303 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100304 output = python.parseTextTable(outputTable, 'list', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400305 return output
306}
307
308/**
309 * Get info about resource from existing OpenStack Heat stack
310 *
311 * @param env Connection parameters for OpenStack API endpoint
312 * @param name Name of the managed Heat stack instance
313 * @param path Optional path to the custom virtualenv
314 */
315def getHeatStackResourceInfo(env, name, resource, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400316 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400317 cmd = "heat resource-show ${name} ${resource}"
318 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100319 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400320 return output
321}
322
323/**
324 * Update existing OpenStack Heat stack
325 *
326 * @param env Connection parameters for OpenStack API endpoint
327 * @param name Name of the managed Heat stack instance
328 * @param path Optional path to the custom virtualenv
329 */
330def updateHeatStack(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400331 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400332 cmd = "heat stack-update ${name}"
333 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100334 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400335 return output
336}
337
338/**
339 * Delete existing OpenStack Heat stack
340 *
341 * @param env Connection parameters for OpenStack API endpoint
342 * @param name Name of the managed Heat stack instance
343 * @param path Optional path to the custom virtualenv
344 */
345def deleteHeatStack(env, name, path = null) {
346 cmd = "heat stack-delete ${name}"
347 outputTable = runOpenstackCommand(cmd, env, path)
348}
349
350/**
Mykyta Karpin72306362018-02-08 16:40:43 +0200351 * Return hashmap of hashes server_id:server_name of servers from OpenStack Heat stack
Sergey Kolekonovba203982016-12-21 18:32:17 +0400352 *
353 * @param env Connection parameters for OpenStack API endpoint
354 * @param name Name of the managed Heat stack instance
355 * @param path Optional path to the custom virtualenv
356 */
357def getHeatStackServers(env, name, path = null) {
Mykyta Karpin72306362018-02-08 16:40:43 +0200358 // set depth to 1000 to ensure all nested resources are shown
359 resources = getHeatStackResources(env, name, path, 1000)
360 servers = [:]
Sergey Kolekonovba203982016-12-21 18:32:17 +0400361 for (resource in resources) {
362 if (resource.resource_type == 'OS::Nova::Server') {
Mykyta Karpin67978112018-02-22 11:16:45 +0200363 server = getHeatStackResourceInfo(env, resource.stack_name, resource.resource_name, path)
Mykyta Karpin72306362018-02-08 16:40:43 +0200364 servers[server.attributes.id] = server.attributes.name
Sergey Kolekonovba203982016-12-21 18:32:17 +0400365 }
366 }
367 echo("[Stack ${name}] Servers: ${servers}")
368 return servers
369}
Jiri Broulikf8f96942018-02-15 10:03:42 +0100370
371/**
Mykyta Karpin8306a9d2018-07-27 11:34:10 +0300372 * Delete nova key pair
373 *
374 * @param env Connection parameters for OpenStack API endpoint
375 * @param name Name of the key pair to delete
376 * @param path Optional path to the custom virtualenv
377 */
378def deleteKeyPair(env, name, path = null) {
379 def common = new com.mirantis.mk.Common()
380 common.infoMsg("Removing key pair ${name}")
381 def cmd = "openstack keypair delete ${name}"
382 runOpenstackCommand(cmd, env, path)
383}
384
385/**
Oleksii Grudev69382ce2020-01-03 15:31:57 +0200386 * Check if Nova keypair exists and delete it.
387 *
388 * @param env Connection parameters for OpenStack API endpoint
389 * @param name Name of the key pair to delete
390 * @param path Path to virtualenv
391**/
392def ensureKeyPairRemoved(String name, env, path) {
393 def common = new com.mirantis.mk.Common()
394 def keypairs = runOpenstackCommand("openstack keypair list -f value -c Name", env, path).tokenize('\n')
395 if (name in keypairs) {
396 deleteKeyPair(env, name, path)
397 common.infoMsg("Keypair ${name} has been deleted")
398 } else {
399 common.warningMsg("Keypair ${name} not found")
400 }
401}
402
403/**
Mykyta Karpin8306a9d2018-07-27 11:34:10 +0300404 * Get nova key pair
405 *
406 * @param env Connection parameters for OpenStack API endpoint
407 * @param name Name of the key pair to show
408 * @param path Optional path to the custom virtualenv
409 */
410
411def getKeyPair(env, name, path = null) {
412 def common = new com.mirantis.mk.Common()
413 def cmd = "openstack keypair show ${name}"
414 def outputTable
415 try {
416 outputTable = runOpenstackCommand(cmd, env, path)
417 } catch (Exception e) {
418 common.infoMsg("Key pair ${name} not found")
419 }
420 return outputTable
421}
422
423/**
Jiri Broulikf8f96942018-02-15 10:03:42 +0100424 * Stops all services that contain specific string (for example nova,heat, etc.)
425 * @param env Salt Connection object or pepperEnv
426 * @param probe single node on which to list service names
427 * @param target all targeted nodes
428 * @param services lists of type of services to be stopped
Jiri Broulikf6daac62018-03-08 13:17:53 +0100429 * @param confirm enable/disable manual service stop confirmation
Jiri Broulikf8f96942018-02-15 10:03:42 +0100430 * @return output of salt commands
431 */
Jiri Broulik27e83052018-03-06 11:37:29 +0100432def stopServices(env, probe, target, services=[], confirm=false) {
Jiri Broulikf8f96942018-02-15 10:03:42 +0100433 def salt = new com.mirantis.mk.Salt()
Jiri Broulikf6daac62018-03-08 13:17:53 +0100434 def common = new com.mirantis.mk.Common()
Jiri Broulikf8f96942018-02-15 10:03:42 +0100435 for (s in services) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400436 def outputServicesStr = salt.getReturnValues(salt.cmdRun(env, probe, "service --status-all | grep ${s} | awk \'{print \$4}\'"))
Jiri Broulikf6daac62018-03-08 13:17:53 +0100437 def servicesList = outputServicesStr.tokenize("\n").init()
Jiri Broulik27e83052018-03-06 11:37:29 +0100438 if (confirm) {
Jiri Broulikf6daac62018-03-08 13:17:53 +0100439 if (servicesList) {
440 try {
441 input message: "Click PROCEED to stop ${servicesList}. Otherwise click ABORT to skip stopping them."
442 for (name in servicesList) {
443 if (!name.contains('Salt command')) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400444 salt.runSaltProcessStep(env, target, 'service.stop', ["${name}"])
Jiri Broulikf6daac62018-03-08 13:17:53 +0100445 }
446 }
447 } catch (Exception er) {
448 common.infoMsg("skipping stopping ${servicesList} services")
449 }
450 }
451 } else {
452 if (servicesList) {
Jiri Broulik27e83052018-03-06 11:37:29 +0100453 for (name in servicesList) {
454 if (!name.contains('Salt command')) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400455 salt.runSaltProcessStep(env, target, 'service.stop', ["${name}"])
Jiri Broulik27e83052018-03-06 11:37:29 +0100456 }
457 }
Jiri Broulikf8f96942018-02-15 10:03:42 +0100458 }
459 }
460 }
461}
462
463/**
Vasyl Saienko4129e102018-09-03 10:15:52 +0300464 * Return intersection of globally installed services and those are
465 * defined on specific target according to theirs priorities.
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200466 * By default services are added to the result list only if
467 * <service>.upgrade.enabled pillar is set to "True". However if it
468 * is needed to obtain list of upgrade services regardless of
469 * <service>.upgrade.enabled pillar value it is needed to set
470 * "upgrade_condition" param to "False".
Vasyl Saienko4129e102018-09-03 10:15:52 +0300471 *
472 * @param env Salt Connection object or env
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200473 * @param target The target node to get list of apps for
474 * @param upgrade_condition Whether to take "upgrade:enabled"
475 * service pillar into consideration
476 * when obtaining list of upgrade services
Vasyl Saienko4129e102018-09-03 10:15:52 +0300477**/
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200478def getOpenStackUpgradeServices(env, target, upgrade_condition=true){
Vasyl Saienko4129e102018-09-03 10:15:52 +0300479 def salt = new com.mirantis.mk.Salt()
480 def common = new com.mirantis.mk.Common()
481
482 def global_apps = salt.getConfig(env, 'I@salt:master:enabled:true', 'orchestration.upgrade.applications')
483 def node_apps = salt.getPillar(env, target, '__reclass__:applications')['return'][0].values()[0]
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200484 if (upgrade_condition) {
485 node_pillar = salt.getPillar(env, target)
486 }
Vasyl Saienko4129e102018-09-03 10:15:52 +0300487 def node_sorted_apps = []
488 if ( !global_apps['return'][0].values()[0].isEmpty() ) {
489 Map<String,Integer> _sorted_apps = [:]
490 for (k in global_apps['return'][0].values()[0].keySet()) {
491 if (k in node_apps) {
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200492 if (upgrade_condition) {
493 if (node_pillar['return'][0].values()[k]['upgrade']['enabled'][0] != null) {
494 if (node_pillar['return'][0].values()[k]['upgrade']['enabled'][0].toBoolean()) {
495 _sorted_apps[k] = global_apps['return'][0].values()[0][k].values()[0].toInteger()
496 }
Oleksii Grudev3116a732019-02-14 18:16:05 +0200497 }
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200498 } else {
499 _sorted_apps[k] = global_apps['return'][0].values()[0][k].values()[0].toInteger()
Oleksii Grudev3116a732019-02-14 18:16:05 +0200500 }
Vasyl Saienko4129e102018-09-03 10:15:52 +0300501 }
502 }
503 node_sorted_apps = common.SortMapByValueAsc(_sorted_apps).keySet()
504 common.infoMsg("Applications are placed in following order:"+node_sorted_apps)
505 } else {
506 common.errorMsg("No applications found.")
507 }
508
509 return node_sorted_apps
510}
511
Vasyl Saienko4129e102018-09-03 10:15:52 +0300512/**
513 * Run specified upgrade phase for all services on given node.
514 *
515 * @param env Salt Connection object or env
516 * @param target The target node to run states on.
517 * @param phase The phase name to run.
518**/
519def runOpenStackUpgradePhase(env, target, phase){
520 def salt = new com.mirantis.mk.Salt()
521 def common = new com.mirantis.mk.Common()
522
523 services = getOpenStackUpgradeServices(env, target)
524 def st
525
526 for (service in services){
527 st = "${service}.upgrade.${phase}".trim()
528 common.infoMsg("Running ${phase} for service ${st} on ${target}")
529 salt.enforceState(env, target, st)
530 }
531}
532
533
534/**
535 * Run OpenStack states on specified node.
536 *
537 * @param env Salt Connection object or env
538 * @param target The target node to run states on.
539**/
540def applyOpenstackAppsStates(env, target){
541 def salt = new com.mirantis.mk.Salt()
542 def common = new com.mirantis.mk.Common()
543
544 services = getOpenStackUpgradeServices(env, target)
545 def st
546
547 for (service in services){
548 st = "${service}".trim()
549 common.infoMsg("Running ${st} on ${target}")
550 salt.enforceState(env, target, st)
551 }
552}
553
Martin Polreich232ad902019-01-21 14:31:00 +0100554def verifyGaleraStatus(env, slave=false, checkTimeSync=false) {
Martin Polreich65864b02018-12-05 10:42:50 +0100555 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100556 def galera = new com.mirantis.mk.Galera()
557 common.warningMsg("verifyGaleraStatus method was moved to Galera class. Please change your calls accordingly.")
558 return galera.verifyGaleraStatus(env, slave, checkTimeSync)
Martin Polreich65864b02018-12-05 10:42:50 +0100559}
560
Martin Polreich9a5d6682018-12-21 16:42:06 +0100561def validateAndPrintGaleraStatusReport(env, out, minion) {
Martin Polreich65864b02018-12-05 10:42:50 +0100562 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100563 def galera = new com.mirantis.mk.Galera()
564 common.warningMsg("validateAndPrintGaleraStatusReport method was moved to Galera class. Please change your calls accordingly.")
565 return galera.validateAndPrintGaleraStatusReport(env, out, minion)
Martin Polreich65864b02018-12-05 10:42:50 +0100566}
567
Martin Polreich9a5d6682018-12-21 16:42:06 +0100568def getGaleraLastShutdownNode(env) {
Martin Polreich9a5d6682018-12-21 16:42:06 +0100569 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100570 def galera = new com.mirantis.mk.Galera()
571 common.warningMsg("getGaleraLastShutdownNode method was moved to Galera class. Please change your calls accordingly.")
572 return galera.getGaleraLastShutdownNode(env)
Martin Polreich9a5d6682018-12-21 16:42:06 +0100573}
574
Ivan Berezovskiy004cac22019-02-01 17:03:28 +0400575def restoreGaleraDb(env) {
Jiri Broulikf8f96942018-02-15 10:03:42 +0100576 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100577 def galera = new com.mirantis.mk.Galera()
578 common.warningMsg("restoreGaleraDb method was moved to Galera class. Please change your calls accordingly.")
579 return galera.restoreGaleraDb(env)
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200580}