blob: a8f0d56dfe299fba957c09643a087f5e21971454 [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 *
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +000012 * @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 */
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +000017def 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
Jakub Josef87a8a3c2018-01-26 12:11:11 +010020 def offlineDeployment = env.getEnvironment().containsKey("OFFLINE_DEPLOYMENT") && env["OFFLINE_DEPLOYMENT"].toBoolean()
Mykyta Karpin1e4bfc92017-11-01 14:38:25 +020021 def virtualenv_cmd = "virtualenv ${path} --python ${python}"
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +000022 if (useSystemPackages) {
Jakub Josef996f4ef2017-10-24 13:20:43 +020023 virtualenv_cmd += " --system-site-packages"
24 }
Tomáš Kukrál69c25452017-07-27 14:59:40 +020025 if (clean) {
26 common.infoMsg("Cleaning venv directory " + path)
27 sh("rm -rf \"${path}\"")
28 }
29
Vasyl Saienkoeed46772020-01-21 12:48:59 +000030 if (offlineDeployment) {
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +000031 virtualenv_cmd += " --no-download"
Vasyl Saienkoeed46772020-01-21 12:48:59 +000032 }
Tomáš Kukrál69c25452017-07-27 14:59:40 +020033 common.infoMsg("[Python ${path}] Setup ${python} environment")
Sergey Kolekonovba203982016-12-21 18:32:17 +040034 sh(returnStdout: true, script: virtualenv_cmd)
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +000035 if (!offlineDeployment) {
36 try {
Denis Egorenko89171f92019-11-12 13:49:23 +040037 def pipPackage = 'pip'
38 if (python == 'python2') {
39 pipPackage = "\"pip<=19.3.1\""
40 common.infoMsg("Pinning pip package due to end of life of Python2 to ${pipPackage} version.")
41 }
Vasyl Saienko9a2bd372020-01-13 10:00:04 +020042 // NOTE(vsaienko): pin setuptools explicitly for latest version that works with python2
Vasyl Saienkoeed46772020-01-21 12:48:59 +000043 runVirtualenvCommand(path, "pip install -U \"setuptools<45.0.0\" ${pipPackage}")
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +000044 } catch (Exception e) {
45 common.warningMsg("Setuptools and pip cannot be updated, you might be offline but OFFLINE_DEPLOYMENT global property not initialized!")
46 }
Yuriy Taraday67352e92017-10-12 10:54:23 +000047 }
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +000048 if (reqs_path == null) {
Vladislav Naumov11103862017-07-19 17:02:39 +030049 def args = ""
50 for (req in reqs) {
51 args = args + "${req}\n"
52 }
53 writeFile file: "${path}/requirements.txt", text: args
54 reqs_path = "${path}/requirements.txt"
Sergey Kolekonovba203982016-12-21 18:32:17 +040055 }
Vladimir Khlyunev16d00012022-02-24 14:14:44 +040056
57 def install_cmd = 'pip install'
58 if (offlineDeployment) {
59 install_cmd += " --find-links=/opt/pip-mirror "
60 }
61 runVirtualenvCommand(path, "${install_cmd} -r ${reqs_path}", true)
Sergey Kolekonovba203982016-12-21 18:32:17 +040062}
63
64/**
65 * Run command in specific python virtualenv
66 *
azvyagintsev386e94e2019-06-13 13:39:04 +030067 * @param path Path to virtualenv
68 * @param cmd Command to be executed
Jakub Josefe2f4ebb2018-01-15 16:11:51 +010069 * @param silent dont print any messages (optional, default false)
azvyagintsev386e94e2019-06-13 13:39:04 +030070 * @param flexAnswer return answer like a dict, with format ['status' : int, 'stderr' : str, 'stdout' : str ]
Sergey Kolekonovba203982016-12-21 18:32:17 +040071 */
azvyagintsev386e94e2019-06-13 13:39:04 +030072def runVirtualenvCommand(path, cmd, silent = false, flexAnswer = false) {
Tomáš Kukrál69c25452017-07-27 14:59:40 +020073 def common = new com.mirantis.mk.Common()
azvyagintsev386e94e2019-06-13 13:39:04 +030074 def res
75 def virtualenv_cmd = "set +x; . ${path}/bin/activate; ${cmd}"
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +000076 if (!silent) {
Jakub Josefe2f4ebb2018-01-15 16:11:51 +010077 common.infoMsg("[Python ${path}] Run command ${cmd}")
78 }
azvyagintsev386e94e2019-06-13 13:39:04 +030079 if (flexAnswer) {
80 res = common.shCmdStatus(virtualenv_cmd)
81 } else {
82 res = sh(
83 returnStdout: true,
84 script: virtualenv_cmd
85 ).trim()
86 }
87 return res
Sergey Kolekonovba203982016-12-21 18:32:17 +040088}
89
Ales Komarekd874d482016-12-26 10:33:29 +010090/**
Dennis Dmitriev8ac1fe72019-08-01 06:16:49 +030091 * Another command runner to control outputs and exit code
92 *
93 * - always print the executing command to control the pipeline execution
94 * - always allows to get the stdout/stderr/status in the result, even with enabled console enabled
95 * - throws an exception with stderr content, so it could be read from the job status and processed
96 *
97 * @param cmd String, command to be executed
98 * @param virtualenv String, path to Python virtualenv (optional, default: '')
99 * @param verbose Boolean, true: (default) mirror stdout to console and to the result['stdout'] at the same time,
100 * false: store stdout only to result['stdout']
101 * @param check_status Boolean, true: (default) throw an exception which contains result['stderr'] if exit code is not 0,
102 * false: only print stderr if not empty, and return the result
103 * @return Map, ['status' : int, 'stderr' : str, 'stdout' : str ]
104 */
105def runCmd(String cmd, String virtualenv='', Boolean verbose=true, Boolean check_status=true) {
106 def common = new com.mirantis.mk.Common()
107
108 def script
109 def redirect_output
110 def result = [:]
111 def stdout_path = sh(script: '#!/bin/bash +x\nmktemp', returnStdout: true).trim()
112 def stderr_path = sh(script: '#!/bin/bash +x\nmktemp', returnStdout: true).trim()
113
114 if (verbose) {
115 // show stdout to console and store to stdout_path
116 redirect_output = " 1> >(tee -a ${stdout_path}) 2>${stderr_path}"
117 } else {
118 // only store stdout to stdout_path
119 redirect_output = " 1>${stdout_path} 2>${stderr_path}"
120 }
121
122 if (virtualenv) {
123 common.infoMsg("Run shell command in Python virtualenv [${virtualenv}]:\n" + cmd)
124 script = """#!/bin/bash +x
125 . ${virtualenv}/bin/activate
126 ( ${cmd.stripIndent()} ) ${redirect_output}
127 """
128 } else {
129 common.infoMsg('Run shell command:\n' + cmd)
130 script = """#!/bin/bash +x
131 ( ${cmd.stripIndent()} ) ${redirect_output}
132 """
133 }
134
135 result['status'] = sh(script: script, returnStatus: true)
136 result['stdout'] = readFile(stdout_path)
137 result['stderr'] = readFile(stderr_path)
138 def cleanup_script = """#!/bin/bash +x
139 rm ${stdout_path} || true
140 rm ${stderr_path} || true
141 """
142 sh(script: cleanup_script)
143
144 if (result['status'] != 0 && check_status) {
145 def error_message = '\nScript returned exit code: ' + result['status'] + '\n<<<<<< STDERR: >>>>>>\n' + result['stderr']
146 common.errorMsg(error_message)
147 common.printMsg('', 'reset')
148 throw new Exception(error_message)
149 }
150
151 if (result['stderr'] && verbose) {
152 def warning_message = '\nScript returned exit code: ' + result['status'] + '\n<<<<<< STDERR: >>>>>>\n' + result['stderr']
153 common.warningMsg(warning_message)
154 common.printMsg('', 'reset')
155 }
156
157 return result
158}
159
160/**
Ales Komarekd874d482016-12-26 10:33:29 +0100161 * Install docutils in isolated environment
162 *
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000163 * @param path Path where virtualenv is created
Ales Komarekd874d482016-12-26 10:33:29 +0100164 */
Vasyl Saienko9a2bd372020-01-13 10:00:04 +0200165def setupDocutilsVirtualenv(path, python="python2") {
Ales Komarekd874d482016-12-26 10:33:29 +0100166 requirements = [
Denis Egorenko97ef0fb2020-01-13 14:22:49 +0400167 'docutils==0.16',
Ales Komarekd874d482016-12-26 10:33:29 +0100168 ]
Vasyl Saienko9a2bd372020-01-13 10:00:04 +0200169 setupVirtualenv(path, python, requirements)
Ales Komarekd874d482016-12-26 10:33:29 +0100170}
171
172
Sergey Kolekonovba203982016-12-21 18:32:17 +0400173@NonCPS
174def loadJson(rawData) {
175 return new groovy.json.JsonSlurperClassic().parseText(rawData)
176}
177
178/**
179 * Parse content from markup-text tables to variables
180 *
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000181 * @param tableStr String representing the table
182 * @param mode Either list (1st row are keys) or item (key, value rows)
183 * @param format Format of the table
Sergey Kolekonovba203982016-12-21 18:32:17 +0400184 */
Ales Komarekd874d482016-12-26 10:33:29 +0100185def parseTextTable(tableStr, type = 'item', format = 'rest', path = none) {
Ales Komarek0e558ee2016-12-23 13:02:55 +0100186 parserFile = "${env.WORKSPACE}/textTableParser.py"
187 parserScript = """import json
188import argparse
189from docutils.parsers.rst import tableparser
190from docutils import statemachine
191
192def parse_item_table(raw_data):
193 i = 1
194 pretty_raw_data = []
195 for datum in raw_data:
196 if datum != "":
197 if datum[3] != ' ' and i > 4:
198 pretty_raw_data.append(raw_data[0])
199 if i == 3:
200 pretty_raw_data.append(datum.replace('-', '='))
201 else:
202 pretty_raw_data.append(datum)
203 i += 1
204 parser = tableparser.GridTableParser()
205 block = statemachine.StringList(pretty_raw_data)
206 docutils_data = parser.parse(block)
207 final_data = {}
208 for line in docutils_data[2]:
209 key = ' '.join(line[0][3]).strip()
210 value = ' '.join(line[1][3]).strip()
211 if key != "":
212 try:
213 value = json.loads(value)
214 except:
215 pass
216 final_data[key] = value
217 i+=1
218 return final_data
219
220def parse_list_table(raw_data):
221 i = 1
222 pretty_raw_data = []
223 for datum in raw_data:
224 if datum != "":
225 if datum[3] != ' ' and i > 4:
226 pretty_raw_data.append(raw_data[0])
227 if i == 3:
228 pretty_raw_data.append(datum.replace('-', '='))
229 else:
230 pretty_raw_data.append(datum)
231 i += 1
232 parser = tableparser.GridTableParser()
233 block = statemachine.StringList(pretty_raw_data)
234 docutils_data = parser.parse(block)
235 final_data = []
236 keys = []
237 for line in docutils_data[1]:
238 for item in line:
239 keys.append(' '.join(item[3]).strip())
240 for line in docutils_data[2]:
241 final_line = {}
242 key = ' '.join(line[0][3]).strip()
243 value = ' '.join(line[1][3]).strip()
244 if key != "":
245 try:
246 value = json.loads(value)
247 except:
248 pass
249 final_data[key] = value
250 i+=1
251 return final_data
252
253def parse_list_table(raw_data):
254 i = 1
255 pretty_raw_data = []
256 for datum in raw_data:
257 if datum != "":
258 if datum[3] != ' ' and i > 4:
259 pretty_raw_data.append(raw_data[0])
260 if i == 3:
261 pretty_raw_data.append(datum.replace('-', '='))
262 else:
263 pretty_raw_data.append(datum)
264 i += 1
265 parser = tableparser.GridTableParser()
266 block = statemachine.StringList(pretty_raw_data)
267 docutils_data = parser.parse(block)
268 final_data = []
269 keys = []
270 for line in docutils_data[1]:
271 for item in line:
272 keys.append(' '.join(item[3]).strip())
273 for line in docutils_data[2]:
274 final_line = {}
275 i = 0
276 for item in line:
277 value = ' '.join(item[3]).strip()
278 try:
279 value = json.loads(value)
280 except:
281 pass
282 final_line[keys[i]] = value
283 i += 1
284 final_data.append(final_line)
285 return final_data
286
287def read_table_file(file):
288 table_file = open(file, 'r')
Ales Komarekc000c152016-12-23 15:32:54 +0100289 raw_data = table_file.read().split('\\n')
Ales Komarek0e558ee2016-12-23 13:02:55 +0100290 table_file.close()
291 return raw_data
292
293parser = argparse.ArgumentParser()
294parser.add_argument('-f','--file', help='File with table data', required=True)
295parser.add_argument('-t','--type', help='Type of table (list/item)', required=True)
296args = vars(parser.parse_args())
297
298raw_data = read_table_file(args['file'])
299
300if args['type'] == 'list':
301 final_data = parse_list_table(raw_data)
302else:
303 final_data = parse_item_table(raw_data)
304
305print json.dumps(final_data)
306"""
307 writeFile file: parserFile, text: parserScript
Sergey Kolekonovba203982016-12-21 18:32:17 +0400308 tableFile = "${env.WORKSPACE}/prettytable.txt"
309 writeFile file: tableFile, text: tableStr
Ales Komarekd874d482016-12-26 10:33:29 +0100310
311 cmd = "python ${parserFile} --file '${tableFile}' --type ${type}"
312 if (path) {
Ales Komarekc6d28dd2016-12-28 12:59:38 +0100313 rawData = runVirtualenvCommand(path, cmd)
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000314 } else {
315 rawData = sh(
Ales Komarekd874d482016-12-26 10:33:29 +0100316 script: cmd,
317 returnStdout: true
318 ).trim()
319 }
Sergey Kolekonovba203982016-12-21 18:32:17 +0400320 data = loadJson(rawData)
321 echo("[Parsed table] ${data}")
322 return data
323}
324
325/**
326 * Install cookiecutter in isolated environment
327 *
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000328 * @param path Path where virtualenv is created
Sergey Kolekonovba203982016-12-21 18:32:17 +0400329 */
330def setupCookiecutterVirtualenv(path) {
331 requirements = [
332 'cookiecutter',
Jakub Josef4df78272017-04-26 14:36:36 +0200333 'jinja2==2.8.1',
Dmitry Pyzhovb883a2d2018-12-14 16:42:52 +0300334 'PyYAML==3.12',
335 'python-gnupg==0.4.3'
Sergey Kolekonovba203982016-12-21 18:32:17 +0400336 ]
337 setupVirtualenv(path, 'python2', requirements)
338}
339
340/**
341 * Generate the cookiecutter templates with given context
342 *
Jakub Josef4e10c372017-04-26 14:13:50 +0200343 * @param template template
344 * @param context template context
345 * @param path Path where virtualenv is created (optional)
346 * @param templatePath path to cookiecutter template repo (optional)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400347 */
Jakub Josef4e10c372017-04-26 14:13:50 +0200348def buildCookiecutterTemplate(template, context, outputDir = '.', path = null, templatePath = ".") {
azvyagintsev7a123aa2019-01-09 21:38:56 +0200349 def common = new com.mirantis.mk.Common()
Tomáš Kukráldad7b462017-03-27 13:53:05 +0200350 configFile = "default_config.yaml"
Tomáš Kukrál6de85042017-04-12 17:49:05 +0200351 writeFile file: configFile, text: context
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000352 common.warningMsg('Old Cookiecutter env detected!')
353 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"
354 output = sh(returnStdout: true, script: command)
355 common.infoMsg('[Cookiecutter build] Result:' + output)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400356}
357
358/**
Denis Egorenko6c2e3ae2018-10-17 16:45:56 +0400359 *
360 * @param context - context template
361 * @param contextName - context template name
362 * @param saltMasterName - hostname of Salt Master node
363 * @param virtualenv - pyvenv with CC and dep's
364 * @param templateEnvDir - root of CookieCutter
365 * @return
366 */
367def generateModel(context, contextName, saltMasterName, virtualenv, modelEnv, templateEnvDir, multiModels = true) {
Denis Egorenkofa2c6752018-10-18 15:51:45 +0400368 def common = new com.mirantis.mk.Common()
Denis Egorenko6c2e3ae2018-10-17 16:45:56 +0400369 def generatedModel = multiModels ? "${modelEnv}/${contextName}" : modelEnv
370 def templateContext = readYaml text: context
371 def clusterDomain = templateContext.default_context.cluster_domain
372 def clusterName = templateContext.default_context.cluster_name
373 def outputDestination = "${generatedModel}/classes/cluster/${clusterName}"
374 def templateBaseDir = templateEnvDir
375 def templateDir = "${templateEnvDir}/dir"
376 def templateOutputDir = templateBaseDir
377 dir(templateEnvDir) {
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000378 if (fileExists(new File(templateEnvDir, 'tox.ini').toString())) {
Aleksey Zvyagintsev07b07ba2019-02-28 13:34:13 +0000379 def tempContextFile = new File(templateEnvDir, 'tempContext.yaml').toString()
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000380 writeFile file: tempContextFile, text: context
381 common.warningMsg('Generating models using context:\n')
382 print(context)
383 withEnv(["CONFIG_FILE=$tempContextFile",
Aleksey Zvyagintsev07b07ba2019-02-28 13:34:13 +0000384 "OUTPUT_DIR=${modelEnv}",
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000385 ]) {
386 print('[Cookiecutter build] Result:\n' +
387 sh(returnStdout: true, script: 'tox -ve generate_auto'))
Aleksey Zvyagintsev4c745e52019-02-21 10:30:02 +0000388 }
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000389 } else {
390 common.warningMsg("Old format: Generating model from context ${contextName}")
391 def productList = ["infra", "cicd", "kdt", "opencontrail", "kubernetes", "openstack", "oss", "stacklight", "ceph"]
392 for (product in productList) {
393 // get templateOutputDir and productDir
394 templateOutputDir = "${templateEnvDir}/output/${product}"
395 productDir = product
396 templateDir = "${templateEnvDir}/cluster_product/${productDir}"
397 // Bw for 2018.8.1 and older releases
398 if (product.startsWith("stacklight") && (!fileExists(templateDir))) {
399 common.warningMsg("Old release detected! productDir => 'stacklight2' ")
400 productDir = "stacklight2"
401 templateDir = "${templateEnvDir}/cluster_product/${productDir}"
402 }
403 // generate infra unless its explicitly disabled
404 if ((product == "infra" && templateContext.default_context.get("infra_enabled", "True").toBoolean())
405 || (templateContext.default_context.get(product + "_enabled", "False").toBoolean())) {
406
407 common.infoMsg("Generating product " + product + " from " + templateDir + " to " + templateOutputDir)
408
409 sh "rm -rf ${templateOutputDir} || true"
410 sh "mkdir -p ${templateOutputDir}"
411 sh "mkdir -p ${outputDestination}"
412
413 buildCookiecutterTemplate(templateDir, context, templateOutputDir, virtualenv, templateBaseDir)
414 sh "mv -v ${templateOutputDir}/${clusterName}/* ${outputDestination}"
415 } else {
416 common.warningMsg("Product " + product + " is disabled")
417 }
418 }
419
420 def localRepositories = templateContext.default_context.local_repositories
421 localRepositories = localRepositories ? localRepositories.toBoolean() : false
422 def offlineDeployment = templateContext.default_context.offline_deployment
423 offlineDeployment = offlineDeployment ? offlineDeployment.toBoolean() : false
424 if (localRepositories && !offlineDeployment) {
425 def mcpVersion = templateContext.default_context.mcp_version
426 def aptlyModelUrl = templateContext.default_context.local_model_url
427 def ssh = new com.mirantis.mk.Ssh()
428 dir(path: modelEnv) {
429 ssh.agentSh "git submodule add \"${aptlyModelUrl}\" \"classes/cluster/${clusterName}/cicd/aptly\""
430 if (!(mcpVersion in ["nightly", "testing", "stable"])) {
431 ssh.agentSh "cd \"classes/cluster/${clusterName}/cicd/aptly\";git fetch --tags;git checkout ${mcpVersion}"
432 }
433 }
434 }
435
436 def nodeFile = "${generatedModel}/nodes/${saltMasterName}.${clusterDomain}.yml"
437 def nodeString = """classes:
438- cluster.${clusterName}.infra.config
439parameters:
440 _param:
441 linux_system_codename: xenial
442 reclass_data_revision: master
443 linux:
444 system:
445 name: ${saltMasterName}
446 domain: ${clusterDomain}
447 """
448 sh "mkdir -p ${generatedModel}/nodes/"
449 writeFile(file: nodeFile, text: nodeString)
450 }
Denis Egorenko6c2e3ae2018-10-17 16:45:56 +0400451 }
452}
453
454/**
Sergey Kolekonovba203982016-12-21 18:32:17 +0400455 * Install jinja rendering in isolated environment
456 *
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000457 * @param path Path where virtualenv is created
Sergey Kolekonovba203982016-12-21 18:32:17 +0400458 */
459def setupJinjaVirtualenv(path) {
460 requirements = [
Denis Egorenko97ef0fb2020-01-13 14:22:49 +0400461 'jinja2-cli==0.7.0',
462 'pyyaml==5.3',
Sergey Kolekonovba203982016-12-21 18:32:17 +0400463 ]
464 setupVirtualenv(path, 'python2', requirements)
465}
466
467/**
468 * Generate the Jinja templates with given context
469 *
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000470 * @param path Path where virtualenv is created
Sergey Kolekonovba203982016-12-21 18:32:17 +0400471 */
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000472def jinjaBuildTemplate(template, context, path = none) {
Sergey Kolekonovba203982016-12-21 18:32:17 +0400473 contextFile = "jinja_context.yml"
474 contextString = ""
475 for (parameter in context) {
476 contextString = "${contextString}${parameter.key}: ${parameter.value}\n"
477 }
478 writeFile file: contextFile, text: contextString
479 cmd = "jinja2 ${template} ${contextFile} --format=yaml"
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000480 data = sh(returnStdout: true, script: cmd)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400481 echo(data)
482 return data
483}
Oleg Grigorovbec45582017-09-12 20:29:24 +0300484
485/**
486 * Install salt-pepper in isolated environment
487 *
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000488 * @param path Path where virtualenv is created
489 * @param url SALT_MASTER_URL
490 * @param credentialsId Credentials to salt api
Oleg Grigorovbec45582017-09-12 20:29:24 +0300491 */
Oleksandr Kononenkoa63f3872021-12-08 10:42:27 +0200492def setupPepperVirtualenv(path, url, credentialsId, python_version = 'python2', useSystemPackages = true) {
chnydaa0dbb252017-10-05 10:46:09 +0200493 def common = new com.mirantis.mk.Common()
494
495 // virtualenv setup
Mykyta Karpin81756c92018-03-02 13:03:26 +0200496 // pin pepper till https://mirantis.jira.com/browse/PROD-18188 is fixed
497 requirements = ['salt-pepper>=0.5.2,<0.5.4']
Oleksandr Kononenkoa63f3872021-12-08 10:42:27 +0200498 setupVirtualenv(path, python_version, requirements, null, true, useSystemPackages)
chnydabcfff182017-11-29 10:24:36 +0100499
chnydaa0dbb252017-10-05 10:46:09 +0200500 // pepperrc creation
501 rcFile = "${path}/pepperrc"
502 creds = common.getPasswordCredentials(credentialsId)
503 rc = """\
504[main]
505SALTAPI_EAUTH=pam
506SALTAPI_URL=${url}
507SALTAPI_USER=${creds.username}
508SALTAPI_PASS=${creds.password.toString()}
509"""
510 writeFile file: rcFile, text: rc
511 return rcFile
Jakub Josefd067f612017-09-26 13:42:56 +0200512}
Oleh Hryhorov44569fb2017-10-26 17:04:55 +0300513
514/**
515 * Install devops in isolated environment
516 *
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000517 * @param path Path where virtualenv is created
518 * @param clean Define to true is the venv have to cleaned up before install a new one
Oleh Hryhorov44569fb2017-10-26 17:04:55 +0300519 */
Aleksey Zvyagintsevc4f66f62019-02-21 10:39:34 +0000520def setupDevOpsVenv(venv, clean = false) {
Oleh Hryhorov44569fb2017-10-26 17:04:55 +0300521 requirements = ['git+https://github.com/openstack/fuel-devops.git']
522 setupVirtualenv(venv, 'python2', requirements, null, false, clean)
523}