blob: e67001375713d68d9bfa40bb831ca7f2959678cf [file] [log] [blame]
Sergey Kolekonovba203982016-12-21 18:32:17 +04001package com.mirantis.mk
2
3/**
4 *
5 * Python functions
6 *
7 */
8
9/**
10 * Install python virtualenv
11 *
Vladislav Naumov11103862017-07-19 17:02:39 +030012 * @param path Path to virtualenv
13 * @param python Version of Python (python/python3)
14 * @param reqs Environment requirements in list format
15 * @param reqs_path Environment requirements path in str format
Sergey Kolekonovba203982016-12-21 18:32:17 +040016 */
Jakub Josef996f4ef2017-10-24 13:20:43 +020017def setupVirtualenv(path, python = 'python2', reqs=[], reqs_path=null, clean=false, useSystemPackages=false) {
Tomáš Kukrál69c25452017-07-27 14:59:40 +020018 def common = new com.mirantis.mk.Common()
19
Mykyta Karpin1e4bfc92017-11-01 14:38:25 +020020 def virtualenv_cmd = "virtualenv ${path} --python ${python}"
Jakub Josef996f4ef2017-10-24 13:20:43 +020021 if (useSystemPackages){
22 virtualenv_cmd += " --system-site-packages"
23 }
Tomáš Kukrál69c25452017-07-27 14:59:40 +020024 if (clean) {
25 common.infoMsg("Cleaning venv directory " + path)
26 sh("rm -rf \"${path}\"")
27 }
28
29 common.infoMsg("[Python ${path}] Setup ${python} environment")
Sergey Kolekonovba203982016-12-21 18:32:17 +040030 sh(returnStdout: true, script: virtualenv_cmd)
Jakub Josef5f97d532017-11-29 18:51:41 +010031 if(!env.getEnvironment().containsKey("OFFLINE_DEPLOYMENT") || !env["OFFLINE_DEPLOYMENT"].toBoolean()){
32 try {
Jakub Josefa2491ad2018-01-15 16:26:27 +010033 runVirtualenvCommand(path, "pip install -U setuptools pip")
Jakub Josef5f97d532017-11-29 18:51:41 +010034 } catch(Exception e) {
Jakub Josefa2491ad2018-01-15 16:26:27 +010035 common.warningMsg("Setuptools and pip cannot be updated, you might be offline but OFFLINE_DEPLOYMENT global property not initialized!")
Jakub Josef5f97d532017-11-29 18:51:41 +010036 }
Yuriy Taraday67352e92017-10-12 10:54:23 +000037 }
Vladislav Naumov11103862017-07-19 17:02:39 +030038 if (reqs_path==null) {
39 def args = ""
40 for (req in reqs) {
41 args = args + "${req}\n"
42 }
43 writeFile file: "${path}/requirements.txt", text: args
44 reqs_path = "${path}/requirements.txt"
Sergey Kolekonovba203982016-12-21 18:32:17 +040045 }
Jakub Josefa2491ad2018-01-15 16:26:27 +010046 runVirtualenvCommand(path, "pip install -r ${reqs_path}", true)
Sergey Kolekonovba203982016-12-21 18:32:17 +040047}
48
49/**
50 * Run command in specific python virtualenv
51 *
52 * @param path Path to virtualenv
53 * @param cmd Command to be executed
Jakub Josefe2f4ebb2018-01-15 16:11:51 +010054 * @param silent dont print any messages (optional, default false)
Sergey Kolekonovba203982016-12-21 18:32:17 +040055 */
Jakub Josefe2f4ebb2018-01-15 16:11:51 +010056def runVirtualenvCommand(path, cmd, silent=false) {
Tomáš Kukrál69c25452017-07-27 14:59:40 +020057 def common = new com.mirantis.mk.Common()
58
Jakub Josef5feeee42018-01-08 15:50:36 +010059 virtualenv_cmd = "set +x; . ${path}/bin/activate; ${cmd}"
Jakub Josefe2f4ebb2018-01-15 16:11:51 +010060 if(!silent){
61 common.infoMsg("[Python ${path}] Run command ${cmd}")
62 }
Sergey Kolekonovba203982016-12-21 18:32:17 +040063 output = sh(
64 returnStdout: true,
65 script: virtualenv_cmd
66 ).trim()
67 return output
68}
69
Ales Komarekd874d482016-12-26 10:33:29 +010070
71/**
72 * Install docutils in isolated environment
73 *
74 * @param path Path where virtualenv is created
75 */
76def setupDocutilsVirtualenv(path) {
77 requirements = [
78 'docutils',
79 ]
80 setupVirtualenv(path, 'python2', requirements)
81}
82
83
Sergey Kolekonovba203982016-12-21 18:32:17 +040084@NonCPS
85def loadJson(rawData) {
86 return new groovy.json.JsonSlurperClassic().parseText(rawData)
87}
88
89/**
90 * Parse content from markup-text tables to variables
91 *
92 * @param tableStr String representing the table
93 * @param mode Either list (1st row are keys) or item (key, value rows)
94 * @param format Format of the table
95 */
Ales Komarekd874d482016-12-26 10:33:29 +010096def parseTextTable(tableStr, type = 'item', format = 'rest', path = none) {
Ales Komarek0e558ee2016-12-23 13:02:55 +010097 parserFile = "${env.WORKSPACE}/textTableParser.py"
98 parserScript = """import json
99import argparse
100from docutils.parsers.rst import tableparser
101from docutils import statemachine
102
103def parse_item_table(raw_data):
104 i = 1
105 pretty_raw_data = []
106 for datum in raw_data:
107 if datum != "":
108 if datum[3] != ' ' and i > 4:
109 pretty_raw_data.append(raw_data[0])
110 if i == 3:
111 pretty_raw_data.append(datum.replace('-', '='))
112 else:
113 pretty_raw_data.append(datum)
114 i += 1
115 parser = tableparser.GridTableParser()
116 block = statemachine.StringList(pretty_raw_data)
117 docutils_data = parser.parse(block)
118 final_data = {}
119 for line in docutils_data[2]:
120 key = ' '.join(line[0][3]).strip()
121 value = ' '.join(line[1][3]).strip()
122 if key != "":
123 try:
124 value = json.loads(value)
125 except:
126 pass
127 final_data[key] = value
128 i+=1
129 return final_data
130
131def parse_list_table(raw_data):
132 i = 1
133 pretty_raw_data = []
134 for datum in raw_data:
135 if datum != "":
136 if datum[3] != ' ' and i > 4:
137 pretty_raw_data.append(raw_data[0])
138 if i == 3:
139 pretty_raw_data.append(datum.replace('-', '='))
140 else:
141 pretty_raw_data.append(datum)
142 i += 1
143 parser = tableparser.GridTableParser()
144 block = statemachine.StringList(pretty_raw_data)
145 docutils_data = parser.parse(block)
146 final_data = []
147 keys = []
148 for line in docutils_data[1]:
149 for item in line:
150 keys.append(' '.join(item[3]).strip())
151 for line in docutils_data[2]:
152 final_line = {}
153 key = ' '.join(line[0][3]).strip()
154 value = ' '.join(line[1][3]).strip()
155 if key != "":
156 try:
157 value = json.loads(value)
158 except:
159 pass
160 final_data[key] = value
161 i+=1
162 return final_data
163
164def parse_list_table(raw_data):
165 i = 1
166 pretty_raw_data = []
167 for datum in raw_data:
168 if datum != "":
169 if datum[3] != ' ' and i > 4:
170 pretty_raw_data.append(raw_data[0])
171 if i == 3:
172 pretty_raw_data.append(datum.replace('-', '='))
173 else:
174 pretty_raw_data.append(datum)
175 i += 1
176 parser = tableparser.GridTableParser()
177 block = statemachine.StringList(pretty_raw_data)
178 docutils_data = parser.parse(block)
179 final_data = []
180 keys = []
181 for line in docutils_data[1]:
182 for item in line:
183 keys.append(' '.join(item[3]).strip())
184 for line in docutils_data[2]:
185 final_line = {}
186 i = 0
187 for item in line:
188 value = ' '.join(item[3]).strip()
189 try:
190 value = json.loads(value)
191 except:
192 pass
193 final_line[keys[i]] = value
194 i += 1
195 final_data.append(final_line)
196 return final_data
197
198def read_table_file(file):
199 table_file = open(file, 'r')
Ales Komarekc000c152016-12-23 15:32:54 +0100200 raw_data = table_file.read().split('\\n')
Ales Komarek0e558ee2016-12-23 13:02:55 +0100201 table_file.close()
202 return raw_data
203
204parser = argparse.ArgumentParser()
205parser.add_argument('-f','--file', help='File with table data', required=True)
206parser.add_argument('-t','--type', help='Type of table (list/item)', required=True)
207args = vars(parser.parse_args())
208
209raw_data = read_table_file(args['file'])
210
211if args['type'] == 'list':
212 final_data = parse_list_table(raw_data)
213else:
214 final_data = parse_item_table(raw_data)
215
216print json.dumps(final_data)
217"""
218 writeFile file: parserFile, text: parserScript
Sergey Kolekonovba203982016-12-21 18:32:17 +0400219 tableFile = "${env.WORKSPACE}/prettytable.txt"
220 writeFile file: tableFile, text: tableStr
Ales Komarekd874d482016-12-26 10:33:29 +0100221
222 cmd = "python ${parserFile} --file '${tableFile}' --type ${type}"
223 if (path) {
Ales Komarekc6d28dd2016-12-28 12:59:38 +0100224 rawData = runVirtualenvCommand(path, cmd)
Ales Komarekd874d482016-12-26 10:33:29 +0100225 }
226 else {
227 rawData = sh (
228 script: cmd,
229 returnStdout: true
230 ).trim()
231 }
Sergey Kolekonovba203982016-12-21 18:32:17 +0400232 data = loadJson(rawData)
233 echo("[Parsed table] ${data}")
234 return data
235}
236
237/**
238 * Install cookiecutter in isolated environment
239 *
240 * @param path Path where virtualenv is created
241 */
242def setupCookiecutterVirtualenv(path) {
243 requirements = [
244 'cookiecutter',
Jakub Josef4df78272017-04-26 14:36:36 +0200245 'jinja2==2.8.1',
246 'PyYAML==3.12'
Sergey Kolekonovba203982016-12-21 18:32:17 +0400247 ]
248 setupVirtualenv(path, 'python2', requirements)
249}
250
251/**
252 * Generate the cookiecutter templates with given context
253 *
Jakub Josef4e10c372017-04-26 14:13:50 +0200254 * @param template template
255 * @param context template context
256 * @param path Path where virtualenv is created (optional)
257 * @param templatePath path to cookiecutter template repo (optional)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400258 */
Jakub Josef4e10c372017-04-26 14:13:50 +0200259def buildCookiecutterTemplate(template, context, outputDir = '.', path = null, templatePath = ".") {
Tomáš Kukráldad7b462017-03-27 13:53:05 +0200260 configFile = "default_config.yaml"
261 configString = "default_context:\n"
Tomáš Kukrál6de85042017-04-12 17:49:05 +0200262 writeFile file: configFile, text: context
Jakub Josef4e61cc02017-04-26 14:29:09 +0200263 command = ". ${path}/bin/activate; if [ -f ${templatePath}/generate.py ]; then python ${templatePath}/generate.py --config-file ${configFile} --template ${template} --output-dir ${outputDir}; else cookiecutter --config-file ${configFile} --output-dir ${outputDir} --overwrite-if-exists --verbose --no-input ${template}; fi"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400264 output = sh (returnStdout: true, script: command)
265 echo("[Cookiecutter build] Output: ${output}")
266}
267
268/**
269 * Install jinja rendering in isolated environment
270 *
271 * @param path Path where virtualenv is created
272 */
273def setupJinjaVirtualenv(path) {
274 requirements = [
275 'jinja2-cli',
276 'pyyaml',
277 ]
278 setupVirtualenv(path, 'python2', requirements)
279}
280
281/**
282 * Generate the Jinja templates with given context
283 *
284 * @param path Path where virtualenv is created
285 */
286def jinjaBuildTemplate (template, context, path = none) {
287 contextFile = "jinja_context.yml"
288 contextString = ""
289 for (parameter in context) {
290 contextString = "${contextString}${parameter.key}: ${parameter.value}\n"
291 }
292 writeFile file: contextFile, text: contextString
293 cmd = "jinja2 ${template} ${contextFile} --format=yaml"
294 data = sh (returnStdout: true, script: cmd)
295 echo(data)
296 return data
297}
Oleg Grigorovbec45582017-09-12 20:29:24 +0300298
299/**
300 * Install salt-pepper in isolated environment
301 *
302 * @param path Path where virtualenv is created
chnydaa0dbb252017-10-05 10:46:09 +0200303 * @param url SALT_MASTER_URL
304 * @param credentialsId Credentials to salt api
Oleg Grigorovbec45582017-09-12 20:29:24 +0300305 */
Mykyta Karpin94916232017-11-15 10:20:59 +0200306def setupPepperVirtualenv(path, url, credentialsId, clean = false) {
chnydaa0dbb252017-10-05 10:46:09 +0200307 def common = new com.mirantis.mk.Common()
308
309 // virtualenv setup
Jakub Josef96cb63a2017-12-06 18:20:59 +0100310 requirements = ['salt-pepper==0.5.2']
Mykyta Karpin94916232017-11-15 10:20:59 +0200311 setupVirtualenv(path, 'python2', requirements, null, clean, true)
chnydabcfff182017-11-29 10:24:36 +0100312
chnydaa0dbb252017-10-05 10:46:09 +0200313 // pepperrc creation
314 rcFile = "${path}/pepperrc"
315 creds = common.getPasswordCredentials(credentialsId)
316 rc = """\
317[main]
318SALTAPI_EAUTH=pam
319SALTAPI_URL=${url}
320SALTAPI_USER=${creds.username}
321SALTAPI_PASS=${creds.password.toString()}
322"""
323 writeFile file: rcFile, text: rc
324 return rcFile
Jakub Josefd067f612017-09-26 13:42:56 +0200325}
Oleh Hryhorov44569fb2017-10-26 17:04:55 +0300326
327/**
328 * Install devops in isolated environment
329 *
330 * @param path Path where virtualenv is created
331 * @param clean Define to true is the venv have to cleaned up before install a new one
332 */
333def setupDevOpsVenv(venv, clean=false) {
334 requirements = ['git+https://github.com/openstack/fuel-devops.git']
335 setupVirtualenv(venv, 'python2', requirements, null, false, clean)
336}