blob: 029b334fa4a4e5dd952d7d2846cad9925acfc879 [file] [log] [blame]
Ryabin Sergeya78ee8d2017-02-07 12:52:18 +04001package com.mirantis.mcp
2
3/*
4 Example usage:
5
6 def ccpCiCd = new com.mirantis.mcp.CCPCICD().newInstance(this, env)
7
8 ccpCiCd.applyPipelineParameters()
9
10 ccpCiCd.fetchEnvConfiguration()
11 ccpCiCd.parametrizeConfig()
12
13 ccpCiCd.build()
14 ccpCiCd.deploy()
15 ccpCiCd.cleanup()
16*/
17
18/*
19 Since groovy-cps demands that local variables may be serialized,
20 any locally defined classes must also be serializable
21
22 More details: https://issues.jenkins-ci.org/browse/JENKINS-32213
23*/
24
25public class ccpCICD implements Serializable {
26
27 /*
28 Endless loop in DefaultInvoker.getProperty when accessing field
29 via getter/setter without @
30
31 This issue fixed in groovy pipeline plugin 2.25
32
33 More details https://issues.jenkins-ci.org/browse/JENKINS-31484
34 */
35
36 /*
37 nodeContext - is a context of which node the job is executed
38 through this context, CCPCICD class able to use
39 dir() writeFile() sh() and other workflow basic steps
40
41 See more https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/
42
43 nodeContext must be passed in class constructor
44 */
45 def nodeContext = null
46
47 /*
48 Job parameters are accessed through environment
49 */
50 def env = null
51
52 /*
53 Directory where stored environment configuration
54 */
55 def envConfigurationPath = null
56 def File envConfiguration = null
57
58 /*
59 Path to entry point yaml in environment directory
60 */
61 def ccpConfigPath = null
62
63 def File virtualEnv = null // Currently not supported
64
65 def URI configurationRepo = null
66
67 /*
68 parsed `ccp config dump` output
69 */
70
71 def Map ccpConfig = null
72
73 /*
74 Part of ccp parameters which will be overwritten by job
75 parametrizeConfig() method
76
77 */
78 def Map ciConfig = [
79 'registry' : [
80 'address' : null,
81 'username' : null,
82 'password' : null,
83 ],
84 'kubernetes' : [
85 'namespace' : 'ccp',
86 'server' : null,
87 'insecure' : true,
88 'username' : null,
89 'password' : null
90 ],
91 'repositories': [
92 'path' : null
93 ]
94
95 ]
96
97 // Using loadYAML and dumpYAML from common library
98 def common = new com.mirantis.mcp.Common()
99
100 // default CCP repo (using in upgrade)
101 def URI ccpSource = new URI('git+https://gerrit.mcp.mirantis.net/ccp/fuel-ccp')
102
103 def public void setConfURL(URI confURI) {
104 if (confURI == null) {
105 throw new IllegalArgumentException('Invalid argument')
106 }
107 this.@configurationRepo = confURI
108 }
109
110 def public URI getConfURL() {
111 return this.@configurationRepo
112 }
113
114 /*
115 According JENKINS-31314 constructor can be used only for assignments properties
116 More details: https://issues.jenkins-ci.org/browse/JENKINS-31314
117 */
118 def public ccpCICD(nodeContext, env) {
119 this.@nodeContext = nodeContext
120 this.@env = env
121 }
122
123 /*
124 Transform jenkins job arguments to ccp configuration
125 Parameters can be overriden with customParameters Map
126
127 Example usage:
128 applyPipelineParameters([
129
130 'images': [
131 'image_specs': [
132 'etcd': [
133 'tag': '41a45e5a9db5'
134 ]
135 ]
136 ]
137
138 ])
139
140 */
141
142 def public void applyPipelineParameters(Map customParameters = null) {
143
144 if (this.@env.CONF_GERRIT_URL != null) {
145 this.setConfURL(new URI(this.@env.CONF_GERRIT_URL))
146 }
147
148
149 if (this.@env.CONF_ENTRYPOINT != null) {
150 this.setCcpConfigPath(new File(this.@env.CONF_ENTRYPOINT))
151 }
152
153 if (this.@env.KUBERNETES_URL != null) {
154 this.setKubernetesURL(new URI(this.@env.KUBERNETES_URL), this.@env.CREDENTIALS_ID)
155 } else {
156 this.@ciConfig.remove('kubernetes')
157 }
158
159 if (this.@env.DOCKER_REGISTRY != null) {
160 this.setRegistry(new URI(this.@env.DOCKER_REGISTRY), this.env.DOCKER_REGISTRY_CREDENTIAL_ID ? this.env.DOCKER_REGISTRY_CREDENTIAL_ID : 'artifactory')
161 } else {
162 this.@ciConfig.remove('registry')
163 }
164
165
166 this.@ciConfig['repositories']['path'] = env.WORKSPACE + '/repos'
167
168 if (customParameters != null) {
169 this.@ciConfig = this.@ciConfig + customParameters
170 }
171 }
172
173 def public File getCcpConfigPath() {
174 return this.@ccpConfigPath
175 }
176
177 def public void setCcpConfigPath(File configPath) {
178 this.@ccpConfigPath = configPath
179 }
180
181 /*
182 Set k8s endpoint and credentials
183
184 Example usage:
185 this.setKubernetesURL(new URI('https://host:443'), 'kubernetes-api')
186 */
187
188 def public void setKubernetesURL(URI kubernetesURL, String credentialId) {
189 if (credentialId != null) {
190 this.@nodeContext.withCredentials([
191 [
192 $class : 'UsernamePasswordMultiBinding',
193 credentialsId : credentialId,
194 passwordVariable : 'K8S_PASSWORD',
195 usernameVariable : 'K8S_USERNAME'
196 ]
197 ]) {
198 this.@ciConfig['kubernetes']['username'] = env.K8S_USERNAME
199 this.@ciConfig['kubernetes']['password'] = env.K8S_PASSWORD
200 }
201 }
202
Ryabin Sergeyead12d92017-02-20 16:52:01 +0400203 /*
204 //TODO(sryabin) properly parse return from getUserInfo()
Ryabin Sergeya78ee8d2017-02-07 12:52:18 +0400205 if (kubernetesURL.getUserInfo()) {
Ryabin Sergeya78ee8d2017-02-07 12:52:18 +0400206 this.@ciConfig['kubernetes']['username'] = kubernetesURL.getUserInfo()
207 }
Ryabin Sergeyead12d92017-02-20 16:52:01 +0400208 */
Ryabin Sergeya78ee8d2017-02-07 12:52:18 +0400209
210 this.@ciConfig['kubernetes']['server'] = kubernetesURL.toString()
211 }
212
213 def public void setRegistry(String registryEndpoint, String credentialId) {
214 if (credentialId) {
215 this.@nodeContext.withCredentials([
216 [
217 $class : 'UsernamePasswordMultiBinding',
218 credentialsId : credentialId,
219 passwordVariable : 'REGISTRY_PASSWORD',
220 usernameVariable : 'REGISTRY_USERNAME'
221 ]
222 ]) {
223 this.@ciConfig['registry']['username'] = env.REGISTRY_USERNAME
224 this.@ciConfig['registry']['password'] = env.REGISTRY_PASSWORD
225 }
226 } else {
227 this.@ciConfig['registry'].remove('username')
228 this.@ciConfig['registry'].remove('password')
229 }
230
231 this.@ciConfig['registry']['address'] = registryEndpoint;
232 }
233
234 def public setEnvConfigurationDir() {
235 // TODO(sryabin) cleanup this dir in desctructor
236 this.@envConfigurationPath = File.createTempDir(this.@env.WORKSPACE + '/envConfiguration', 'ccpci')
237 }
238
239 def public File getEnvConfigurationDir() {
240 return this.@envConfigurationPath
241 }
242
243
244
245 def public File fetchEnvConfiguration() {
246
247 def gitTools = new com.mirantis.mcp.Git()
248
249 this.setEnvConfigurationDir()
250
251 gitTools.gitSSHCheckout ([
252 credentialsId : this.@env.CONF_GERRIT_CREDENTIAL_ID,
253 branch : "master",
254 host : this.getConfURL().getHost(),
255 port : this.getConfURL().getPort(),
256 project: this.getConfURL().getPath(),
257 targetDir: this.getEnvConfigurationDir().toString()
258 ])
259
260 return this.getEnvConfigurationDir()
261 }
262
263 def public String configDump() {
264 return this.ccpExecute('config dump')
265 }
266
267 /*
268 merge ccp configuration from repo and custom parameters from job arguments
269 */
270 def public Map parametrizeConfig() {
271 this.fetchEnvConfiguration()
272 this.@ccpConfig = this.@common.loadYAML(this.configDump())
273 this.setCcpConfigPath(new File('parametrized.yaml'));
274 this.@nodeContext.writeFile file: this.getEnvConfigurationDir().toString() + '/' + this.getCcpConfigPath().toString(), \
275 text: this.@common.dumpYAML(this.@ccpConfig + this.@ciConfig)
276 }
277
278 def public Map getConfig() {
279 return this.@ccpConfig
280 }
281
282
283 /*
284 Example usage:
285 ci.ccpExecute('config dump')
286 */
287 def public String ccpExecute(args) {
288 // TODO(sryabin) pass custom args from class property, like debug
289 def String output = null;
290 this.@nodeContext.dir(this.getEnvConfigurationDir().toString()) {
291 output = this.@nodeContext.sh(
292 script: "PYTHONWARNINGS='ignore:Unverified HTTPS request' ccp --config-file " + this.getCcpConfigPath().toString() + " ${args}",
293 returnStdout: true
294 )
295 }
296 return output
297 }
298
299 /*
300 Update fuel-ccp
301
302 @param virtualEnv File, path to python virtual environment, currently not supported
303 @param source URI, if not present, use upstream
304 @param upgradePip Boolean, upgrade pip if required
305
306 Usage example:
307 upgradeCcp(new File('/home/ubuntu/.venv'), new URI('http://github.com/openstack/fuel-ccp'))
308 */
309 def public void upgradeCcp(File virtualEnv = null, URI source, Boolean upgradePip = false) {
310 if (virtualEnv) {
311 throw new UnsupportedOperationException('Python virtual environments not implemented')
312 }
313
314 try {
315 def output = this.@nodeContext.sh(
316 script: 'pip install --user --upgrade ' + ((source != null) ? source : this.@ccpSource).toString(),
317 returnStdout: true
318 )
319 } catch (e) {
320 // TODO(sryabin) catch in stderr "You should consider upgrading via the 'pip install --upgrade pip' command."
321 if (upgradePip == true) {
322 this.@nodeContext.sh(
323 script: 'pip install --upgrade pip',
324 returnStdout: true
325 )
326 }
327 // FIXME(sryabin) infinity loop
328 //this.upgradeCcp(virtualEnv, source, false)
329 }
330 }
331 def public void upgradeCcp() {
332 this.upgradeCcp(null, null, true)
333 }
334
335 def build() {
336 //TODO(sryabin) implement build -c functionality
337 return this.ccpExecute('build')
338 }
339
340 def deploy() {
341 //TODO(sryabin) implement build -c functionality
342 return this.ccpExecute('deploy')
343 }
344
345 def cleanup() {
346 try {
347 this.ccpExecute('cleanup')
348 } catch (err) {
349 this.ccpExecute('cleanup --skip-os-cleanup')
350 }
351 }
352
353 def fetch() {
354 // TODO(sryabin) implement fetch -f functioanlity
355 return this.ccpExecute('fetch')
356 }
357}
358
359/*
360 Workaround for scope limitation, and
361 org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified new
362
363 def ccpCiCd = new com.mirantis.mcp.CCPCICD()
364 def CCPCICD ci = new ccpCiCd.ccpCICD(this, env) return no such CCPCICD()
365
366 Example usage:
367 def ccpCiCd = new com.mirantis.mcp.CCPCICD().newInstance(this, env)
368
369*/
370
371def newInstance(nodeContext, env) {
372 return new ccpCICD(nodeContext,env)
373}