blob: 876299eda954986167f4fe256ce56ba4bc4df8ea [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 {
33 //TODO: remove wget after global env prop enforcments
Alexander Noskova5f11962017-12-05 11:25:16 +040034 runVirtualenvCommand(path, "wget -q -T 10 --spider http://google.com && pip install -U setuptools pip")
Jakub Josef5f97d532017-11-29 18:51:41 +010035 } catch(Exception e) {
36 common.warningMsg("Setuptools and pip cannot be updated, you might be offline")
37 }
Yuriy Taraday67352e92017-10-12 10:54:23 +000038 }
Vladislav Naumov11103862017-07-19 17:02:39 +030039 if (reqs_path==null) {
40 def args = ""
41 for (req in reqs) {
42 args = args + "${req}\n"
43 }
44 writeFile file: "${path}/requirements.txt", text: args
45 reqs_path = "${path}/requirements.txt"
Sergey Kolekonovba203982016-12-21 18:32:17 +040046 }
Vladislav Naumov11103862017-07-19 17:02:39 +030047 runVirtualenvCommand(path, "pip install -r ${reqs_path}")
Sergey Kolekonovba203982016-12-21 18:32:17 +040048}
49
50/**
51 * Run command in specific python virtualenv
52 *
53 * @param path Path to virtualenv
54 * @param cmd Command to be executed
Jakub Josefe2f4ebb2018-01-15 16:11:51 +010055 * @param silent dont print any messages (optional, default false)
Sergey Kolekonovba203982016-12-21 18:32:17 +040056 */
Jakub Josefe2f4ebb2018-01-15 16:11:51 +010057def runVirtualenvCommand(path, cmd, silent=false) {
Tomáš Kukrál69c25452017-07-27 14:59:40 +020058 def common = new com.mirantis.mk.Common()
59
Jakub Josef5feeee42018-01-08 15:50:36 +010060 virtualenv_cmd = "set +x; . ${path}/bin/activate; ${cmd}"
Jakub Josefe2f4ebb2018-01-15 16:11:51 +010061 if(!silent){
62 common.infoMsg("[Python ${path}] Run command ${cmd}")
63 }
Sergey Kolekonovba203982016-12-21 18:32:17 +040064 output = sh(
65 returnStdout: true,
66 script: virtualenv_cmd
67 ).trim()
68 return output
69}
70
Ales Komarekd874d482016-12-26 10:33:29 +010071
72/**
73 * Install docutils in isolated environment
74 *
75 * @param path Path where virtualenv is created
76 */
77def setupDocutilsVirtualenv(path) {
78 requirements = [
79 'docutils',
80 ]
81 setupVirtualenv(path, 'python2', requirements)
82}
83
84
Sergey Kolekonovba203982016-12-21 18:32:17 +040085@NonCPS
86def loadJson(rawData) {
87 return new groovy.json.JsonSlurperClassic().parseText(rawData)
88}
89
90/**
91 * Parse content from markup-text tables to variables
92 *
93 * @param tableStr String representing the table
94 * @param mode Either list (1st row are keys) or item (key, value rows)
95 * @param format Format of the table
96 */
Ales Komarekd874d482016-12-26 10:33:29 +010097def parseTextTable(tableStr, type = 'item', format = 'rest', path = none) {
Ales Komarek0e558ee2016-12-23 13:02:55 +010098 parserFile = "${env.WORKSPACE}/textTableParser.py"
99 parserScript = """import json
100import argparse
101from docutils.parsers.rst import tableparser
102from docutils import statemachine
103
104def parse_item_table(raw_data):
105 i = 1
106 pretty_raw_data = []
107 for datum in raw_data:
108 if datum != "":
109 if datum[3] != ' ' and i > 4:
110 pretty_raw_data.append(raw_data[0])
111 if i == 3:
112 pretty_raw_data.append(datum.replace('-', '='))
113 else:
114 pretty_raw_data.append(datum)
115 i += 1
116 parser = tableparser.GridTableParser()
117 block = statemachine.StringList(pretty_raw_data)
118 docutils_data = parser.parse(block)
119 final_data = {}
120 for line in docutils_data[2]:
121 key = ' '.join(line[0][3]).strip()
122 value = ' '.join(line[1][3]).strip()
123 if key != "":
124 try:
125 value = json.loads(value)
126 except:
127 pass
128 final_data[key] = value
129 i+=1
130 return final_data
131
132def parse_list_table(raw_data):
133 i = 1
134 pretty_raw_data = []
135 for datum in raw_data:
136 if datum != "":
137 if datum[3] != ' ' and i > 4:
138 pretty_raw_data.append(raw_data[0])
139 if i == 3:
140 pretty_raw_data.append(datum.replace('-', '='))
141 else:
142 pretty_raw_data.append(datum)
143 i += 1
144 parser = tableparser.GridTableParser()
145 block = statemachine.StringList(pretty_raw_data)
146 docutils_data = parser.parse(block)
147 final_data = []
148 keys = []
149 for line in docutils_data[1]:
150 for item in line:
151 keys.append(' '.join(item[3]).strip())
152 for line in docutils_data[2]:
153 final_line = {}
154 key = ' '.join(line[0][3]).strip()
155 value = ' '.join(line[1][3]).strip()
156 if key != "":
157 try:
158 value = json.loads(value)
159 except:
160 pass
161 final_data[key] = value
162 i+=1
163 return final_data
164
165def parse_list_table(raw_data):
166 i = 1
167 pretty_raw_data = []
168 for datum in raw_data:
169 if datum != "":
170 if datum[3] != ' ' and i > 4:
171 pretty_raw_data.append(raw_data[0])
172 if i == 3:
173 pretty_raw_data.append(datum.replace('-', '='))
174 else:
175 pretty_raw_data.append(datum)
176 i += 1
177 parser = tableparser.GridTableParser()
178 block = statemachine.StringList(pretty_raw_data)
179 docutils_data = parser.parse(block)
180 final_data = []
181 keys = []
182 for line in docutils_data[1]:
183 for item in line:
184 keys.append(' '.join(item[3]).strip())
185 for line in docutils_data[2]:
186 final_line = {}
187 i = 0
188 for item in line:
189 value = ' '.join(item[3]).strip()
190 try:
191 value = json.loads(value)
192 except:
193 pass
194 final_line[keys[i]] = value
195 i += 1
196 final_data.append(final_line)
197 return final_data
198
199def read_table_file(file):
200 table_file = open(file, 'r')
Ales Komarekc000c152016-12-23 15:32:54 +0100201 raw_data = table_file.read().split('\\n')
Ales Komarek0e558ee2016-12-23 13:02:55 +0100202 table_file.close()
203 return raw_data
204
205parser = argparse.ArgumentParser()
206parser.add_argument('-f','--file', help='File with table data', required=True)
207parser.add_argument('-t','--type', help='Type of table (list/item)', required=True)
208args = vars(parser.parse_args())
209
210raw_data = read_table_file(args['file'])
211
212if args['type'] == 'list':
213 final_data = parse_list_table(raw_data)
214else:
215 final_data = parse_item_table(raw_data)
216
217print json.dumps(final_data)
218"""
219 writeFile file: parserFile, text: parserScript
Sergey Kolekonovba203982016-12-21 18:32:17 +0400220 tableFile = "${env.WORKSPACE}/prettytable.txt"
221 writeFile file: tableFile, text: tableStr
Ales Komarekd874d482016-12-26 10:33:29 +0100222
223 cmd = "python ${parserFile} --file '${tableFile}' --type ${type}"
224 if (path) {
Ales Komarekc6d28dd2016-12-28 12:59:38 +0100225 rawData = runVirtualenvCommand(path, cmd)
Ales Komarekd874d482016-12-26 10:33:29 +0100226 }
227 else {
228 rawData = sh (
229 script: cmd,
230 returnStdout: true
231 ).trim()
232 }
Sergey Kolekonovba203982016-12-21 18:32:17 +0400233 data = loadJson(rawData)
234 echo("[Parsed table] ${data}")
235 return data
236}
237
238/**
239 * Install cookiecutter in isolated environment
240 *
241 * @param path Path where virtualenv is created
242 */
243def setupCookiecutterVirtualenv(path) {
244 requirements = [
245 'cookiecutter',
Jakub Josef4df78272017-04-26 14:36:36 +0200246 'jinja2==2.8.1',
247 'PyYAML==3.12'
Sergey Kolekonovba203982016-12-21 18:32:17 +0400248 ]
249 setupVirtualenv(path, 'python2', requirements)
250}
251
252/**
253 * Generate the cookiecutter templates with given context
254 *
Jakub Josef4e10c372017-04-26 14:13:50 +0200255 * @param template template
256 * @param context template context
257 * @param path Path where virtualenv is created (optional)
258 * @param templatePath path to cookiecutter template repo (optional)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400259 */
Jakub Josef4e10c372017-04-26 14:13:50 +0200260def buildCookiecutterTemplate(template, context, outputDir = '.', path = null, templatePath = ".") {
Tomáš Kukráldad7b462017-03-27 13:53:05 +0200261 configFile = "default_config.yaml"
262 configString = "default_context:\n"
Tomáš Kukrál6de85042017-04-12 17:49:05 +0200263 writeFile file: configFile, text: context
Jakub Josef4e61cc02017-04-26 14:29:09 +0200264 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 +0400265 output = sh (returnStdout: true, script: command)
266 echo("[Cookiecutter build] Output: ${output}")
267}
268
269/**
270 * Install jinja rendering in isolated environment
271 *
272 * @param path Path where virtualenv is created
273 */
274def setupJinjaVirtualenv(path) {
275 requirements = [
276 'jinja2-cli',
277 'pyyaml',
278 ]
279 setupVirtualenv(path, 'python2', requirements)
280}
281
282/**
283 * Generate the Jinja templates with given context
284 *
285 * @param path Path where virtualenv is created
286 */
287def jinjaBuildTemplate (template, context, path = none) {
288 contextFile = "jinja_context.yml"
289 contextString = ""
290 for (parameter in context) {
291 contextString = "${contextString}${parameter.key}: ${parameter.value}\n"
292 }
293 writeFile file: contextFile, text: contextString
294 cmd = "jinja2 ${template} ${contextFile} --format=yaml"
295 data = sh (returnStdout: true, script: cmd)
296 echo(data)
297 return data
298}
Oleg Grigorovbec45582017-09-12 20:29:24 +0300299
300/**
301 * Install salt-pepper in isolated environment
302 *
303 * @param path Path where virtualenv is created
chnydaa0dbb252017-10-05 10:46:09 +0200304 * @param url SALT_MASTER_URL
305 * @param credentialsId Credentials to salt api
Oleg Grigorovbec45582017-09-12 20:29:24 +0300306 */
Mykyta Karpin94916232017-11-15 10:20:59 +0200307def setupPepperVirtualenv(path, url, credentialsId, clean = false) {
chnydaa0dbb252017-10-05 10:46:09 +0200308 def common = new com.mirantis.mk.Common()
309
310 // virtualenv setup
Jakub Josef96cb63a2017-12-06 18:20:59 +0100311 requirements = ['salt-pepper==0.5.2']
Mykyta Karpin94916232017-11-15 10:20:59 +0200312 setupVirtualenv(path, 'python2', requirements, null, clean, true)
chnydabcfff182017-11-29 10:24:36 +0100313
chnydaa0dbb252017-10-05 10:46:09 +0200314 // pepperrc creation
315 rcFile = "${path}/pepperrc"
316 creds = common.getPasswordCredentials(credentialsId)
317 rc = """\
318[main]
319SALTAPI_EAUTH=pam
320SALTAPI_URL=${url}
321SALTAPI_USER=${creds.username}
322SALTAPI_PASS=${creds.password.toString()}
323"""
324 writeFile file: rcFile, text: rc
325 return rcFile
Jakub Josefd067f612017-09-26 13:42:56 +0200326}
Oleh Hryhorov44569fb2017-10-26 17:04:55 +0300327
328/**
329 * Install devops in isolated environment
330 *
331 * @param path Path where virtualenv is created
332 * @param clean Define to true is the venv have to cleaned up before install a new one
333 */
334def setupDevOpsVenv(venv, clean=false) {
335 requirements = ['git+https://github.com/openstack/fuel-devops.git']
336 setupVirtualenv(venv, 'python2', requirements, null, false, clean)
337}