| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 1 | package com.mirantis.mk | 
|  | 2 |  | 
|  | 3 | /** | 
|  | 4 | * | 
|  | 5 | * Python functions | 
|  | 6 | * | 
|  | 7 | */ | 
|  | 8 |  | 
|  | 9 | /** | 
|  | 10 | * Install python virtualenv | 
|  | 11 | * | 
| Vladislav Naumov | 1110386 | 2017-07-19 17:02:39 +0300 | [diff] [blame] | 12 | * @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 Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 16 | */ | 
| Jakub Josef | 996f4ef | 2017-10-24 13:20:43 +0200 | [diff] [blame] | 17 | def setupVirtualenv(path, python = 'python2', reqs=[], reqs_path=null, clean=false, useSystemPackages=false) { | 
| Tomáš Kukrál | 69c2545 | 2017-07-27 14:59:40 +0200 | [diff] [blame] | 18 | def common = new com.mirantis.mk.Common() | 
|  | 19 |  | 
| Jakub Josef | 87a8a3c | 2018-01-26 12:11:11 +0100 | [diff] [blame] | 20 | def offlineDeployment = env.getEnvironment().containsKey("OFFLINE_DEPLOYMENT") && env["OFFLINE_DEPLOYMENT"].toBoolean() | 
| Mykyta Karpin | 1e4bfc9 | 2017-11-01 14:38:25 +0200 | [diff] [blame] | 21 | def virtualenv_cmd = "virtualenv ${path} --python ${python}" | 
| Jakub Josef | 996f4ef | 2017-10-24 13:20:43 +0200 | [diff] [blame] | 22 | if (useSystemPackages){ | 
|  | 23 | virtualenv_cmd += " --system-site-packages" | 
|  | 24 | } | 
| Tomáš Kukrál | 69c2545 | 2017-07-27 14:59:40 +0200 | [diff] [blame] | 25 | if (clean) { | 
|  | 26 | common.infoMsg("Cleaning venv directory " + path) | 
|  | 27 | sh("rm -rf \"${path}\"") | 
|  | 28 | } | 
|  | 29 |  | 
| Jakub Josef | 87a8a3c | 2018-01-26 12:11:11 +0100 | [diff] [blame] | 30 | if(offlineDeployment){ | 
|  | 31 | virtualenv_cmd+=" --no-download" | 
|  | 32 | } | 
| Tomáš Kukrál | 69c2545 | 2017-07-27 14:59:40 +0200 | [diff] [blame] | 33 | common.infoMsg("[Python ${path}] Setup ${python} environment") | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 34 | sh(returnStdout: true, script: virtualenv_cmd) | 
| Jakub Josef | 87a8a3c | 2018-01-26 12:11:11 +0100 | [diff] [blame] | 35 | if(!offlineDeployment){ | 
| Jakub Josef | 5f97d53 | 2017-11-29 18:51:41 +0100 | [diff] [blame] | 36 | try { | 
| Jakub Josef | a2491ad | 2018-01-15 16:26:27 +0100 | [diff] [blame] | 37 | runVirtualenvCommand(path, "pip install -U setuptools pip") | 
| Jakub Josef | 5f97d53 | 2017-11-29 18:51:41 +0100 | [diff] [blame] | 38 | } catch(Exception e) { | 
| Jakub Josef | a2491ad | 2018-01-15 16:26:27 +0100 | [diff] [blame] | 39 | common.warningMsg("Setuptools and pip cannot be updated, you might be offline but OFFLINE_DEPLOYMENT global property not initialized!") | 
| Jakub Josef | 5f97d53 | 2017-11-29 18:51:41 +0100 | [diff] [blame] | 40 | } | 
| Yuriy Taraday | 67352e9 | 2017-10-12 10:54:23 +0000 | [diff] [blame] | 41 | } | 
| Vladislav Naumov | 1110386 | 2017-07-19 17:02:39 +0300 | [diff] [blame] | 42 | if (reqs_path==null) { | 
|  | 43 | def args = "" | 
|  | 44 | for (req in reqs) { | 
|  | 45 | args = args + "${req}\n" | 
|  | 46 | } | 
|  | 47 | writeFile file: "${path}/requirements.txt", text: args | 
|  | 48 | reqs_path = "${path}/requirements.txt" | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 49 | } | 
| Jakub Josef | a2491ad | 2018-01-15 16:26:27 +0100 | [diff] [blame] | 50 | runVirtualenvCommand(path, "pip install -r ${reqs_path}", true) | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 51 | } | 
|  | 52 |  | 
|  | 53 | /** | 
|  | 54 | * Run command in specific python virtualenv | 
|  | 55 | * | 
|  | 56 | * @param path   Path to virtualenv | 
|  | 57 | * @param cmd    Command to be executed | 
| Jakub Josef | e2f4ebb | 2018-01-15 16:11:51 +0100 | [diff] [blame] | 58 | * @param silent dont print any messages (optional, default false) | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 59 | */ | 
| Jakub Josef | e2f4ebb | 2018-01-15 16:11:51 +0100 | [diff] [blame] | 60 | def runVirtualenvCommand(path, cmd, silent=false) { | 
| Tomáš Kukrál | 69c2545 | 2017-07-27 14:59:40 +0200 | [diff] [blame] | 61 | def common = new com.mirantis.mk.Common() | 
|  | 62 |  | 
| Jakub Josef | 5feeee4 | 2018-01-08 15:50:36 +0100 | [diff] [blame] | 63 | virtualenv_cmd = "set +x; . ${path}/bin/activate; ${cmd}" | 
| Jakub Josef | e2f4ebb | 2018-01-15 16:11:51 +0100 | [diff] [blame] | 64 | if(!silent){ | 
|  | 65 | common.infoMsg("[Python ${path}] Run command ${cmd}") | 
|  | 66 | } | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 67 | output = sh( | 
|  | 68 | returnStdout: true, | 
|  | 69 | script: virtualenv_cmd | 
|  | 70 | ).trim() | 
|  | 71 | return output | 
|  | 72 | } | 
|  | 73 |  | 
| Ales Komarek | d874d48 | 2016-12-26 10:33:29 +0100 | [diff] [blame] | 74 |  | 
|  | 75 | /** | 
|  | 76 | * Install docutils in isolated environment | 
|  | 77 | * | 
|  | 78 | * @param path        Path where virtualenv is created | 
|  | 79 | */ | 
|  | 80 | def setupDocutilsVirtualenv(path) { | 
|  | 81 | requirements = [ | 
|  | 82 | 'docutils', | 
|  | 83 | ] | 
|  | 84 | setupVirtualenv(path, 'python2', requirements) | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 |  | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 88 | @NonCPS | 
|  | 89 | def loadJson(rawData) { | 
|  | 90 | return new groovy.json.JsonSlurperClassic().parseText(rawData) | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | /** | 
|  | 94 | * Parse content from markup-text tables to variables | 
|  | 95 | * | 
|  | 96 | * @param tableStr   String representing the table | 
|  | 97 | * @param mode       Either list (1st row are keys) or item (key, value rows) | 
|  | 98 | * @param format     Format of the table | 
|  | 99 | */ | 
| Ales Komarek | d874d48 | 2016-12-26 10:33:29 +0100 | [diff] [blame] | 100 | def parseTextTable(tableStr, type = 'item', format = 'rest', path = none) { | 
| Ales Komarek | 0e558ee | 2016-12-23 13:02:55 +0100 | [diff] [blame] | 101 | parserFile = "${env.WORKSPACE}/textTableParser.py" | 
|  | 102 | parserScript = """import json | 
|  | 103 | import argparse | 
|  | 104 | from docutils.parsers.rst import tableparser | 
|  | 105 | from docutils import statemachine | 
|  | 106 |  | 
|  | 107 | def parse_item_table(raw_data): | 
|  | 108 | i = 1 | 
|  | 109 | pretty_raw_data = [] | 
|  | 110 | for datum in raw_data: | 
|  | 111 | if datum != "": | 
|  | 112 | if datum[3] != ' ' and i > 4: | 
|  | 113 | pretty_raw_data.append(raw_data[0]) | 
|  | 114 | if i == 3: | 
|  | 115 | pretty_raw_data.append(datum.replace('-', '=')) | 
|  | 116 | else: | 
|  | 117 | pretty_raw_data.append(datum) | 
|  | 118 | i += 1 | 
|  | 119 | parser = tableparser.GridTableParser() | 
|  | 120 | block = statemachine.StringList(pretty_raw_data) | 
|  | 121 | docutils_data = parser.parse(block) | 
|  | 122 | final_data = {} | 
|  | 123 | for line in docutils_data[2]: | 
|  | 124 | key = ' '.join(line[0][3]).strip() | 
|  | 125 | value = ' '.join(line[1][3]).strip() | 
|  | 126 | if key != "": | 
|  | 127 | try: | 
|  | 128 | value = json.loads(value) | 
|  | 129 | except: | 
|  | 130 | pass | 
|  | 131 | final_data[key] = value | 
|  | 132 | i+=1 | 
|  | 133 | return final_data | 
|  | 134 |  | 
|  | 135 | def parse_list_table(raw_data): | 
|  | 136 | i = 1 | 
|  | 137 | pretty_raw_data = [] | 
|  | 138 | for datum in raw_data: | 
|  | 139 | if datum != "": | 
|  | 140 | if datum[3] != ' ' and i > 4: | 
|  | 141 | pretty_raw_data.append(raw_data[0]) | 
|  | 142 | if i == 3: | 
|  | 143 | pretty_raw_data.append(datum.replace('-', '=')) | 
|  | 144 | else: | 
|  | 145 | pretty_raw_data.append(datum) | 
|  | 146 | i += 1 | 
|  | 147 | parser = tableparser.GridTableParser() | 
|  | 148 | block = statemachine.StringList(pretty_raw_data) | 
|  | 149 | docutils_data = parser.parse(block) | 
|  | 150 | final_data = [] | 
|  | 151 | keys = [] | 
|  | 152 | for line in docutils_data[1]: | 
|  | 153 | for item in line: | 
|  | 154 | keys.append(' '.join(item[3]).strip()) | 
|  | 155 | for line in docutils_data[2]: | 
|  | 156 | final_line = {} | 
|  | 157 | key = ' '.join(line[0][3]).strip() | 
|  | 158 | value = ' '.join(line[1][3]).strip() | 
|  | 159 | if key != "": | 
|  | 160 | try: | 
|  | 161 | value = json.loads(value) | 
|  | 162 | except: | 
|  | 163 | pass | 
|  | 164 | final_data[key] = value | 
|  | 165 | i+=1 | 
|  | 166 | return final_data | 
|  | 167 |  | 
|  | 168 | def parse_list_table(raw_data): | 
|  | 169 | i = 1 | 
|  | 170 | pretty_raw_data = [] | 
|  | 171 | for datum in raw_data: | 
|  | 172 | if datum != "": | 
|  | 173 | if datum[3] != ' ' and i > 4: | 
|  | 174 | pretty_raw_data.append(raw_data[0]) | 
|  | 175 | if i == 3: | 
|  | 176 | pretty_raw_data.append(datum.replace('-', '=')) | 
|  | 177 | else: | 
|  | 178 | pretty_raw_data.append(datum) | 
|  | 179 | i += 1 | 
|  | 180 | parser = tableparser.GridTableParser() | 
|  | 181 | block = statemachine.StringList(pretty_raw_data) | 
|  | 182 | docutils_data = parser.parse(block) | 
|  | 183 | final_data = [] | 
|  | 184 | keys = [] | 
|  | 185 | for line in docutils_data[1]: | 
|  | 186 | for item in line: | 
|  | 187 | keys.append(' '.join(item[3]).strip()) | 
|  | 188 | for line in docutils_data[2]: | 
|  | 189 | final_line = {} | 
|  | 190 | i = 0 | 
|  | 191 | for item in line: | 
|  | 192 | value = ' '.join(item[3]).strip() | 
|  | 193 | try: | 
|  | 194 | value = json.loads(value) | 
|  | 195 | except: | 
|  | 196 | pass | 
|  | 197 | final_line[keys[i]] = value | 
|  | 198 | i += 1 | 
|  | 199 | final_data.append(final_line) | 
|  | 200 | return final_data | 
|  | 201 |  | 
|  | 202 | def read_table_file(file): | 
|  | 203 | table_file = open(file, 'r') | 
| Ales Komarek | c000c15 | 2016-12-23 15:32:54 +0100 | [diff] [blame] | 204 | raw_data = table_file.read().split('\\n') | 
| Ales Komarek | 0e558ee | 2016-12-23 13:02:55 +0100 | [diff] [blame] | 205 | table_file.close() | 
|  | 206 | return raw_data | 
|  | 207 |  | 
|  | 208 | parser = argparse.ArgumentParser() | 
|  | 209 | parser.add_argument('-f','--file', help='File with table data', required=True) | 
|  | 210 | parser.add_argument('-t','--type', help='Type of table (list/item)', required=True) | 
|  | 211 | args = vars(parser.parse_args()) | 
|  | 212 |  | 
|  | 213 | raw_data = read_table_file(args['file']) | 
|  | 214 |  | 
|  | 215 | if args['type'] == 'list': | 
|  | 216 | final_data = parse_list_table(raw_data) | 
|  | 217 | else: | 
|  | 218 | final_data = parse_item_table(raw_data) | 
|  | 219 |  | 
|  | 220 | print json.dumps(final_data) | 
|  | 221 | """ | 
|  | 222 | writeFile file: parserFile, text: parserScript | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 223 | tableFile = "${env.WORKSPACE}/prettytable.txt" | 
|  | 224 | writeFile file: tableFile, text: tableStr | 
| Ales Komarek | d874d48 | 2016-12-26 10:33:29 +0100 | [diff] [blame] | 225 |  | 
|  | 226 | cmd = "python ${parserFile} --file '${tableFile}' --type ${type}" | 
|  | 227 | if (path) { | 
| Ales Komarek | c6d28dd | 2016-12-28 12:59:38 +0100 | [diff] [blame] | 228 | rawData = runVirtualenvCommand(path, cmd) | 
| Ales Komarek | d874d48 | 2016-12-26 10:33:29 +0100 | [diff] [blame] | 229 | } | 
|  | 230 | else { | 
|  | 231 | rawData = sh ( | 
|  | 232 | script: cmd, | 
|  | 233 | returnStdout: true | 
|  | 234 | ).trim() | 
|  | 235 | } | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 236 | data = loadJson(rawData) | 
|  | 237 | echo("[Parsed table] ${data}") | 
|  | 238 | return data | 
|  | 239 | } | 
|  | 240 |  | 
|  | 241 | /** | 
|  | 242 | * Install cookiecutter in isolated environment | 
|  | 243 | * | 
|  | 244 | * @param path        Path where virtualenv is created | 
|  | 245 | */ | 
|  | 246 | def setupCookiecutterVirtualenv(path) { | 
|  | 247 | requirements = [ | 
|  | 248 | 'cookiecutter', | 
| Jakub Josef | 4df7827 | 2017-04-26 14:36:36 +0200 | [diff] [blame] | 249 | 'jinja2==2.8.1', | 
| Dmitry Pyzhov | b883a2d | 2018-12-14 16:42:52 +0300 | [diff] [blame^] | 250 | 'PyYAML==3.12', | 
|  | 251 | 'python-gnupg==0.4.3' | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 252 | ] | 
|  | 253 | setupVirtualenv(path, 'python2', requirements) | 
|  | 254 | } | 
|  | 255 |  | 
|  | 256 | /** | 
|  | 257 | * Generate the cookiecutter templates with given context | 
|  | 258 | * | 
| Jakub Josef | 4e10c37 | 2017-04-26 14:13:50 +0200 | [diff] [blame] | 259 | * @param template template | 
|  | 260 | * @param context template context | 
|  | 261 | * @param path Path where virtualenv is created (optional) | 
|  | 262 | * @param templatePath path to cookiecutter template repo (optional) | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 263 | */ | 
| Jakub Josef | 4e10c37 | 2017-04-26 14:13:50 +0200 | [diff] [blame] | 264 | def buildCookiecutterTemplate(template, context, outputDir = '.', path = null, templatePath = ".") { | 
| Tomáš Kukrál | dad7b46 | 2017-03-27 13:53:05 +0200 | [diff] [blame] | 265 | configFile = "default_config.yaml" | 
|  | 266 | configString = "default_context:\n" | 
| Tomáš Kukrál | 6de8504 | 2017-04-12 17:49:05 +0200 | [diff] [blame] | 267 | writeFile file: configFile, text: context | 
| Jakub Josef | 4e61cc0 | 2017-04-26 14:29:09 +0200 | [diff] [blame] | 268 | 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 Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 269 | output = sh (returnStdout: true, script: command) | 
|  | 270 | echo("[Cookiecutter build] Output: ${output}") | 
|  | 271 | } | 
|  | 272 |  | 
|  | 273 | /** | 
| Denis Egorenko | 6c2e3ae | 2018-10-17 16:45:56 +0400 | [diff] [blame] | 274 | * | 
|  | 275 | * @param context - context template | 
|  | 276 | * @param contextName - context template name | 
|  | 277 | * @param saltMasterName - hostname of Salt Master node | 
|  | 278 | * @param virtualenv - pyvenv with CC and dep's | 
|  | 279 | * @param templateEnvDir - root of CookieCutter | 
|  | 280 | * @return | 
|  | 281 | */ | 
|  | 282 | def generateModel(context, contextName, saltMasterName, virtualenv, modelEnv, templateEnvDir, multiModels = true) { | 
| Denis Egorenko | fa2c675 | 2018-10-18 15:51:45 +0400 | [diff] [blame] | 283 | def common = new com.mirantis.mk.Common() | 
| Denis Egorenko | 6c2e3ae | 2018-10-17 16:45:56 +0400 | [diff] [blame] | 284 | def generatedModel = multiModels ? "${modelEnv}/${contextName}" : modelEnv | 
|  | 285 | def templateContext = readYaml text: context | 
|  | 286 | def clusterDomain = templateContext.default_context.cluster_domain | 
|  | 287 | def clusterName = templateContext.default_context.cluster_name | 
|  | 288 | def outputDestination = "${generatedModel}/classes/cluster/${clusterName}" | 
|  | 289 | def templateBaseDir = templateEnvDir | 
|  | 290 | def templateDir = "${templateEnvDir}/dir" | 
|  | 291 | def templateOutputDir = templateBaseDir | 
|  | 292 | dir(templateEnvDir) { | 
|  | 293 | common.infoMsg("Generating model from context ${contextName}") | 
|  | 294 | def productList = ["infra", "cicd", "opencontrail", "kubernetes", "openstack", "oss", "stacklight", "ceph"] | 
|  | 295 | for (product in productList) { | 
|  | 296 | // get templateOutputDir and productDir | 
|  | 297 | templateOutputDir = "${templateEnvDir}/output/${product}" | 
|  | 298 | productDir = product | 
|  | 299 | templateDir = "${templateEnvDir}/cluster_product/${productDir}" | 
|  | 300 | // Bw for 2018.8.1 and older releases | 
|  | 301 | if (product.startsWith("stacklight") && (!fileExists(templateDir))) { | 
|  | 302 | common.warningMsg("Old release detected! productDir => 'stacklight2' ") | 
|  | 303 | productDir = "stacklight2" | 
|  | 304 | templateDir = "${templateEnvDir}/cluster_product/${productDir}" | 
|  | 305 | } | 
| Adam Tengler | a237313 | 2018-10-18 15:40:16 +0200 | [diff] [blame] | 306 | // generate infra unless its explicitly disabled | 
|  | 307 | if ((product == "infra" && templateContext.default_context.get("infra_enabled", "True").toBoolean()) | 
|  | 308 | || (templateContext.default_context.get(product + "_enabled", "False").toBoolean())) { | 
| Denis Egorenko | 6c2e3ae | 2018-10-17 16:45:56 +0400 | [diff] [blame] | 309 |  | 
|  | 310 | common.infoMsg("Generating product " + product + " from " + templateDir + " to " + templateOutputDir) | 
|  | 311 |  | 
|  | 312 | sh "rm -rf ${templateOutputDir} || true" | 
|  | 313 | sh "mkdir -p ${templateOutputDir}" | 
|  | 314 | sh "mkdir -p ${outputDestination}" | 
|  | 315 |  | 
|  | 316 | buildCookiecutterTemplate(templateDir, context, templateOutputDir, virtualenv, templateBaseDir) | 
|  | 317 | sh "mv -v ${templateOutputDir}/${clusterName}/* ${outputDestination}" | 
|  | 318 | } else { | 
|  | 319 | common.warningMsg("Product " + product + " is disabled") | 
|  | 320 | } | 
|  | 321 | } | 
|  | 322 |  | 
|  | 323 | def localRepositories = templateContext.default_context.local_repositories | 
|  | 324 | localRepositories = localRepositories ? localRepositories.toBoolean() : false | 
|  | 325 | def offlineDeployment = templateContext.default_context.offline_deployment | 
|  | 326 | offlineDeployment = offlineDeployment ? offlineDeployment.toBoolean() : false | 
|  | 327 | if (localRepositories && !offlineDeployment) { | 
|  | 328 | def mcpVersion = templateContext.default_context.mcp_version | 
|  | 329 | def aptlyModelUrl = templateContext.default_context.local_model_url | 
|  | 330 | def ssh = new com.mirantis.mk.Ssh() | 
|  | 331 | dir(path: modelEnv) { | 
|  | 332 | ssh.agentSh "git submodule add \"${aptlyModelUrl}\" \"classes/cluster/${clusterName}/cicd/aptly\"" | 
|  | 333 | if (!(mcpVersion in ["nightly", "testing", "stable"])) { | 
|  | 334 | ssh.agentSh "cd \"classes/cluster/${clusterName}/cicd/aptly\";git fetch --tags;git checkout ${mcpVersion}" | 
|  | 335 | } | 
|  | 336 | } | 
|  | 337 | } | 
|  | 338 |  | 
|  | 339 | def nodeFile = "${generatedModel}/nodes/${saltMasterName}.${clusterDomain}.yml" | 
|  | 340 | def nodeString = """classes: | 
|  | 341 | - cluster.${clusterName}.infra.config | 
|  | 342 | parameters: | 
|  | 343 | _param: | 
|  | 344 | linux_system_codename: xenial | 
|  | 345 | reclass_data_revision: master | 
|  | 346 | linux: | 
|  | 347 | system: | 
|  | 348 | name: ${saltMasterName} | 
|  | 349 | domain: ${clusterDomain} | 
|  | 350 | """ | 
|  | 351 | sh "mkdir -p ${generatedModel}/nodes/" | 
|  | 352 | writeFile(file: nodeFile, text: nodeString) | 
|  | 353 | } | 
|  | 354 | } | 
|  | 355 |  | 
|  | 356 | /** | 
| Sergey Kolekonov | ba20398 | 2016-12-21 18:32:17 +0400 | [diff] [blame] | 357 | * Install jinja rendering in isolated environment | 
|  | 358 | * | 
|  | 359 | * @param path        Path where virtualenv is created | 
|  | 360 | */ | 
|  | 361 | def setupJinjaVirtualenv(path) { | 
|  | 362 | requirements = [ | 
|  | 363 | 'jinja2-cli', | 
|  | 364 | 'pyyaml', | 
|  | 365 | ] | 
|  | 366 | setupVirtualenv(path, 'python2', requirements) | 
|  | 367 | } | 
|  | 368 |  | 
|  | 369 | /** | 
|  | 370 | * Generate the Jinja templates with given context | 
|  | 371 | * | 
|  | 372 | * @param path        Path where virtualenv is created | 
|  | 373 | */ | 
|  | 374 | def jinjaBuildTemplate (template, context, path = none) { | 
|  | 375 | contextFile = "jinja_context.yml" | 
|  | 376 | contextString = "" | 
|  | 377 | for (parameter in context) { | 
|  | 378 | contextString = "${contextString}${parameter.key}: ${parameter.value}\n" | 
|  | 379 | } | 
|  | 380 | writeFile file: contextFile, text: contextString | 
|  | 381 | cmd = "jinja2 ${template} ${contextFile} --format=yaml" | 
|  | 382 | data = sh (returnStdout: true, script: cmd) | 
|  | 383 | echo(data) | 
|  | 384 | return data | 
|  | 385 | } | 
| Oleg Grigorov | bec4558 | 2017-09-12 20:29:24 +0300 | [diff] [blame] | 386 |  | 
|  | 387 | /** | 
|  | 388 | * Install salt-pepper in isolated environment | 
|  | 389 | * | 
|  | 390 | * @param path        Path where virtualenv is created | 
| chnyda | a0dbb25 | 2017-10-05 10:46:09 +0200 | [diff] [blame] | 391 | * @param url         SALT_MASTER_URL | 
|  | 392 | * @param credentialsId        Credentials to salt api | 
| Oleg Grigorov | bec4558 | 2017-09-12 20:29:24 +0300 | [diff] [blame] | 393 | */ | 
| Jakub Josef | c9b6d66 | 2018-02-21 16:21:03 +0100 | [diff] [blame] | 394 | def setupPepperVirtualenv(path, url, credentialsId) { | 
| chnyda | a0dbb25 | 2017-10-05 10:46:09 +0200 | [diff] [blame] | 395 | def common = new com.mirantis.mk.Common() | 
|  | 396 |  | 
|  | 397 | // virtualenv setup | 
| Mykyta Karpin | 81756c9 | 2018-03-02 13:03:26 +0200 | [diff] [blame] | 398 | // pin pepper till https://mirantis.jira.com/browse/PROD-18188 is fixed | 
|  | 399 | requirements = ['salt-pepper>=0.5.2,<0.5.4'] | 
| Jakub Josef | c9b6d66 | 2018-02-21 16:21:03 +0100 | [diff] [blame] | 400 | setupVirtualenv(path, 'python2', requirements, null, true, true) | 
| chnyda | bcfff18 | 2017-11-29 10:24:36 +0100 | [diff] [blame] | 401 |  | 
| chnyda | a0dbb25 | 2017-10-05 10:46:09 +0200 | [diff] [blame] | 402 | // pepperrc creation | 
|  | 403 | rcFile = "${path}/pepperrc" | 
|  | 404 | creds = common.getPasswordCredentials(credentialsId) | 
|  | 405 | rc = """\ | 
|  | 406 | [main] | 
|  | 407 | SALTAPI_EAUTH=pam | 
|  | 408 | SALTAPI_URL=${url} | 
|  | 409 | SALTAPI_USER=${creds.username} | 
|  | 410 | SALTAPI_PASS=${creds.password.toString()} | 
|  | 411 | """ | 
|  | 412 | writeFile file: rcFile, text: rc | 
|  | 413 | return rcFile | 
| Jakub Josef | d067f61 | 2017-09-26 13:42:56 +0200 | [diff] [blame] | 414 | } | 
| Oleh Hryhorov | 44569fb | 2017-10-26 17:04:55 +0300 | [diff] [blame] | 415 |  | 
|  | 416 | /** | 
|  | 417 | * Install devops in isolated environment | 
|  | 418 | * | 
|  | 419 | * @param path        Path where virtualenv is created | 
|  | 420 | * @param clean       Define to true is the venv have to cleaned up before install a new one | 
|  | 421 | */ | 
|  | 422 | def setupDevOpsVenv(venv, clean=false) { | 
|  | 423 | requirements = ['git+https://github.com/openstack/fuel-devops.git'] | 
|  | 424 | setupVirtualenv(venv, 'python2', requirements, null, false, clean) | 
|  | 425 | } |