blob: 1b98f376d2a3f571fb6e8b7f27e960204f88c203 [file] [log] [blame]
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +03001package com.mirantis.mcp
2
sgarbuz60651572019-05-30 16:34:17 +03003import static org.yaml.snakeyaml.DumperOptions.FlowStyle.BLOCK
Pavlo Shchelokovskyybd0ca532018-12-13 18:50:00 +00004import java.util.zip.GZIPInputStream
5import java.util.zip.GZIPOutputStream
6
Sergey Reshetnyak70b1fe62017-01-31 22:27:06 +03007@Grab(group='org.yaml', module='snakeyaml', version='1.17')
8import org.yaml.snakeyaml.Yaml
sgarbuz60651572019-05-30 16:34:17 +03009import org.yaml.snakeyaml.DumperOptions
Dmitry Teselkin5808aa52024-05-13 12:49:56 +020010import org.yaml.snakeyaml.LoaderOptions
Sergey Reshetnyak70b1fe62017-01-31 22:27:06 +030011
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030012/**
13 * https://issues.jenkins-ci.org/browse/JENKINS-26481
14 * fix groovy List.collect()
15 **/
16@NonCPS
Dmitry Burmistrovc28e9222018-07-16 18:46:18 +040017def constructString(ArrayList options, String keyOption, String separator = ' ') {
18 return options.collect { keyOption + it }.join(separator).replaceAll('\n', '')
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030019}
20
21/**
22 * Generate current timestamp
23 *
24 * @param format Defaults to yyyyMMddHHmmss
25 */
26def getDatetime(format = "yyyyMMddHHmmss") {
Dmitry Burmistrovc28e9222018-07-16 18:46:18 +040027 def now = new Date()
28 return now.format(format, TimeZone.getTimeZone('UTC'))
Denis Egorenko8c606552016-12-07 14:22:50 +040029}
30
31/**
32 * Run tox with or without specified environment
33 * @param env String, name of environment
34 */
35def runTox(String env = null) {
36 if (env) {
37 sh "tox -v -e ${env}"
38 } else {
Dmitry Burmistrovc28e9222018-07-16 18:46:18 +040039 sh 'tox -v'
Denis Egorenko8c606552016-12-07 14:22:50 +040040 }
41}
Sergey Kulanove897d8f2017-01-23 16:44:03 +020042
43/**
Sergey Reshetnyak70b1fe62017-01-31 22:27:06 +030044 * Convert YAML document to Map object
45 * @param data YAML string
46 */
47@NonCPS
48def loadYAML(String data) {
Dmitry Teselkin5808aa52024-05-13 12:49:56 +020049 LoaderOptions options = new LoaderOptions()
50 options.setMaxAliasesForCollections(100)
51 def yaml = new Yaml(options)
Sergey Reshetnyak70b1fe62017-01-31 22:27:06 +030052 return yaml.load(data)
53}
54
55/**
56 * Convert Map object to YAML string
57 * @param map Map object
58 */
59@NonCPS
60def dumpYAML(Map map) {
sgarbuz60651572019-05-30 16:34:17 +030061 DumperOptions options = new DumperOptions()
62 options.setPrettyFlow(true)
63 options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK)
64 def yaml = new Yaml(options)
Sergey Reshetnyak70b1fe62017-01-31 22:27:06 +030065 return yaml.dump(map)
66}
67
68/**
Sergey Kulanov21c936c2017-02-02 13:43:14 +020069 * Render jinja template
70 * @param templateVars String, A dict, a dict subclass, json or some keyword arguments
71 * @param templateFile String, jinja template file path
72 * @param resultFile String, result/generate file path
73 *
74 * Usage example:
75 *
76 * def common = new com.mirantis.mcp.Common()
77 * common.renderJinjaTemplate(
78 * "${NODE_JSON}",
79 * "${WORKSPACE}/inventory/inventory.cfg",
80 * "${WORKSPACE}/inventory/inventory.cfg")
81 * where NODE_JSON= data in json format
82 */
83def renderJinjaTemplate(String templateVars, String templateFile, String resultFile) {
84
85 sh """
86 python -c "
87import sys
88import jinja2
89from jinja2 import Template
90
91# Useful for very coarse version differentiation.
92PY2 = sys.version_info[0] == 2
93PY3 = sys.version_info[0] == 3
94PY34 = sys.version_info[0:2] >= (3, 4)
95
96if PY3:
97 string_types = str,
98else:
99 string_types = basestring
100
101
102def to_bool(a):
103 ''' return a bool for the arg '''
104 if a is None or type(a) == bool:
105 return a
106 if isinstance(a, string_types):
107 a = a.lower()
108 if a in ['yes', 'on', '1', 'true', 1]:
109 return True
110 else:
111 return False
112
113
114def generate(templateVars, templateFile, resultFile):
115 templateLoader = jinja2.FileSystemLoader(searchpath='/')
116 templateEnv = jinja2.Environment(loader=templateLoader)
117 templateEnv.filters['bool'] = to_bool
118 template = templateEnv.get_template(templateFile)
119 outputText = template.render(templateVars)
120 Template(outputText).stream().dump(resultFile)
121
122generate(${templateVars}, '${templateFile}', '${resultFile}')
123"
124 cat ${resultFile}
125 """
126}
127
128/**
Sergey Kulanove897d8f2017-01-23 16:44:03 +0200129 * Run function on k8s cluster
130 *
131 * @param config LinkedHashMap
132 * config includes next parameters:
133 * - label, pod label
134 * - function, code that should be run on k8s cluster
135 * - jnlpImg, jnlp slave image
136 * - slaveImg, slave image
137 *
138 * Usage example:
139 *
140 * def runFunc = new com.mirantis.mcp.Common()
141 * runFunc.runOnKubernetes ([
142 * function : this.&buildCalicoContainers,
143 * jnlpImg: 'docker-prod-virtual.docker.mirantis.net/mirantis/jenkins-slave-images/jnlp-slave:latest',
144 * slaveImg : 'sandbox-docker-dev-local.docker.mirantis.net/skulanov/jenkins-slave-images/calico-slave:1'
145 * ])
146 * // promotion example. In case of promotion we need only jnlp container
147 * def runFunc = new com.mirantis.mcp.Common()
148 * runFunc.runOnKubernetes ([
149 * jnlpImg: 'docker-prod-virtual.docker.mirantis.net/mirantis/jenkins-slave-images/jnlp-slave:latest',
150 * function : this.&promote_artifacts
151 * ])
152 */
153def runOnKubernetes(LinkedHashMap config) {
154
155
156 def jenkinsSlaveImg = config.get('slaveImg', 'none')
157 def jnlpSlaveImg = config.get('jnlpImg', 'none')
158 def lbl = config.get('label', "buildpod.${env.JOB_NAME}.${env.BUILD_NUMBER}".replace('-', '_').replace('/', '_'))
159 def toRun = config.get('function', 'none')
160
Sergey Kulanovb1aa0ff2017-01-23 17:48:44 +0200161 if (jnlpSlaveImg == 'none') {
Sergey Kulanove897d8f2017-01-23 16:44:03 +0200162 error('jnlp Slave image MUST be defined')
163 }
164
165 if (toRun == 'none'){
166 error('Code that should be run on k8s MUST be passed along with function parameter')
167 }
168
169 if (jenkinsSlaveImg == 'none'){
170 // we are running jnlp container only, since no jenkinsSlaveImg is specified, so
171 // we are in promotion mode
172 podTemplate(label: lbl,
173 containers: [
174 containerTemplate(
175 name: 'jnlp',
176 image: jnlpSlaveImg,
177 args: '${computer.jnlpmac} ${computer.name}'
178 )
179 ],
180 ) {
181 node(lbl){
182 container('jnlp') {
183 toRun()
184 }
185 }
186 }
187
188 } else {
189 podTemplate(label: lbl,
190 containers: [
191 containerTemplate(
192 name: 'jnlp',
193 image: jnlpSlaveImg,
194 args: '${computer.jnlpmac} ${computer.name}'
195 ),
196 containerTemplate(
197 name: 'k8s-slave',
198 image: jenkinsSlaveImg,
199 alwaysPullImage: false,
200 ttyEnabled: true,
201 privileged: true
202 )
203 ],
204 ) {
205 node(lbl){
206 container('k8s-slave') {
Sergey Kulanovb36e36e2017-01-23 18:26:40 +0200207 return toRun()
Sergey Kulanove897d8f2017-01-23 16:44:03 +0200208 }
209 }
210 }
211 } //else
212
213}
Pavlo Shchelokovskyybd0ca532018-12-13 18:50:00 +0000214
Pavlo Shchelokovskyyb1e6d0b2018-12-17 17:17:20 +0000215/**
216 * Compress a string with Gzip and encode result with Base64 encoding,
217 * useful for wire transfer of large text data over text-based protocols like HTTP
218 * @param s string to encode
219 * @return base64-encoded gzipped string
220*/
Pavlo Shchelokovskyybd0ca532018-12-13 18:50:00 +0000221def zipBase64(String s){
222 def targetStream = new ByteArrayOutputStream()
223 def zipStream = new GZIPOutputStream(targetStream)
224 zipStream.write(s.getBytes('UTF-8'))
225 zipStream.close()
226 def zippedBytes = targetStream.toByteArray()
227 targetStream.close()
Pavlo Shchelokovskyyb1e6d0b2018-12-17 17:17:20 +0000228 return zippedBytes.encodeBase64().toString()
Pavlo Shchelokovskyybd0ca532018-12-13 18:50:00 +0000229}
230
Pavlo Shchelokovskyyb1e6d0b2018-12-17 17:17:20 +0000231/**
232 * De-compress a base64-encoded gzipped string, reverts result of zipBase64
233 * @param compressed base64-endcoded gzipped string
234 * @return decoded decompressed string
235*/
Pavlo Shchelokovskyybd0ca532018-12-13 18:50:00 +0000236def unzipBase64(String compressed){
237 def inflaterStream = new GZIPInputStream(new ByteArrayInputStream(compressed.decodeBase64()))
238 def uncompressedStr = inflaterStream.getText('UTF-8')
239 return uncompressedStr
240}