blob: 7a45dbe44d067611eb527133962f75a242a2f0e5 [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 *
azvyagintsevf6e47f32019-07-22 13:34:03 +030021 * @param path Path where virtualenv is created
22 * @param version Version of the OpenStack clients
Sergey Kolekonovba203982016-12-21 18:32:17 +040023 */
24
Tomáš Kukrálbee0b992017-08-10 16:50:40 +020025def setupOpenstackVirtualenv(path, version = 'latest') {
azvyagintsevf6e47f32019-07-22 13:34:03 +030026 setupOpenstackVirtualenv(['path': path, 'version': version])
27}
28
29/**
30 * Install OpenStack service clients in isolated environment
31 *
32 * @param config : Config map with opts:
33 * path Path where virtualenv is created
34 * version Version of the OpenStack clients
35 * pyversion Version of the Python exec.
36 * requirements list of additional pip packages to be installed
37 *
38 */
39
40def setupOpenstackVirtualenv(LinkedHashMap config) {
iberezovskiyd4240b52017-02-20 17:18:28 +040041 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +040042
azvyagintsevf6e47f32019-07-22 13:34:03 +030043 def path = config.path
44 def version = config.get('version', 'latest')
45 def pyversion = config.get('pyversion', 'python2')
46 def requirements = config.get('requirements', [])
47 def os_requirements = []
Sergey Kolekonovba203982016-12-21 18:32:17 +040048
Sergey Kolekonovba203982016-12-21 18:32:17 +040049
azvyagintsevf6e47f32019-07-22 13:34:03 +030050 if (version in ['kilo', 'liberty', 'mitaka']) {
51 os_requirements = [
52 //XXX: hack to fix https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1635463
53 'cliff==2.8',
54 'python-cinderclient>=1.3.1,<1.4.0',
55 'python-glanceclient>=0.19.0,<0.20.0',
56 'python-heatclient>=0.6.0,<0.7.0',
57 'python-keystoneclient>=1.6.0,<1.7.0',
58 'python-neutronclient>=2.2.6,<2.3.0',
59 'python-novaclient>=2.19.0,<2.20.0',
60 'python-swiftclient>=2.5.0,<2.6.0',
61 'python-openstackclient>=1.7.0,<1.8.0',
62 'oslo.config>=2.2.0,<2.3.0',
63 'oslo.i18n>=2.3.0,<2.4.0',
64 'oslo.serialization>=1.8.0,<1.9.0',
65 'oslo.utils>=1.4.0,<1.5.0',
66 'docutils'
67 ]
Tomáš Kukrál381a8c92017-06-21 09:01:52 +020068 } else {
azvyagintsevf6e47f32019-07-22 13:34:03 +030069 pyversion = 'python3'
70 os_requirements = [
71 //XXX: hack to fix https://bugs.launchpad.net/ubuntu/+source/python-pip/+bug/1635463
72 'cliff==2.8',
73 // NOTE(vsaienko): cmd2 is dependency for cliff, since we don't using upper-contstraints
74 // we have to pin cmd2 < 0.9.0 as later versions are not compatible with python2.
75 // the same for warlock package due: https://github.com/bcwaldon/warlock/commit/4241a7a9fbccfce7eb3298c2abdf00ca2dede64a
76 // TODO(vsaienko): use upper-constraints here, as in requirements we set only lowest library
77 // versions.
78 'cmd2<0.9.0;python_version=="2.7"',
79 'cmd2>=0.9.1;python_version=="3.4"',
80 'cmd2>=0.9.1;python_version=="3.5"',
81 'warlock<=1.3.1;python_version=="2.7"',
82 'warlock>1.3.1;python_version=="3.4"',
83 'warlock>1.3.1;python_version=="3.5"',
84 'python-openstackclient',
85 'python-octaviaclient',
86 'python-heatclient',
87 'docutils'
88 ]
Sergey Kolekonovba203982016-12-21 18:32:17 +040089 }
azvyagintsevf6e47f32019-07-22 13:34:03 +030090 requirements = requirements + os_requirements
91 // (alexz): could we install docutils at single stage?
92 python.setupVirtualenv(path, pyversion, ['docutils'], null, true)
93 python.setupVirtualenv(path, pyversion, requirements.unique(), null, true)
Sergey Kolekonovba203982016-12-21 18:32:17 +040094}
95
96/**
97 * create connection to OpenStack API endpoint
98 *
Jakub Josef6c963762018-01-18 16:02:22 +010099 * @param path Path to created venv
Sergey Kolekonovba203982016-12-21 18:32:17 +0400100 * @param url OpenStack API endpoint address
101 * @param credentialsId Credentials to the OpenStack API
102 * @param project OpenStack project to connect to
103 */
Jakub Josef6c963762018-01-18 16:02:22 +0100104def createOpenstackEnv(path, url, credentialsId, project, project_domain="default",
Tomáš Kukrál381a8c92017-06-21 09:01:52 +0200105 project_id="", user_domain="default", api_ver="2", cacert="/etc/ssl/certs/ca-certificates.crt") {
iberezovskiyd4240b52017-02-20 17:18:28 +0400106 def common = new com.mirantis.mk.Common()
Jakub Josef6c963762018-01-18 16:02:22 +0100107 rcFile = "${path}/keystonerc"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400108 creds = common.getPasswordCredentials(credentialsId)
Alexander Tivelkovf89a1882017-01-11 13:29:35 +0300109 rc = """set +x
110export OS_USERNAME=${creds.username}
Ales Komarek0e558ee2016-12-23 13:02:55 +0100111export OS_PASSWORD=${creds.password.toString()}
112export OS_TENANT_NAME=${project}
113export OS_AUTH_URL=${url}
114export OS_AUTH_STRATEGY=keystone
kairat_kushaev0a26bf72017-05-18 13:20:09 +0400115export OS_PROJECT_NAME=${project}
Jakub Josefbd927322017-05-30 13:20:27 +0000116export OS_PROJECT_ID=${project_id}
kairat_kushaev0a26bf72017-05-18 13:20:09 +0400117export OS_PROJECT_DOMAIN_ID=${project_domain}
Jakub Josefbd927322017-05-30 13:20:27 +0000118export OS_USER_DOMAIN_NAME=${user_domain}
Kirill Mashchenko234708f2017-07-20 17:00:01 +0300119export OS_IDENTITY_API_VERSION=${api_ver}
Tomáš Kukrál381a8c92017-06-21 09:01:52 +0200120export OS_CACERT=${cacert}
Alexander Tivelkovf89a1882017-01-11 13:29:35 +0300121set -x
Ales Komarek0e558ee2016-12-23 13:02:55 +0100122"""
123 writeFile file: rcFile, text: rc
124 return rcFile
Sergey Kolekonovba203982016-12-21 18:32:17 +0400125}
126
127/**
128 * Run command with OpenStack env params and optional python env
129 *
130 * @param cmd Command to be executed
131 * @param env Environmental parameters with endpoint credentials
132 * @param path Optional path to virtualenv with specific clients
133 */
134def runOpenstackCommand(cmd, venv, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400135 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400136 openstackCmd = ". ${venv}; ${cmd}"
137 if (path) {
138 output = python.runVirtualenvCommand(path, openstackCmd)
139 }
140 else {
141 echo("[Command]: ${openstackCmd}")
142 output = sh (
143 script: openstackCmd,
144 returnStdout: true
145 ).trim()
146 }
147 return output
148}
149
150/**
151 * Get OpenStack Keystone token for current credentials
152 *
153 * @param env Connection parameters for OpenStack API endpoint
154 * @param path Optional path to the custom virtualenv
155 */
156def getKeystoneToken(client, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400157 def python = new com.mirantis.mk.Python()
Jakub Josefbd927322017-05-30 13:20:27 +0000158 cmd = "openstack token issue"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400159 outputTable = runOpenstackCommand(cmd, client, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100160 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400161 return output
162}
163
164/**
Ales Komarek51b7b152017-06-27 11:14:50 +0200165 * Create OpenStack environment file
Sergey Kolekonovba203982016-12-21 18:32:17 +0400166 *
167 * @param env Connection parameters for OpenStack API endpoint
168 * @param path Optional path to the custom virtualenv
169 */
170def createHeatEnv(file, environment = [], original_file = null) {
171 if (original_file) {
172 envString = readFile file: original_file
Tomáš Kukrál03029442017-02-21 17:14:29 +0100173 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400174 envString = "parameters:\n"
175 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100176
Tomáš Kukrálc3964e52017-02-22 14:07:37 +0100177 p = entries(environment)
Tomáš Kukrálb1fe9642017-02-22 11:21:17 +0100178 for (int i = 0; i < p.size(); i++) {
179 envString = "${envString} ${p.get(i)[0]}: ${p.get(i)[1]}\n"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400180 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100181
Tomáš Kukrále19ddea2017-02-21 11:09:40 +0100182 echo("writing to env file:\n${envString}")
Sergey Kolekonovba203982016-12-21 18:32:17 +0400183 writeFile file: file, text: envString
184}
185
186/**
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200187 * Create new OpenStack Heat stack. Will wait for action to be complited in
188 * specified amount of time (by default 120min)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400189 *
190 * @param env Connection parameters for OpenStack API endpoint
191 * @param template HOT template for the new Heat stack
192 * @param environment Environmentale parameters of the new Heat stack
193 * @param name Name of the new Heat stack
194 * @param path Optional path to the custom virtualenv
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200195 * @param timeout Optional number in minutes to wait for stack action is applied.
Sergey Kolekonovba203982016-12-21 18:32:17 +0400196 */
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200197def createHeatStack(client, name, template, params = [], environment = null, path = null, action="create", timeout=120) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400198 def python = new com.mirantis.mk.Python()
Jakub Josef0a898762017-08-11 16:27:44 +0200199 def templateFile = "${env.WORKSPACE}/template/template/${template}.hot"
200 def envFile
201 def envSource
Sergey Kolekonovba203982016-12-21 18:32:17 +0400202 if (environment) {
Tomáš Kukrála1152742017-08-22 16:21:50 +0200203 envFile = "${env.WORKSPACE}/template/env/${name}.env"
204 if (environment.contains("/")) {
205 //init() returns all elements but the last in a collection.
206 def envPath = environment.tokenize("/").init().join("/")
207 if (envPath) {
208 envFile = "${env.WORKSPACE}/template/env/${envPath}/${name}.env"
209 }
Ales Komarek51b7b152017-06-27 11:14:50 +0200210 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200211 envSource = "${env.WORKSPACE}/template/env/${environment}.env"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400212 createHeatEnv(envFile, params, envSource)
Jakub Josef9a59aeb2017-08-11 15:50:20 +0200213 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400214 envFile = "${env.WORKSPACE}/template/${name}.env"
215 createHeatEnv(envFile, params)
216 }
Tomáš Kukrála1152742017-08-22 16:21:50 +0200217
Mykyta Karpincf44f812017-08-28 14:45:21 +0300218 def cmd
Vasyl Saienkob91df802019-01-23 17:22:57 +0200219 def cmd_args = "-t ${templateFile} -e ${envFile} --timeout ${timeout} --wait ${name}"
Mykyta Karpincf44f812017-08-28 14:45:21 +0300220
Tomáš Kukrála1152742017-08-22 16:21:50 +0200221 if (action == "create") {
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200222 cmd = "openstack stack create ${cmd_args}"
Tomáš Kukrála1152742017-08-22 16:21:50 +0200223 } else {
Vasyl Saienko0adc34b2019-01-23 15:52:37 +0200224 cmd = "openstack stack update ${cmd_args}"
Tomáš Kukrála1152742017-08-22 16:21:50 +0200225 }
226
Sergey Kolekonovba203982016-12-21 18:32:17 +0400227 dir("${env.WORKSPACE}/template/template") {
Vasyl Saienkod4254192019-01-23 18:02:01 +0200228 def out = runOpenstackCommand(cmd, client, path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400229 }
Sergey Kolekonovba203982016-12-21 18:32:17 +0400230}
231
232/**
Jakub Josefdb4baf22017-05-10 15:16:09 +0200233 * Returns list of stacks for stack name filter
234 *
235 * @param client Connection parameters for OpenStack API endpoint
236 * @param filter Stack name filter
237 * @param path Optional path to the custom virtualenv
238 */
239def getStacksForNameContains(client, filter, path = null){
Jakub Josef6465fca2017-05-10 16:09:20 +0200240 cmd = 'heat stack-list | awk \'NR>3 {print $4}\' | sed \'$ d\' | grep ' + filter + '|| true'
Jakub Josefdb4baf22017-05-10 15:16:09 +0200241 return runOpenstackCommand(cmd, client, path).trim().tokenize("\n")
242}
243
244
245/**
Jakub Josef5e238a22017-04-19 16:35:15 +0200246 * Get list of stack names with given stack status
247 *
Jakub Josefdb4baf22017-05-10 15:16:09 +0200248 * @param client Connection parameters for OpenStack API endpoint
Jakub Josef5e238a22017-04-19 16:35:15 +0200249 * @param status Stack status
250 * @param path Optional path to the custom virtualenv
251 */
252 def getStacksWithStatus(client, status, path = null) {
253 cmd = 'heat stack-list -f stack_status='+status+' | awk \'NR>3 {print $4}\' | sed \'$ d\''
254 return runOpenstackCommand(cmd, client, path).trim().tokenize("\n")
255 }
256
257/**
Sergey Kolekonovba203982016-12-21 18:32:17 +0400258 * Get life cycle status for 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 getHeatStackStatus(client, name, path = null) {
265 cmd = 'heat stack-list | awk -v stack='+name+' \'{if ($4==stack) print $6}\''
266 return runOpenstackCommand(cmd, client, path)
267}
268
269/**
270 * Get info about existing OpenStack Heat stack
271 *
272 * @param env Connection parameters for OpenStack API endpoint
273 * @param name Name of the managed Heat stack instance
274 * @param path Optional path to the custom virtualenv
275 */
276def getHeatStackInfo(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400277 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400278 cmd = "heat stack-show ${name}"
279 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100280 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400281 return output
282}
283
284/**
285 * Get existing OpenStack Heat stack output parameter
286 *
287 * @param env Connection parameters for OpenStack API endpoint
288 * @param name Name of the managed Heat stack
289 * @param parameter Name of the output parameter
290 * @param path Optional path to the custom virtualenv
291 */
292def getHeatStackOutputParam(env, name, outputParam, path = null) {
Vasyl Saienkoea4b2812017-07-10 10:36:03 +0000293 cmd = "heat output-show ${name} ${outputParam}"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400294 output = runOpenstackCommand(cmd, env, path)
Ales Komarekeedc2222017-01-03 10:10:03 +0100295 echo("${cmd}: ${output}")
Vasyl Saienko2a1c2de2017-07-11 11:41:53 +0300296 // NOTE(vsaienko) heatclient 1.5.1 returns output in "", while later
297 // versions returns string without "".
298 // TODO Use openstack 'stack output show' when all jobs using at least Mitaka heatclient
299 return "${output}".replaceAll('"', '')
Sergey Kolekonovba203982016-12-21 18:32:17 +0400300}
301
302/**
303 * List all resources from existing OpenStack Heat stack
304 *
305 * @param env Connection parameters for OpenStack API endpoint
306 * @param name Name of the managed Heat stack instance
307 * @param path Optional path to the custom virtualenv
Mykyta Karpin72306362018-02-08 16:40:43 +0200308 * @param depth Optional depth of stack for listing resources,
309 * 0 - do not list nested resources
Sergey Kolekonovba203982016-12-21 18:32:17 +0400310 */
Mykyta Karpin72306362018-02-08 16:40:43 +0200311def getHeatStackResources(env, name, path = null, depth = 0) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400312 def python = new com.mirantis.mk.Python()
Mykyta Karpin72306362018-02-08 16:40:43 +0200313 cmd = "heat resource-list --nested-depth ${depth} ${name}"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400314 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100315 output = python.parseTextTable(outputTable, 'list', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400316 return output
317}
318
319/**
320 * Get info about resource from existing OpenStack Heat stack
321 *
322 * @param env Connection parameters for OpenStack API endpoint
323 * @param name Name of the managed Heat stack instance
324 * @param path Optional path to the custom virtualenv
325 */
326def getHeatStackResourceInfo(env, name, resource, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400327 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400328 cmd = "heat resource-show ${name} ${resource}"
329 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100330 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400331 return output
332}
333
334/**
335 * Update existing OpenStack Heat stack
336 *
337 * @param env Connection parameters for OpenStack API endpoint
338 * @param name Name of the managed Heat stack instance
339 * @param path Optional path to the custom virtualenv
340 */
341def updateHeatStack(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400342 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400343 cmd = "heat stack-update ${name}"
344 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100345 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400346 return output
347}
348
349/**
350 * Delete existing OpenStack Heat stack
351 *
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 deleteHeatStack(env, name, path = null) {
357 cmd = "heat stack-delete ${name}"
358 outputTable = runOpenstackCommand(cmd, env, path)
359}
360
361/**
Mykyta Karpin72306362018-02-08 16:40:43 +0200362 * Return hashmap of hashes server_id:server_name of servers from OpenStack Heat stack
Sergey Kolekonovba203982016-12-21 18:32:17 +0400363 *
364 * @param env Connection parameters for OpenStack API endpoint
365 * @param name Name of the managed Heat stack instance
366 * @param path Optional path to the custom virtualenv
367 */
368def getHeatStackServers(env, name, path = null) {
Mykyta Karpin72306362018-02-08 16:40:43 +0200369 // set depth to 1000 to ensure all nested resources are shown
370 resources = getHeatStackResources(env, name, path, 1000)
371 servers = [:]
Sergey Kolekonovba203982016-12-21 18:32:17 +0400372 for (resource in resources) {
373 if (resource.resource_type == 'OS::Nova::Server') {
Mykyta Karpin67978112018-02-22 11:16:45 +0200374 server = getHeatStackResourceInfo(env, resource.stack_name, resource.resource_name, path)
Mykyta Karpin72306362018-02-08 16:40:43 +0200375 servers[server.attributes.id] = server.attributes.name
Sergey Kolekonovba203982016-12-21 18:32:17 +0400376 }
377 }
378 echo("[Stack ${name}] Servers: ${servers}")
379 return servers
380}
Jiri Broulikf8f96942018-02-15 10:03:42 +0100381
382/**
Mykyta Karpin8306a9d2018-07-27 11:34:10 +0300383 * Delete nova key pair
384 *
385 * @param env Connection parameters for OpenStack API endpoint
386 * @param name Name of the key pair to delete
387 * @param path Optional path to the custom virtualenv
388 */
389def deleteKeyPair(env, name, path = null) {
390 def common = new com.mirantis.mk.Common()
391 common.infoMsg("Removing key pair ${name}")
392 def cmd = "openstack keypair delete ${name}"
393 runOpenstackCommand(cmd, env, path)
394}
395
396/**
397 * Get nova key pair
398 *
399 * @param env Connection parameters for OpenStack API endpoint
400 * @param name Name of the key pair to show
401 * @param path Optional path to the custom virtualenv
402 */
403
404def getKeyPair(env, name, path = null) {
405 def common = new com.mirantis.mk.Common()
406 def cmd = "openstack keypair show ${name}"
407 def outputTable
408 try {
409 outputTable = runOpenstackCommand(cmd, env, path)
410 } catch (Exception e) {
411 common.infoMsg("Key pair ${name} not found")
412 }
413 return outputTable
414}
415
416/**
Jiri Broulikf8f96942018-02-15 10:03:42 +0100417 * Stops all services that contain specific string (for example nova,heat, etc.)
418 * @param env Salt Connection object or pepperEnv
419 * @param probe single node on which to list service names
420 * @param target all targeted nodes
421 * @param services lists of type of services to be stopped
Jiri Broulikf6daac62018-03-08 13:17:53 +0100422 * @param confirm enable/disable manual service stop confirmation
Jiri Broulikf8f96942018-02-15 10:03:42 +0100423 * @return output of salt commands
424 */
Jiri Broulik27e83052018-03-06 11:37:29 +0100425def stopServices(env, probe, target, services=[], confirm=false) {
Jiri Broulikf8f96942018-02-15 10:03:42 +0100426 def salt = new com.mirantis.mk.Salt()
Jiri Broulikf6daac62018-03-08 13:17:53 +0100427 def common = new com.mirantis.mk.Common()
Jiri Broulikf8f96942018-02-15 10:03:42 +0100428 for (s in services) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400429 def outputServicesStr = salt.getReturnValues(salt.cmdRun(env, probe, "service --status-all | grep ${s} | awk \'{print \$4}\'"))
Jiri Broulikf6daac62018-03-08 13:17:53 +0100430 def servicesList = outputServicesStr.tokenize("\n").init()
Jiri Broulik27e83052018-03-06 11:37:29 +0100431 if (confirm) {
Jiri Broulikf6daac62018-03-08 13:17:53 +0100432 if (servicesList) {
433 try {
434 input message: "Click PROCEED to stop ${servicesList}. Otherwise click ABORT to skip stopping them."
435 for (name in servicesList) {
436 if (!name.contains('Salt command')) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400437 salt.runSaltProcessStep(env, target, 'service.stop', ["${name}"])
Jiri Broulikf6daac62018-03-08 13:17:53 +0100438 }
439 }
440 } catch (Exception er) {
441 common.infoMsg("skipping stopping ${servicesList} services")
442 }
443 }
444 } else {
445 if (servicesList) {
Jiri Broulik27e83052018-03-06 11:37:29 +0100446 for (name in servicesList) {
447 if (!name.contains('Salt command')) {
Dmitry Ukovd72cd2a2018-09-04 17:31:46 +0400448 salt.runSaltProcessStep(env, target, 'service.stop', ["${name}"])
Jiri Broulik27e83052018-03-06 11:37:29 +0100449 }
450 }
Jiri Broulikf8f96942018-02-15 10:03:42 +0100451 }
452 }
453 }
454}
455
456/**
Vasyl Saienko4129e102018-09-03 10:15:52 +0300457 * Return intersection of globally installed services and those are
458 * defined on specific target according to theirs priorities.
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200459 * By default services are added to the result list only if
460 * <service>.upgrade.enabled pillar is set to "True". However if it
461 * is needed to obtain list of upgrade services regardless of
462 * <service>.upgrade.enabled pillar value it is needed to set
463 * "upgrade_condition" param to "False".
Vasyl Saienko4129e102018-09-03 10:15:52 +0300464 *
465 * @param env Salt Connection object or env
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200466 * @param target The target node to get list of apps for
467 * @param upgrade_condition Whether to take "upgrade:enabled"
468 * service pillar into consideration
469 * when obtaining list of upgrade services
Vasyl Saienko4129e102018-09-03 10:15:52 +0300470**/
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200471def getOpenStackUpgradeServices(env, target, upgrade_condition=true){
Vasyl Saienko4129e102018-09-03 10:15:52 +0300472 def salt = new com.mirantis.mk.Salt()
473 def common = new com.mirantis.mk.Common()
474
475 def global_apps = salt.getConfig(env, 'I@salt:master:enabled:true', 'orchestration.upgrade.applications')
476 def node_apps = salt.getPillar(env, target, '__reclass__:applications')['return'][0].values()[0]
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200477 if (upgrade_condition) {
478 node_pillar = salt.getPillar(env, target)
479 }
Vasyl Saienko4129e102018-09-03 10:15:52 +0300480 def node_sorted_apps = []
481 if ( !global_apps['return'][0].values()[0].isEmpty() ) {
482 Map<String,Integer> _sorted_apps = [:]
483 for (k in global_apps['return'][0].values()[0].keySet()) {
484 if (k in node_apps) {
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200485 if (upgrade_condition) {
486 if (node_pillar['return'][0].values()[k]['upgrade']['enabled'][0] != null) {
487 if (node_pillar['return'][0].values()[k]['upgrade']['enabled'][0].toBoolean()) {
488 _sorted_apps[k] = global_apps['return'][0].values()[0][k].values()[0].toInteger()
489 }
Oleksii Grudev3116a732019-02-14 18:16:05 +0200490 }
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200491 } else {
492 _sorted_apps[k] = global_apps['return'][0].values()[0][k].values()[0].toInteger()
Oleksii Grudev3116a732019-02-14 18:16:05 +0200493 }
Vasyl Saienko4129e102018-09-03 10:15:52 +0300494 }
495 }
496 node_sorted_apps = common.SortMapByValueAsc(_sorted_apps).keySet()
497 common.infoMsg("Applications are placed in following order:"+node_sorted_apps)
498 } else {
499 common.errorMsg("No applications found.")
500 }
501
502 return node_sorted_apps
503}
504
Vasyl Saienko4129e102018-09-03 10:15:52 +0300505/**
506 * Run specified upgrade phase for all services on given node.
507 *
508 * @param env Salt Connection object or env
509 * @param target The target node to run states on.
510 * @param phase The phase name to run.
511**/
512def runOpenStackUpgradePhase(env, target, phase){
513 def salt = new com.mirantis.mk.Salt()
514 def common = new com.mirantis.mk.Common()
515
516 services = getOpenStackUpgradeServices(env, target)
517 def st
518
519 for (service in services){
520 st = "${service}.upgrade.${phase}".trim()
521 common.infoMsg("Running ${phase} for service ${st} on ${target}")
522 salt.enforceState(env, target, st)
523 }
524}
525
526
527/**
528 * Run OpenStack states on specified node.
529 *
530 * @param env Salt Connection object or env
531 * @param target The target node to run states on.
532**/
533def applyOpenstackAppsStates(env, target){
534 def salt = new com.mirantis.mk.Salt()
535 def common = new com.mirantis.mk.Common()
536
537 services = getOpenStackUpgradeServices(env, target)
538 def st
539
540 for (service in services){
541 st = "${service}".trim()
542 common.infoMsg("Running ${st} on ${target}")
543 salt.enforceState(env, target, st)
544 }
545}
546
Martin Polreich232ad902019-01-21 14:31:00 +0100547def verifyGaleraStatus(env, slave=false, checkTimeSync=false) {
Martin Polreich65864b02018-12-05 10:42:50 +0100548 def common = new com.mirantis.mk.Common()
Martin Polreich8f0f3ac2019-02-15 10:03:33 +0100549 def galera = new com.mirantis.mk.Galera()
550 common.warningMsg("verifyGaleraStatus method was moved to Galera class. Please change your calls accordingly.")
551 return galera.verifyGaleraStatus(env, slave, checkTimeSync)
Martin Polreich65864b02018-12-05 10:42:50 +0100552}
553
Martin Polreich9a5d6682018-12-21 16:42:06 +0100554def validateAndPrintGaleraStatusReport(env, out, minion) {
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("validateAndPrintGaleraStatusReport method was moved to Galera class. Please change your calls accordingly.")
558 return galera.validateAndPrintGaleraStatusReport(env, out, minion)
Martin Polreich65864b02018-12-05 10:42:50 +0100559}
560
Martin Polreich9a5d6682018-12-21 16:42:06 +0100561def getGaleraLastShutdownNode(env) {
Martin Polreich9a5d6682018-12-21 16:42:06 +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("getGaleraLastShutdownNode method was moved to Galera class. Please change your calls accordingly.")
565 return galera.getGaleraLastShutdownNode(env)
Martin Polreich9a5d6682018-12-21 16:42:06 +0100566}
567
Ivan Berezovskiy004cac22019-02-01 17:03:28 +0400568def restoreGaleraDb(env) {
Jiri Broulikf8f96942018-02-15 10:03:42 +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("restoreGaleraDb method was moved to Galera class. Please change your calls accordingly.")
572 return galera.restoreGaleraDb(env)
Oleksii Grudev3aaadc22019-03-14 10:54:58 +0200573}