blob: 0ac72fca73ef75a7d2b9bf02a946206e8425886e [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
Yuriy Taraday67352e92017-10-12 10:54:23 +000020 def virtualenv_cmd = "[ -d ${path} ] || 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)
Yuriy Taraday67352e92017-10-12 10:54:23 +000031 try {
32 runVirtualenvCommand(path, "pip install -U setuptools pip")
33 } catch(Exception e) {
Jakub Josef781e6ec2017-10-18 14:13:13 +020034 common.warningMsg("Setuptools and pip cannot be updated, you might be offline")
Yuriy Taraday67352e92017-10-12 10:54:23 +000035 }
Vladislav Naumov11103862017-07-19 17:02:39 +030036 if (reqs_path==null) {
37 def args = ""
38 for (req in reqs) {
39 args = args + "${req}\n"
40 }
41 writeFile file: "${path}/requirements.txt", text: args
42 reqs_path = "${path}/requirements.txt"
Sergey Kolekonovba203982016-12-21 18:32:17 +040043 }
Vladislav Naumov11103862017-07-19 17:02:39 +030044 runVirtualenvCommand(path, "pip install -r ${reqs_path}")
Sergey Kolekonovba203982016-12-21 18:32:17 +040045}
46
47/**
48 * Run command in specific python virtualenv
49 *
50 * @param path Path to virtualenv
51 * @param cmd Command to be executed
52 */
53def runVirtualenvCommand(path, cmd) {
Tomáš Kukrál69c25452017-07-27 14:59:40 +020054 def common = new com.mirantis.mk.Common()
55
Jakub Josef0164dc12017-03-28 16:33:46 +020056 virtualenv_cmd = ". ${path}/bin/activate > /dev/null; ${cmd}"
Tomáš Kukrál69c25452017-07-27 14:59:40 +020057 common.infoMsg("[Python ${path}] Run command ${cmd}")
Sergey Kolekonovba203982016-12-21 18:32:17 +040058 output = sh(
59 returnStdout: true,
60 script: virtualenv_cmd
61 ).trim()
62 return output
63}
64
Ales Komarekd874d482016-12-26 10:33:29 +010065
66/**
67 * Install docutils in isolated environment
68 *
69 * @param path Path where virtualenv is created
70 */
71def setupDocutilsVirtualenv(path) {
72 requirements = [
73 'docutils',
74 ]
75 setupVirtualenv(path, 'python2', requirements)
76}
77
78
Sergey Kolekonovba203982016-12-21 18:32:17 +040079@NonCPS
80def loadJson(rawData) {
81 return new groovy.json.JsonSlurperClassic().parseText(rawData)
82}
83
84/**
85 * Parse content from markup-text tables to variables
86 *
87 * @param tableStr String representing the table
88 * @param mode Either list (1st row are keys) or item (key, value rows)
89 * @param format Format of the table
90 */
Ales Komarekd874d482016-12-26 10:33:29 +010091def parseTextTable(tableStr, type = 'item', format = 'rest', path = none) {
Ales Komarek0e558ee2016-12-23 13:02:55 +010092 parserFile = "${env.WORKSPACE}/textTableParser.py"
93 parserScript = """import json
94import argparse
95from docutils.parsers.rst import tableparser
96from docutils import statemachine
97
98def parse_item_table(raw_data):
99 i = 1
100 pretty_raw_data = []
101 for datum in raw_data:
102 if datum != "":
103 if datum[3] != ' ' and i > 4:
104 pretty_raw_data.append(raw_data[0])
105 if i == 3:
106 pretty_raw_data.append(datum.replace('-', '='))
107 else:
108 pretty_raw_data.append(datum)
109 i += 1
110 parser = tableparser.GridTableParser()
111 block = statemachine.StringList(pretty_raw_data)
112 docutils_data = parser.parse(block)
113 final_data = {}
114 for line in docutils_data[2]:
115 key = ' '.join(line[0][3]).strip()
116 value = ' '.join(line[1][3]).strip()
117 if key != "":
118 try:
119 value = json.loads(value)
120 except:
121 pass
122 final_data[key] = value
123 i+=1
124 return final_data
125
126def parse_list_table(raw_data):
127 i = 1
128 pretty_raw_data = []
129 for datum in raw_data:
130 if datum != "":
131 if datum[3] != ' ' and i > 4:
132 pretty_raw_data.append(raw_data[0])
133 if i == 3:
134 pretty_raw_data.append(datum.replace('-', '='))
135 else:
136 pretty_raw_data.append(datum)
137 i += 1
138 parser = tableparser.GridTableParser()
139 block = statemachine.StringList(pretty_raw_data)
140 docutils_data = parser.parse(block)
141 final_data = []
142 keys = []
143 for line in docutils_data[1]:
144 for item in line:
145 keys.append(' '.join(item[3]).strip())
146 for line in docutils_data[2]:
147 final_line = {}
148 key = ' '.join(line[0][3]).strip()
149 value = ' '.join(line[1][3]).strip()
150 if key != "":
151 try:
152 value = json.loads(value)
153 except:
154 pass
155 final_data[key] = value
156 i+=1
157 return final_data
158
159def parse_list_table(raw_data):
160 i = 1
161 pretty_raw_data = []
162 for datum in raw_data:
163 if datum != "":
164 if datum[3] != ' ' and i > 4:
165 pretty_raw_data.append(raw_data[0])
166 if i == 3:
167 pretty_raw_data.append(datum.replace('-', '='))
168 else:
169 pretty_raw_data.append(datum)
170 i += 1
171 parser = tableparser.GridTableParser()
172 block = statemachine.StringList(pretty_raw_data)
173 docutils_data = parser.parse(block)
174 final_data = []
175 keys = []
176 for line in docutils_data[1]:
177 for item in line:
178 keys.append(' '.join(item[3]).strip())
179 for line in docutils_data[2]:
180 final_line = {}
181 i = 0
182 for item in line:
183 value = ' '.join(item[3]).strip()
184 try:
185 value = json.loads(value)
186 except:
187 pass
188 final_line[keys[i]] = value
189 i += 1
190 final_data.append(final_line)
191 return final_data
192
193def read_table_file(file):
194 table_file = open(file, 'r')
Ales Komarekc000c152016-12-23 15:32:54 +0100195 raw_data = table_file.read().split('\\n')
Ales Komarek0e558ee2016-12-23 13:02:55 +0100196 table_file.close()
197 return raw_data
198
199parser = argparse.ArgumentParser()
200parser.add_argument('-f','--file', help='File with table data', required=True)
201parser.add_argument('-t','--type', help='Type of table (list/item)', required=True)
202args = vars(parser.parse_args())
203
204raw_data = read_table_file(args['file'])
205
206if args['type'] == 'list':
207 final_data = parse_list_table(raw_data)
208else:
209 final_data = parse_item_table(raw_data)
210
211print json.dumps(final_data)
212"""
213 writeFile file: parserFile, text: parserScript
Sergey Kolekonovba203982016-12-21 18:32:17 +0400214 tableFile = "${env.WORKSPACE}/prettytable.txt"
215 writeFile file: tableFile, text: tableStr
Ales Komarekd874d482016-12-26 10:33:29 +0100216
217 cmd = "python ${parserFile} --file '${tableFile}' --type ${type}"
218 if (path) {
Ales Komarekc6d28dd2016-12-28 12:59:38 +0100219 rawData = runVirtualenvCommand(path, cmd)
Ales Komarekd874d482016-12-26 10:33:29 +0100220 }
221 else {
222 rawData = sh (
223 script: cmd,
224 returnStdout: true
225 ).trim()
226 }
Sergey Kolekonovba203982016-12-21 18:32:17 +0400227 data = loadJson(rawData)
228 echo("[Parsed table] ${data}")
229 return data
230}
231
232/**
233 * Install cookiecutter in isolated environment
234 *
235 * @param path Path where virtualenv is created
236 */
237def setupCookiecutterVirtualenv(path) {
238 requirements = [
239 'cookiecutter',
Jakub Josef4df78272017-04-26 14:36:36 +0200240 'jinja2==2.8.1',
241 'PyYAML==3.12'
Sergey Kolekonovba203982016-12-21 18:32:17 +0400242 ]
243 setupVirtualenv(path, 'python2', requirements)
244}
245
246/**
247 * Generate the cookiecutter templates with given context
248 *
Jakub Josef4e10c372017-04-26 14:13:50 +0200249 * @param template template
250 * @param context template context
251 * @param path Path where virtualenv is created (optional)
252 * @param templatePath path to cookiecutter template repo (optional)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400253 */
Jakub Josef4e10c372017-04-26 14:13:50 +0200254def buildCookiecutterTemplate(template, context, outputDir = '.', path = null, templatePath = ".") {
Tomáš Kukráldad7b462017-03-27 13:53:05 +0200255 configFile = "default_config.yaml"
256 configString = "default_context:\n"
Tomáš Kukrál6de85042017-04-12 17:49:05 +0200257 writeFile file: configFile, text: context
Jakub Josef4e61cc02017-04-26 14:29:09 +0200258 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 +0400259 output = sh (returnStdout: true, script: command)
260 echo("[Cookiecutter build] Output: ${output}")
261}
262
263/**
264 * Install jinja rendering in isolated environment
265 *
266 * @param path Path where virtualenv is created
267 */
268def setupJinjaVirtualenv(path) {
269 requirements = [
270 'jinja2-cli',
271 'pyyaml',
272 ]
273 setupVirtualenv(path, 'python2', requirements)
274}
275
276/**
277 * Generate the Jinja templates with given context
278 *
279 * @param path Path where virtualenv is created
280 */
281def jinjaBuildTemplate (template, context, path = none) {
282 contextFile = "jinja_context.yml"
283 contextString = ""
284 for (parameter in context) {
285 contextString = "${contextString}${parameter.key}: ${parameter.value}\n"
286 }
287 writeFile file: contextFile, text: contextString
288 cmd = "jinja2 ${template} ${contextFile} --format=yaml"
289 data = sh (returnStdout: true, script: cmd)
290 echo(data)
291 return data
292}
Oleg Grigorovbec45582017-09-12 20:29:24 +0300293
294/**
295 * Install salt-pepper in isolated environment
296 *
297 * @param path Path where virtualenv is created
chnydaa0dbb252017-10-05 10:46:09 +0200298 * @param url SALT_MASTER_URL
299 * @param credentialsId Credentials to salt api
Oleg Grigorovbec45582017-09-12 20:29:24 +0300300 */
chnydaa0dbb252017-10-05 10:46:09 +0200301def setupPepperVirtualenv(path, url, credentialsId) {
302 def common = new com.mirantis.mk.Common()
303
304 // virtualenv setup
chnydab38216a2017-10-12 09:46:32 +0200305 requirements = ['salt-pepper']
Jakub Josef996f4ef2017-10-24 13:20:43 +0200306 setupVirtualenv(path, 'python2', requirements, null, false, true)
chnydaa0dbb252017-10-05 10:46:09 +0200307
308 // pepperrc creation
309 rcFile = "${path}/pepperrc"
310 creds = common.getPasswordCredentials(credentialsId)
311 rc = """\
312[main]
313SALTAPI_EAUTH=pam
314SALTAPI_URL=${url}
315SALTAPI_USER=${creds.username}
316SALTAPI_PASS=${creds.password.toString()}
317"""
318 writeFile file: rcFile, text: rc
319 return rcFile
Jakub Josefd067f612017-09-26 13:42:56 +0200320}