blob: d50d742e22d5ae1036667ed2ef142375cc3d4695 [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 *
21 * @param path Path where virtualenv is created
22 * @param version Version of the OpenStack clients
23 */
24
Vasyl Saienkoa56c1ab2020-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
29 def openstack_kilo_packages = [
Jakub Josef268bc842017-10-10 14:36:17 +020030 //XXX: hack to fix https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1635463
31 'cliff==2.8',
Sergey Kolekonovba203982016-12-21 18:32:17 +040032 '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',
Jakub Josefbd927322017-05-30 13:20:27 +000039 'python-openstackclient>=1.7.0,<1.8.0',
Sergey Kolekonovba203982016-12-21 18:32:17 +040040 '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 Egorenko71754dc2020-01-13 14:22:49 +040044 'docutils==0.16'
Sergey Kolekonovba203982016-12-21 18:32:17 +040045 ]
46
Tomáš Kukrál381a8c92017-06-21 09:01:52 +020047 def openstack_latest_packages = [
Jakub Josef268bc842017-10-10 14:36:17 +020048 //XXX: hack to fix https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1635463
49 'cliff==2.8',
Vasyl Saienko36a019d2018-05-30 09:51:18 +030050 // 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 // TODO(vsaienko): use upper-constraints here, as in requirements we set only lowest library
53 // versions.
54 'cmd2<0.9.0;python_version=="2.7"',
55 'cmd2>=0.9.1;python_version=="3.4"',
56 'cmd2>=0.9.1;python_version=="3.5"',
Denis Egorenko71754dc2020-01-13 14:22:49 +040057 // NOTE: pin client packages to current latest to prevent
58 // downloading packages which are not support Python 2.7
Vladimir Khlyunev75d2ea12022-11-24 23:29:47 +040059 'keystoneauth1<=5.0.0',
Denis Egorenko71754dc2020-01-13 14:22:49 +040060 'python-openstackclient==4.0.0',
Vasyl Saienkof14fc572020-01-13 18:25:44 +020061 'python-heatclient==1.18.0',
Mykyta Karpin3fe5c2e2020-09-09 11:24:41 +030062 'docutils==0.16',
63 'pyrsistent<0.17.1',
Tomáš Kukrálc6a94c62017-06-19 14:44:24 +020064 ]
Sergey Kolekonovba203982016-12-21 18:32:17 +040065
Tomáš Kukrálc6a94c62017-06-19 14:44:24 +020066 if (version == 'kilo') {
Sergey Kolekonovba203982016-12-21 18:32:17 +040067 requirements = openstack_kilo_packages
Tomáš Kukrálc6a94c62017-06-19 14:44:24 +020068 } else if (version == 'liberty') {
Sergey Kolekonovba203982016-12-21 18:32:17 +040069 requirements = openstack_kilo_packages
Tomáš Kukrálc6a94c62017-06-19 14:44:24 +020070 } else if (version == 'mitaka') {
Sergey Kolekonovba203982016-12-21 18:32:17 +040071 requirements = openstack_kilo_packages
Tomáš Kukrál381a8c92017-06-21 09:01:52 +020072 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +040073 requirements = openstack_latest_packages
74 }
Vasyl Saienkoa56c1ab2020-01-13 10:00:04 +020075 pythonLib.setupVirtualenv(path, python, requirements, null, true)
Sergey Kolekonovba203982016-12-21 18:32:17 +040076}
77
78/**
79 * create connection to OpenStack API endpoint
80 *
Jakub Josef6c963762018-01-18 16:02:22 +010081 * @param path Path to created venv
Sergey Kolekonovba203982016-12-21 18:32:17 +040082 * @param url OpenStack API endpoint address
83 * @param credentialsId Credentials to the OpenStack API
84 * @param project OpenStack project to connect to
85 */
Jakub Josef6c963762018-01-18 16:02:22 +010086def createOpenstackEnv(path, url, credentialsId, project, project_domain="default",
Tomáš Kukrál381a8c92017-06-21 09:01:52 +020087 project_id="", user_domain="default", api_ver="2", cacert="/etc/ssl/certs/ca-certificates.crt") {
iberezovskiyd4240b52017-02-20 17:18:28 +040088 def common = new com.mirantis.mk.Common()
Jakub Josef6c963762018-01-18 16:02:22 +010089 rcFile = "${path}/keystonerc"
Sergey Kolekonovba203982016-12-21 18:32:17 +040090 creds = common.getPasswordCredentials(credentialsId)
Alexander Tivelkovf89a1882017-01-11 13:29:35 +030091 rc = """set +x
92export OS_USERNAME=${creds.username}
Ales Komarek0e558ee2016-12-23 13:02:55 +010093export OS_PASSWORD=${creds.password.toString()}
94export OS_TENANT_NAME=${project}
95export OS_AUTH_URL=${url}
96export OS_AUTH_STRATEGY=keystone
kairat_kushaev0a26bf72017-05-18 13:20:09 +040097export OS_PROJECT_NAME=${project}
Jakub Josefbd927322017-05-30 13:20:27 +000098export OS_PROJECT_ID=${project_id}
kairat_kushaev0a26bf72017-05-18 13:20:09 +040099export OS_PROJECT_DOMAIN_ID=${project_domain}
Jakub Josefbd927322017-05-30 13:20:27 +0000100export OS_USER_DOMAIN_NAME=${user_domain}
Kirill Mashchenko234708f2017-07-20 17:00:01 +0300101export OS_IDENTITY_API_VERSION=${api_ver}
Tomáš Kukrál381a8c92017-06-21 09:01:52 +0200102export OS_CACERT=${cacert}
Alexander Tivelkovf89a1882017-01-11 13:29:35 +0300103set -x
Ales Komarek0e558ee2016-12-23 13:02:55 +0100104"""
105 writeFile file: rcFile, text: rc
106 return rcFile
Sergey Kolekonovba203982016-12-21 18:32:17 +0400107}
108
109/**
110 * Run command with OpenStack env params and optional python env
111 *
112 * @param cmd Command to be executed
113 * @param env Environmental parameters with endpoint credentials
114 * @param path Optional path to virtualenv with specific clients
115 */
116def runOpenstackCommand(cmd, venv, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400117 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400118 openstackCmd = ". ${venv}; ${cmd}"
119 if (path) {
120 output = python.runVirtualenvCommand(path, openstackCmd)
121 }
122 else {
123 echo("[Command]: ${openstackCmd}")
124 output = sh (
125 script: openstackCmd,
126 returnStdout: true
127 ).trim()
128 }
129 return output
130}
131
132/**
133 * Get OpenStack Keystone token for current credentials
134 *
135 * @param env Connection parameters for OpenStack API endpoint
136 * @param path Optional path to the custom virtualenv
137 */
138def getKeystoneToken(client, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400139 def python = new com.mirantis.mk.Python()
Jakub Josefbd927322017-05-30 13:20:27 +0000140 cmd = "openstack token issue"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400141 outputTable = runOpenstackCommand(cmd, client, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100142 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400143 return output
144}
145
146/**
Ales Komarek51b7b152017-06-27 11:14:50 +0200147 * Create OpenStack environment file
Sergey Kolekonovba203982016-12-21 18:32:17 +0400148 *
149 * @param env Connection parameters for OpenStack API endpoint
150 * @param path Optional path to the custom virtualenv
151 */
152def createHeatEnv(file, environment = [], original_file = null) {
153 if (original_file) {
154 envString = readFile file: original_file
Tomáš Kukrál03029442017-02-21 17:14:29 +0100155 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400156 envString = "parameters:\n"
157 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100158
Tomáš Kukrálc3964e52017-02-22 14:07:37 +0100159 p = entries(environment)
Tomáš Kukrálb1fe9642017-02-22 11:21:17 +0100160 for (int i = 0; i < p.size(); i++) {
161 envString = "${envString} ${p.get(i)[0]}: ${p.get(i)[1]}\n"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400162 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100163
Tomáš Kukrále19ddea2017-02-21 11:09:40 +0100164 echo("writing to env file:\n${envString}")
Sergey Kolekonovba203982016-12-21 18:32:17 +0400165 writeFile file: file, text: envString
166}
167
168/**
169 * Create new OpenStack Heat stack
170 *
171 * @param env Connection parameters for OpenStack API endpoint
172 * @param template HOT template for the new Heat stack
173 * @param environment Environmentale parameters of the new Heat stack
174 * @param name Name of the new Heat stack
175 * @param path Optional path to the custom virtualenv
176 */
Tomáš Kukrála1152742017-08-22 16:21:50 +0200177def createHeatStack(client, name, template, params = [], environment = null, path = null, action="create") {
iberezovskiyd4240b52017-02-20 17:18:28 +0400178 def python = new com.mirantis.mk.Python()
Jakub Josef0a898762017-08-11 16:27:44 +0200179 def templateFile = "${env.WORKSPACE}/template/template/${template}.hot"
180 def envFile
181 def envSource
Sergey Kolekonovba203982016-12-21 18:32:17 +0400182 if (environment) {
Tomáš Kukrála1152742017-08-22 16:21:50 +0200183 envFile = "${env.WORKSPACE}/template/env/${name}.env"
184 if (environment.contains("/")) {
185 //init() returns all elements but the last in a collection.
186 def envPath = environment.tokenize("/").init().join("/")
187 if (envPath) {
188 envFile = "${env.WORKSPACE}/template/env/${envPath}/${name}.env"
189 }
Ales Komarek51b7b152017-06-27 11:14:50 +0200190 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200191 envSource = "${env.WORKSPACE}/template/env/${environment}.env"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400192 createHeatEnv(envFile, params, envSource)
Jakub Josef9a59aeb2017-08-11 15:50:20 +0200193 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400194 envFile = "${env.WORKSPACE}/template/${name}.env"
195 createHeatEnv(envFile, params)
196 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200197
Mykyta Karpincf44f812017-08-28 14:45:21 +0300198 def cmd
199 def waitState
200
Tomáš Kukrála1152742017-08-22 16:21:50 +0200201 if (action == "create") {
Mykyta Karpincf44f812017-08-28 14:45:21 +0300202 cmd = "heat stack-create -f ${templateFile} -e ${envFile} ${name}"
203 waitState = "CREATE_COMPLETE"
Tomáš Kukrála1152742017-08-22 16:21:50 +0200204 } else {
Mykyta Karpincf44f812017-08-28 14:45:21 +0300205 cmd = "heat stack-update -f ${templateFile} -e ${envFile} ${name}"
206 waitState = "UPDATE_COMPLETE"
Tomáš Kukrála1152742017-08-22 16:21:50 +0200207 }
208
Sergey Kolekonovba203982016-12-21 18:32:17 +0400209 dir("${env.WORKSPACE}/template/template") {
210 outputTable = runOpenstackCommand(cmd, client, path)
211 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200212
Ales Komareke11e8792016-12-28 09:42:25 +0100213 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400214
Jakub Josef9a59aeb2017-08-11 15:50:20 +0200215 def heatStatusCheckerCount = 1
Jakub Josefe0337272017-09-12 14:15:27 +0200216 while (heatStatusCheckerCount <= 250) {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400217 status = getHeatStackStatus(client, name, path)
Jakub Josef9a59aeb2017-08-11 15:50:20 +0200218 echo("[Heat Stack] Status: ${status}, Check: ${heatStatusCheckerCount}")
Ales Komarekdce8b472016-12-30 16:56:07 +0100219
Tomáš Kukrála1152742017-08-22 16:21:50 +0200220 if (status.contains('CREATE_FAILED')) {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400221 info = getHeatStackInfo(client, name, path)
222 throw new Exception(info.stack_status_reason)
Tomáš Kukrála1152742017-08-22 16:21:50 +0200223
224 } else if (status.contains(waitState)) {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400225 info = getHeatStackInfo(client, name, path)
226 echo(info.stack_status_reason)
227 break
228 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200229
Jakub Josefe0337272017-09-12 14:15:27 +0200230 sleep(30)
Jakub Josef9a59aeb2017-08-11 15:50:20 +0200231 heatStatusCheckerCount++
Sergey Kolekonovba203982016-12-21 18:32:17 +0400232 }
233 echo("[Heat Stack] Status: ${status}")
234}
235
236/**
Jakub Josefdb4baf22017-05-10 15:16:09 +0200237 * Returns list of stacks for stack name filter
238 *
239 * @param client Connection parameters for OpenStack API endpoint
240 * @param filter Stack name filter
241 * @param path Optional path to the custom virtualenv
242 */
243def getStacksForNameContains(client, filter, path = null){
Jakub Josef6465fca2017-05-10 16:09:20 +0200244 cmd = 'heat stack-list | awk \'NR>3 {print $4}\' | sed \'$ d\' | grep ' + filter + '|| true'
Jakub Josefdb4baf22017-05-10 15:16:09 +0200245 return runOpenstackCommand(cmd, client, path).trim().tokenize("\n")
246}
247
248
249/**
Jakub Josef5e238a22017-04-19 16:35:15 +0200250 * Get list of stack names with given stack status
251 *
Jakub Josefdb4baf22017-05-10 15:16:09 +0200252 * @param client Connection parameters for OpenStack API endpoint
Jakub Josef5e238a22017-04-19 16:35:15 +0200253 * @param status Stack status
254 * @param path Optional path to the custom virtualenv
255 */
256 def getStacksWithStatus(client, status, path = null) {
257 cmd = 'heat stack-list -f stack_status='+status+' | awk \'NR>3 {print $4}\' | sed \'$ d\''
258 return runOpenstackCommand(cmd, client, path).trim().tokenize("\n")
259 }
260
261/**
Sergey Kolekonovba203982016-12-21 18:32:17 +0400262 * Get life cycle status for existing OpenStack Heat stack
263 *
264 * @param env Connection parameters for OpenStack API endpoint
265 * @param name Name of the managed Heat stack instance
266 * @param path Optional path to the custom virtualenv
267 */
268def getHeatStackStatus(client, name, path = null) {
269 cmd = 'heat stack-list | awk -v stack='+name+' \'{if ($4==stack) print $6}\''
270 return runOpenstackCommand(cmd, client, path)
271}
272
273/**
274 * Get info about existing OpenStack Heat stack
275 *
276 * @param env Connection parameters for OpenStack API endpoint
277 * @param name Name of the managed Heat stack instance
278 * @param path Optional path to the custom virtualenv
279 */
280def getHeatStackInfo(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400281 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400282 cmd = "heat stack-show ${name}"
283 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100284 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400285 return output
286}
287
288/**
289 * Get existing OpenStack Heat stack output parameter
290 *
291 * @param env Connection parameters for OpenStack API endpoint
292 * @param name Name of the managed Heat stack
293 * @param parameter Name of the output parameter
294 * @param path Optional path to the custom virtualenv
295 */
296def getHeatStackOutputParam(env, name, outputParam, path = null) {
Vasyl Saienkoea4b2812017-07-10 10:36:03 +0000297 cmd = "heat output-show ${name} ${outputParam}"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400298 output = runOpenstackCommand(cmd, env, path)
Ales Komarekeedc2222017-01-03 10:10:03 +0100299 echo("${cmd}: ${output}")
Vasyl Saienko2a1c2de2017-07-11 11:41:53 +0300300 // NOTE(vsaienko) heatclient 1.5.1 returns output in "", while later
301 // versions returns string without "".
302 // TODO Use openstack 'stack output show' when all jobs using at least Mitaka heatclient
303 return "${output}".replaceAll('"', '')
Sergey Kolekonovba203982016-12-21 18:32:17 +0400304}
305
306/**
307 * List all resources from existing OpenStack Heat stack
308 *
309 * @param env Connection parameters for OpenStack API endpoint
310 * @param name Name of the managed Heat stack instance
311 * @param path Optional path to the custom virtualenv
Mykyta Karpin72306362018-02-08 16:40:43 +0200312 * @param depth Optional depth of stack for listing resources,
313 * 0 - do not list nested resources
Sergey Kolekonovba203982016-12-21 18:32:17 +0400314 */
Mykyta Karpin72306362018-02-08 16:40:43 +0200315def getHeatStackResources(env, name, path = null, depth = 0) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400316 def python = new com.mirantis.mk.Python()
Mykyta Karpin72306362018-02-08 16:40:43 +0200317 cmd = "heat resource-list --nested-depth ${depth} ${name}"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400318 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100319 output = python.parseTextTable(outputTable, 'list', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400320 return output
321}
322
323/**
324 * Get info about resource from 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 getHeatStackResourceInfo(env, name, resource, 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 resource-show ${name} ${resource}"
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 * Update 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 updateHeatStack(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400346 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400347 cmd = "heat stack-update ${name}"
348 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100349 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400350 return output
351}
352
353/**
354 * Delete existing OpenStack Heat stack
355 *
356 * @param env Connection parameters for OpenStack API endpoint
357 * @param name Name of the managed Heat stack instance
358 * @param path Optional path to the custom virtualenv
359 */
360def deleteHeatStack(env, name, path = null) {
361 cmd = "heat stack-delete ${name}"
362 outputTable = runOpenstackCommand(cmd, env, path)
363}
364
365/**
Mykyta Karpin72306362018-02-08 16:40:43 +0200366 * Return hashmap of hashes server_id:server_name of servers from OpenStack Heat stack
Sergey Kolekonovba203982016-12-21 18:32:17 +0400367 *
368 * @param env Connection parameters for OpenStack API endpoint
369 * @param name Name of the managed Heat stack instance
370 * @param path Optional path to the custom virtualenv
371 */
372def getHeatStackServers(env, name, path = null) {
Mykyta Karpin72306362018-02-08 16:40:43 +0200373 // set depth to 1000 to ensure all nested resources are shown
374 resources = getHeatStackResources(env, name, path, 1000)
375 servers = [:]
Sergey Kolekonovba203982016-12-21 18:32:17 +0400376 for (resource in resources) {
377 if (resource.resource_type == 'OS::Nova::Server') {
Mykyta Karpin67978112018-02-22 11:16:45 +0200378 server = getHeatStackResourceInfo(env, resource.stack_name, resource.resource_name, path)
Mykyta Karpin72306362018-02-08 16:40:43 +0200379 servers[server.attributes.id] = server.attributes.name
Sergey Kolekonovba203982016-12-21 18:32:17 +0400380 }
381 }
382 echo("[Stack ${name}] Servers: ${servers}")
383 return servers
384}
Jiri Broulikf8f96942018-02-15 10:03:42 +0100385
386/**
Mykyta Karpin8306a9d2018-07-27 11:34:10 +0300387 * Delete nova key pair
388 *
389 * @param env Connection parameters for OpenStack API endpoint
390 * @param name Name of the key pair to delete
391 * @param path Optional path to the custom virtualenv
392 */
393def deleteKeyPair(env, name, path = null) {
394 def common = new com.mirantis.mk.Common()
395 common.infoMsg("Removing key pair ${name}")
396 def cmd = "openstack keypair delete ${name}"
397 runOpenstackCommand(cmd, env, path)
398}
399
400/**
401 * Get nova key pair
402 *
403 * @param env Connection parameters for OpenStack API endpoint
404 * @param name Name of the key pair to show
405 * @param path Optional path to the custom virtualenv
406 */
407
408def getKeyPair(env, name, path = null) {
409 def common = new com.mirantis.mk.Common()
410 def cmd = "openstack keypair show ${name}"
411 def outputTable
412 try {
413 outputTable = runOpenstackCommand(cmd, env, path)
414 } catch (Exception e) {
415 common.infoMsg("Key pair ${name} not found")
416 }
417 return outputTable
418}
419
420/**
Jiri Broulikf8f96942018-02-15 10:03:42 +0100421 * Stops all services that contain specific string (for example nova,heat, etc.)
422 * @param env Salt Connection object or pepperEnv
423 * @param probe single node on which to list service names
424 * @param target all targeted nodes
425 * @param services lists of type of services to be stopped
Jiri Broulikf6daac62018-03-08 13:17:53 +0100426 * @param confirm enable/disable manual service stop confirmation
Jiri Broulikf8f96942018-02-15 10:03:42 +0100427 * @return output of salt commands
428 */
Jiri Broulik27e83052018-03-06 11:37:29 +0100429def stopServices(env, probe, target, services=[], confirm=false) {
Jiri Broulikf8f96942018-02-15 10:03:42 +0100430 def salt = new com.mirantis.mk.Salt()
Jiri Broulikf6daac62018-03-08 13:17:53 +0100431 def common = new com.mirantis.mk.Common()
Jiri Broulikf8f96942018-02-15 10:03:42 +0100432 for (s in services) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400433 def outputServicesStr = salt.getReturnValues(salt.cmdRun(env, probe, "service --status-all | grep ${s} | awk \'{print \$4}\'"))
Jiri Broulikf6daac62018-03-08 13:17:53 +0100434 def servicesList = outputServicesStr.tokenize("\n").init()
Jiri Broulik27e83052018-03-06 11:37:29 +0100435 if (confirm) {
Jiri Broulikf6daac62018-03-08 13:17:53 +0100436 if (servicesList) {
437 try {
438 input message: "Click PROCEED to stop ${servicesList}. Otherwise click ABORT to skip stopping them."
439 for (name in servicesList) {
440 if (!name.contains('Salt command')) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400441 salt.runSaltProcessStep(env, target, 'service.stop', ["${name}"])
Jiri Broulikf6daac62018-03-08 13:17:53 +0100442 }
443 }
444 } catch (Exception er) {
445 common.infoMsg("skipping stopping ${servicesList} services")
446 }
447 }
448 } else {
449 if (servicesList) {
Jiri Broulik27e83052018-03-06 11:37:29 +0100450 for (name in servicesList) {
451 if (!name.contains('Salt command')) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400452 salt.runSaltProcessStep(env, target, 'service.stop', ["${name}"])
Jiri Broulik27e83052018-03-06 11:37:29 +0100453 }
454 }
Jiri Broulikf8f96942018-02-15 10:03:42 +0100455 }
456 }
457 }
458}
459
460/**
Vasyl Saienko4129e102018-09-03 10:15:52 +0300461 * Return intersection of globally installed services and those are
462 * defined on specific target according to theirs priorities.
463 *
464 * @param env Salt Connection object or env
465 * @param target The target node to get list of apps for.
466**/
467def getOpenStackUpgradeServices(env, target){
468 def salt = new com.mirantis.mk.Salt()
469 def common = new com.mirantis.mk.Common()
470
471 def global_apps = salt.getConfig(env, 'I@salt:master:enabled:true', 'orchestration.upgrade.applications')
472 def node_apps = salt.getPillar(env, target, '__reclass__:applications')['return'][0].values()[0]
473 def node_sorted_apps = []
474 if ( !global_apps['return'][0].values()[0].isEmpty() ) {
475 Map<String,Integer> _sorted_apps = [:]
476 for (k in global_apps['return'][0].values()[0].keySet()) {
477 if (k in node_apps) {
478 _sorted_apps[k] = global_apps['return'][0].values()[0][k].values()[0].toInteger()
479 }
480 }
481 node_sorted_apps = common.SortMapByValueAsc(_sorted_apps).keySet()
482 common.infoMsg("Applications are placed in following order:"+node_sorted_apps)
483 } else {
484 common.errorMsg("No applications found.")
485 }
486
487 return node_sorted_apps
488}
489
490
491/**
492 * Run specified upgrade phase for all services on given node.
493 *
494 * @param env Salt Connection object or env
495 * @param target The target node to run states on.
496 * @param phase The phase name to run.
497**/
498def runOpenStackUpgradePhase(env, target, phase){
499 def salt = new com.mirantis.mk.Salt()
500 def common = new com.mirantis.mk.Common()
501
502 services = getOpenStackUpgradeServices(env, target)
503 def st
504
505 for (service in services){
506 st = "${service}.upgrade.${phase}".trim()
507 common.infoMsg("Running ${phase} for service ${st} on ${target}")
508 salt.enforceState(env, target, st)
509 }
510}
511
512
513/**
514 * Run OpenStack states on specified node.
515 *
516 * @param env Salt Connection object or env
517 * @param target The target node to run states on.
518**/
519def applyOpenstackAppsStates(env, target){
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}".trim()
528 common.infoMsg("Running ${st} on ${target}")
529 salt.enforceState(env, target, st)
530 }
531}
532
Martin Polreichddfe51c2019-01-21 14:31:00 +0100533def verifyGaleraStatus(env, slave=false, checkTimeSync=false) {
Martin Polreich65864b02018-12-05 10:42:50 +0100534 def common = new com.mirantis.mk.Common()
Martin Polreichf89f9b42019-05-07 15:37:13 +0200535 def galera = new com.mirantis.mk.Galera()
536 common.warningMsg("verifyGaleraStatus method was moved to Galera class. Please change your calls accordingly.")
537 return galera.verifyGaleraStatus(env, slave, checkTimeSync)
Martin Polreich65864b02018-12-05 10:42:50 +0100538}
539
Martin Polreich47c09d12018-12-21 16:42:06 +0100540def validateAndPrintGaleraStatusReport(env, out, minion) {
Martin Polreich65864b02018-12-05 10:42:50 +0100541 def common = new com.mirantis.mk.Common()
Martin Polreichf89f9b42019-05-07 15:37:13 +0200542 def galera = new com.mirantis.mk.Galera()
543 common.warningMsg("validateAndPrintGaleraStatusReport method was moved to Galera class. Please change your calls accordingly.")
544 return galera.validateAndPrintGaleraStatusReport(env, out, minion)
Martin Polreich65864b02018-12-05 10:42:50 +0100545}
546
Martin Polreich47c09d12018-12-21 16:42:06 +0100547def getGaleraLastShutdownNode(env) {
Martin Polreich47c09d12018-12-21 16:42:06 +0100548 def common = new com.mirantis.mk.Common()
Martin Polreichf89f9b42019-05-07 15:37:13 +0200549 def galera = new com.mirantis.mk.Galera()
550 common.warningMsg("getGaleraLastShutdownNode method was moved to Galera class. Please change your calls accordingly.")
551 return galera.getGaleraLastShutdownNode(env)
Martin Polreich47c09d12018-12-21 16:42:06 +0100552}
553
Martin Polreichdb692582019-04-25 14:32:36 +0200554def restoreGaleraDb(env) {
Jiri Broulikf8f96942018-02-15 10:03:42 +0100555 def common = new com.mirantis.mk.Common()
Martin Polreichf89f9b42019-05-07 15:37:13 +0200556 def galera = new com.mirantis.mk.Galera()
557 common.warningMsg("restoreGaleraDb method was moved to Galera class. Please change your calls accordingly.")
558 return galera.restoreGaleraDb(env)
Martin Polreich65864b02018-12-05 10:42:50 +0100559}