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