blob: 1d79ea3649e7a13e82e7942b5a63f5f696e48957 [file] [log] [blame]
Sergey Kolekonovba203982016-12-21 18:32:17 +04001package com.mirantis.mk
2
3/**
4 *
5 * Openstack functions
6 *
7 */
8
9/**
10 * Install OpenStack service clients in isolated environment
11 *
12 * @param path Path where virtualenv is created
13 * @param version Version of the OpenStack clients
14 */
15
16def setupOpenstackVirtualenv(path, version = 'kilo'){
iberezovskiyd4240b52017-02-20 17:18:28 +040017 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +040018
19 def openstack_kilo_packages = [
20 'python-cinderclient>=1.3.1,<1.4.0',
21 'python-glanceclient>=0.19.0,<0.20.0',
22 'python-heatclient>=0.6.0,<0.7.0',
23 'python-keystoneclient>=1.6.0,<1.7.0',
24 'python-neutronclient>=2.2.6,<2.3.0',
25 'python-novaclient>=2.19.0,<2.20.0',
26 'python-swiftclient>=2.5.0,<2.6.0',
27 'oslo.config>=2.2.0,<2.3.0',
28 'oslo.i18n>=2.3.0,<2.4.0',
29 'oslo.serialization>=1.8.0,<1.9.0',
30 'oslo.utils>=1.4.0,<1.5.0',
Ales Komarekd874d482016-12-26 10:33:29 +010031 'docutils>=0.12'
Sergey Kolekonovba203982016-12-21 18:32:17 +040032 ]
33
34 def openstack_latest_packages = openstack_kilo_packages
35
36 if(version == 'kilo') {
37 requirements = openstack_kilo_packages
38 }
39 else if(version == 'liberty') {
40 requirements = openstack_kilo_packages
41 }
42 else if(version == 'mitaka') {
43 requirements = openstack_kilo_packages
44 }
45 else {
46 requirements = openstack_latest_packages
47 }
48 python.setupVirtualenv(path, 'python2', requirements)
49}
50
51/**
52 * create connection to OpenStack API endpoint
53 *
54 * @param url OpenStack API endpoint address
55 * @param credentialsId Credentials to the OpenStack API
56 * @param project OpenStack project to connect to
57 */
Sergey Kolekonovba203982016-12-21 18:32:17 +040058def createOpenstackEnv(url, credentialsId, project) {
iberezovskiyd4240b52017-02-20 17:18:28 +040059 def common = new com.mirantis.mk.Common()
Ales Komarek0e558ee2016-12-23 13:02:55 +010060 rcFile = "${env.WORKSPACE}/keystonerc"
Sergey Kolekonovba203982016-12-21 18:32:17 +040061 creds = common.getPasswordCredentials(credentialsId)
Alexander Tivelkovf89a1882017-01-11 13:29:35 +030062 rc = """set +x
63export OS_USERNAME=${creds.username}
Ales Komarek0e558ee2016-12-23 13:02:55 +010064export OS_PASSWORD=${creds.password.toString()}
65export OS_TENANT_NAME=${project}
66export OS_AUTH_URL=${url}
67export OS_AUTH_STRATEGY=keystone
Alexander Tivelkovf89a1882017-01-11 13:29:35 +030068set -x
Ales Komarek0e558ee2016-12-23 13:02:55 +010069"""
70 writeFile file: rcFile, text: rc
71 return rcFile
Sergey Kolekonovba203982016-12-21 18:32:17 +040072}
73
74/**
75 * Run command with OpenStack env params and optional python env
76 *
77 * @param cmd Command to be executed
78 * @param env Environmental parameters with endpoint credentials
79 * @param path Optional path to virtualenv with specific clients
80 */
81def runOpenstackCommand(cmd, venv, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +040082 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +040083 openstackCmd = ". ${venv}; ${cmd}"
84 if (path) {
85 output = python.runVirtualenvCommand(path, openstackCmd)
86 }
87 else {
88 echo("[Command]: ${openstackCmd}")
89 output = sh (
90 script: openstackCmd,
91 returnStdout: true
92 ).trim()
93 }
94 return output
95}
96
97/**
98 * Get OpenStack Keystone token for current credentials
99 *
100 * @param env Connection parameters for OpenStack API endpoint
101 * @param path Optional path to the custom virtualenv
102 */
103def getKeystoneToken(client, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400104 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400105 cmd = "keystone token-get"
106 outputTable = runOpenstackCommand(cmd, client, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100107 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400108 return output
109}
110
111/**
112 * Get OpenStack Keystone token for current credentials
113 *
114 * @param env Connection parameters for OpenStack API endpoint
115 * @param path Optional path to the custom virtualenv
116 */
117def createHeatEnv(file, environment = [], original_file = null) {
118 if (original_file) {
119 envString = readFile file: original_file
Tomáš Kukrál03029442017-02-21 17:14:29 +0100120 } else {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400121 envString = "parameters:\n"
122 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100123
Tomáš Kukrálb1fe9642017-02-22 11:21:17 +0100124 def p = environment.collect {k, v -> [k, v]}
125 for (int i = 0; i < p.size(); i++) {
126 envString = "${envString} ${p.get(i)[0]}: ${p.get(i)[1]}\n"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400127 }
Tomáš Kukrál03029442017-02-21 17:14:29 +0100128
Tomáš Kukrále19ddea2017-02-21 11:09:40 +0100129 echo("writing to env file:\n${envString}")
Sergey Kolekonovba203982016-12-21 18:32:17 +0400130 writeFile file: file, text: envString
131}
132
133/**
134 * Create new OpenStack Heat stack
135 *
136 * @param env Connection parameters for OpenStack API endpoint
137 * @param template HOT template for the new Heat stack
138 * @param environment Environmentale parameters of the new Heat stack
139 * @param name Name of the new Heat stack
140 * @param path Optional path to the custom virtualenv
141 */
142def createHeatStack(client, name, template, params = [], environment = null, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400143 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400144 templateFile = "${env.WORKSPACE}/template/template/${template}.hot"
145 if (environment) {
146 envFile = "${env.WORKSPACE}/template/env/${template}/${name}.env"
147 envSource = "${env.WORKSPACE}/template/env/${template}/${environment}.env"
148 createHeatEnv(envFile, params, envSource)
149 }
150 else {
151 envFile = "${env.WORKSPACE}/template/${name}.env"
152 createHeatEnv(envFile, params)
153 }
154 cmd = "heat stack-create -f ${templateFile} -e ${envFile} ${name}"
155 dir("${env.WORKSPACE}/template/template") {
156 outputTable = runOpenstackCommand(cmd, client, path)
157 }
Ales Komareke11e8792016-12-28 09:42:25 +0100158 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400159
160 i = 1
Ales Komarekdce8b472016-12-30 16:56:07 +0100161
Sergey Kolekonovba203982016-12-21 18:32:17 +0400162 while (true) {
163 status = getHeatStackStatus(client, name, path)
164 echo("[Heat Stack] Status: ${status}, Check: ${i}")
Ales Komarekdce8b472016-12-30 16:56:07 +0100165
166 if (status.indexOf('CREATE_FAILED') != -1) {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400167 info = getHeatStackInfo(client, name, path)
168 throw new Exception(info.stack_status_reason)
169 }
Ales Komarekdce8b472016-12-30 16:56:07 +0100170 else if (status.indexOf('CREATE_COMPLETE') != -1) {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400171 info = getHeatStackInfo(client, name, path)
172 echo(info.stack_status_reason)
173 break
174 }
175 sh('sleep 5s')
176 i++
177 }
178 echo("[Heat Stack] Status: ${status}")
179}
180
181/**
182 * Get life cycle status for existing OpenStack Heat stack
183 *
184 * @param env Connection parameters for OpenStack API endpoint
185 * @param name Name of the managed Heat stack instance
186 * @param path Optional path to the custom virtualenv
187 */
188def getHeatStackStatus(client, name, path = null) {
189 cmd = 'heat stack-list | awk -v stack='+name+' \'{if ($4==stack) print $6}\''
190 return runOpenstackCommand(cmd, client, path)
191}
192
193/**
194 * Get info about existing OpenStack Heat stack
195 *
196 * @param env Connection parameters for OpenStack API endpoint
197 * @param name Name of the managed Heat stack instance
198 * @param path Optional path to the custom virtualenv
199 */
200def getHeatStackInfo(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400201 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400202 cmd = "heat stack-show ${name}"
203 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100204 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400205 return output
206}
207
208/**
209 * Get existing OpenStack Heat stack output parameter
210 *
211 * @param env Connection parameters for OpenStack API endpoint
212 * @param name Name of the managed Heat stack
213 * @param parameter Name of the output parameter
214 * @param path Optional path to the custom virtualenv
215 */
216def getHeatStackOutputParam(env, name, outputParam, path = null) {
217 cmd = "heat output-show ${name} ${outputParam}"
218 output = runOpenstackCommand(cmd, env, path)
Ales Komarekeedc2222017-01-03 10:10:03 +0100219 echo("${cmd}: ${output}")
Ales Komarek7ebd0062017-01-03 10:59:29 +0100220 return "${output}".substring(1, output.length()-1)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400221}
222
223/**
224 * List all resources from existing OpenStack Heat stack
225 *
226 * @param env Connection parameters for OpenStack API endpoint
227 * @param name Name of the managed Heat stack instance
228 * @param path Optional path to the custom virtualenv
229 */
230def getHeatStackResources(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400231 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400232 cmd = "heat resource-list ${name}"
233 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100234 output = python.parseTextTable(outputTable, 'list', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400235 return output
236}
237
238/**
239 * Get info about resource from existing OpenStack Heat stack
240 *
241 * @param env Connection parameters for OpenStack API endpoint
242 * @param name Name of the managed Heat stack instance
243 * @param path Optional path to the custom virtualenv
244 */
245def getHeatStackResourceInfo(env, name, resource, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400246 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400247 cmd = "heat resource-show ${name} ${resource}"
248 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100249 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400250 return output
251}
252
253/**
254 * Update existing OpenStack Heat stack
255 *
256 * @param env Connection parameters for OpenStack API endpoint
257 * @param name Name of the managed Heat stack instance
258 * @param path Optional path to the custom virtualenv
259 */
260def updateHeatStack(env, name, path = null) {
iberezovskiyd4240b52017-02-20 17:18:28 +0400261 def python = new com.mirantis.mk.Python()
Sergey Kolekonovba203982016-12-21 18:32:17 +0400262 cmd = "heat stack-update ${name}"
263 outputTable = runOpenstackCommand(cmd, env, path)
Ales Komareke11e8792016-12-28 09:42:25 +0100264 output = python.parseTextTable(outputTable, 'item', 'prettytable', path)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400265 return output
266}
267
268/**
269 * Delete existing OpenStack Heat stack
270 *
271 * @param env Connection parameters for OpenStack API endpoint
272 * @param name Name of the managed Heat stack instance
273 * @param path Optional path to the custom virtualenv
274 */
275def deleteHeatStack(env, name, path = null) {
276 cmd = "heat stack-delete ${name}"
277 outputTable = runOpenstackCommand(cmd, env, path)
278}
279
280/**
281 * Return list of servers from OpenStack Heat stack
282 *
283 * @param env Connection parameters for OpenStack API endpoint
284 * @param name Name of the managed Heat stack instance
285 * @param path Optional path to the custom virtualenv
286 */
287def getHeatStackServers(env, name, path = null) {
288 resources = heatGetStackResources(env, name, path)
289 servers = []
290 for (resource in resources) {
291 if (resource.resource_type == 'OS::Nova::Server') {
292 resourceName = resource.resource_name
293 server = heatGetStackResourceInfo(env, name, resourceName, path)
294 servers.add(server.attributes.name)
295 }
296 }
297 echo("[Stack ${name}] Servers: ${servers}")
298 return servers
299}