blob: 61015f5e0c5cf3ded76210acf20d3dfa22e75934 [file] [log] [blame]
Tomáš Kukrálb9957b32017-02-28 14:49:00 +01001/**
Tomáš Kukrál4691f682017-07-27 16:36:12 +02002
3
4
5
6
7
8
9
10
11* This pipeline is deprecated, please use cloud-deploy-pipeline
12
13
14
15
16
17
18
19
20
21
22
23
Tomáš Kukrálb9957b32017-02-28 14:49:00 +010024 *
25 * Launch heat stack with basic k8s
26 * Flow parameters:
Jakub Josef3c7915f2017-05-24 11:23:57 +020027 * STACK_NAME Heat stack name
28 * STACK_TYPE Orchestration engine: heat, ''
29 * STACK_INSTALL What should be installed (k8s, openstack, ...)
30 * STACK_TEST What should be tested (k8s, openstack, ...)
31 *
32 * STACK_TEMPLATE_URL URL to git repo with stack templates
33 * STACK_TEMPLATE_BRANCH Stack templates repo branch
34 * STACK_TEMPLATE_CREDENTIALS Credentials to the stack templates repo
35 * STACK_TEMPLATE Heat stack HOT template
Vasyl Saienkod3bbc502017-07-17 10:46:36 +030036 * STACK_RECLASS_ADDRESS Stack reclass address
37 * STACK_RECLASS_BRANCH Stack reclass repo branch
Jakub Josef3c7915f2017-05-24 11:23:57 +020038 * STACK_DELETE Delete stack when finished (bool)
39 * STACK_REUSE Reuse stack (don't create one)
40 * STACK_CLEANUP_JOB Name of job for deleting Heat stack
Tomáš Kukrálb9957b32017-02-28 14:49:00 +010041 *
42 * Expected parameters:
Tomáš Kukrálb9957b32017-02-28 14:49:00 +010043 * required for STACK_TYPE=heat
Matthew Mosesohn59fc6482017-06-01 18:53:10 +030044 * HEAT_STACK_ENVIRONMENT Heat stack environmental parameters
45 * HEAT_STACK_ZONE Heat stack availability zone
46 * HEAT_STACK_PUBLIC_NET Heat stack floating IP pool
47 * OPENSTACK_API_URL OpenStack API address
48 * OPENSTACK_API_CREDENTIALS Credentials to the OpenStack API
49 * OPENSTACK_API_PROJECT OpenStack project to connect to
50 * OPENSTACK_API_PROJECT_DOMAIN Domain for OpenStack project
51 * OPENSTACK_API_PROJECT_ID ID for OpenStack project
52 * OPENSTACK_API_USER_DOMAIN Domain for OpenStack user
53 * OPENSTACK_API_CLIENT Versions of OpenStack python clients
54 * OPENSTACK_API_VERSION Version of the OpenStack API (2/3)
Tomáš Kukrálb9957b32017-02-28 14:49:00 +010055 *
56 * SALT_MASTER_CREDENTIALS Credentials to the Salt API
57 *
58 * required for STACK_TYPE=NONE or empty string
59 * SALT_MASTER_URL URL of Salt-API
Tomáš Kukrálb9957b32017-02-28 14:49:00 +010060 *
Tomáš Kukrál5c2ec132017-07-26 09:57:27 +020061 * Test settings:
62 * TEST_K8S_API_SERVER Kubernetes API address
63 * TEST_K8S_CONFORMANCE_IMAGE Path to docker image with conformance e2e tests
64 *
65 * TEST_TEMPEST_IMAGE Tempest image link
66 * TEST_DOCKER_INSTALL Install docker on the target if tue
67 * TEST_TEMPEST_PATTERN If not false, run tests matched to pattern only
68 * TEST_TEMPEST_TARGET Salt target for tempest node
Victor Ryzhenkin5f3b7e62017-03-09 16:02:58 +040069 *
Matthew Mosesohna85f24e2017-04-28 13:45:19 +030070 * optional parameters for overwriting soft params
Matthew Mosesohn13933442017-07-04 21:20:08 +030071 * SALT_OVERRIDES YAML with overrides for Salt deployment
Matthew Mosesohna85f24e2017-04-28 13:45:19 +030072 *
Tomáš Kukrálb9957b32017-02-28 14:49:00 +010073 */
74
Tomáš Kukrál1f8b5012017-04-28 21:07:10 +020075common = new com.mirantis.mk.Common()
Tomáš Kukrálb9957b32017-02-28 14:49:00 +010076git = new com.mirantis.mk.Git()
77openstack = new com.mirantis.mk.Openstack()
Tomáš Kukrál1f8b5012017-04-28 21:07:10 +020078orchestrate = new com.mirantis.mk.Orchestrate()
Tomáš Kukrálb9957b32017-02-28 14:49:00 +010079salt = new com.mirantis.mk.Salt()
Ondrej Smola8f35e482017-03-30 14:04:36 +020080test = new com.mirantis.mk.Test()
Tomáš Kukrál1f8b5012017-04-28 21:07:10 +020081
Tomáš Kukrálab2f3702017-05-11 09:17:43 +020082_MAX_PERMITTED_STACKS = 2
Tomáš Kukrále80680a2017-03-02 16:34:35 +010083
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +040084node {
85 // try to get STACK_INSTALL or fallback to INSTALL if exists
86 try {
87 def temporary = STACK_INSTALL
88 } catch (MissingPropertyException e) {
89 try {
90 STACK_INSTALL = INSTALL
91 env['STACK_INSTALL'] = INSTALL
92 } catch (MissingPropertyException e2) {
93 common.errorMsg("Property STACK_INSTALL or INSTALL not found!")
94 }
95 }
96 try {
97 //
98 // Prepare machines
99 //
100 stage ('Create infrastructure') {
Tomáš Kukrála18de112017-03-02 13:57:47 +0100101
Tomáš Kukrálc9a630a2017-03-07 17:28:53 +0100102 if (STACK_TYPE == 'heat') {
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400103 // value defaults
104 def openstackCloud
105 def openstackVersion = OPENSTACK_API_CLIENT ? OPENSTACK_API_CLIENT : 'liberty'
106 def openstackEnv = "${env.WORKSPACE}/venv"
Tomáš Kukrál4507c6a2017-03-23 19:00:39 +0100107
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400108 if (STACK_REUSE.toBoolean() == true && STACK_NAME == '') {
109 error("If you want to reuse existing stack you need to provide it's name")
110 }
111
112 if (STACK_REUSE.toBoolean() == false) {
113 // Don't allow to set custom heat stack name
114 wrap([$class: 'BuildUser']) {
115 if (env.BUILD_USER_ID) {
116 STACK_NAME = "${env.BUILD_USER_ID}-${JOB_NAME}-${BUILD_NUMBER}"
117 } else {
118 STACK_NAME = "jenkins-${JOB_NAME}-${BUILD_NUMBER}"
119 }
120 currentBuild.description = STACK_NAME
Tomáš Kukrálc9a630a2017-03-07 17:28:53 +0100121 }
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400122 }
Tomáš Kukrálc9a630a2017-03-07 17:28:53 +0100123
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400124 // set description
125 currentBuild.description = "${STACK_NAME}"
126
127 // get templates
128 git.checkoutGitRepository('template', STACK_TEMPLATE_URL, STACK_TEMPLATE_BRANCH, STACK_TEMPLATE_CREDENTIALS)
129
130 // create openstack env
131 openstack.setupOpenstackVirtualenv(openstackEnv, openstackVersion)
132 openstackCloud = openstack.createOpenstackEnv(
133 OPENSTACK_API_URL, OPENSTACK_API_CREDENTIALS,
134 OPENSTACK_API_PROJECT, OPENSTACK_API_PROJECT_DOMAIN,
135 OPENSTACK_API_PROJECT_ID, OPENSTACK_API_USER_DOMAIN,
136 OPENSTACK_API_VERSION)
137 openstack.getKeystoneToken(openstackCloud, openstackEnv)
138 //
139 // Verify possibility of create stack for given user and stack type
140 //
141 wrap([$class: 'BuildUser']) {
142 if (env.BUILD_USER_ID && !env.BUILD_USER_ID.equals("jenkins") && !env.BUILD_USER_ID.equals("mceloud") && !STACK_REUSE.toBoolean()) {
143 def existingStacks = openstack.getStacksForNameContains(openstackCloud, "${env.BUILD_USER_ID}-${JOB_NAME}", openstackEnv)
144 if(existingStacks.size() >= _MAX_PERMITTED_STACKS){
145 STACK_DELETE = "false"
146 throw new Exception("You cannot create new stack, you already have ${_MAX_PERMITTED_STACKS} stacks of this type (${JOB_NAME}). \nStack names: ${existingStacks}")
Tomáš Kukrálbcc53ea2017-03-08 08:15:57 +0100147 }
Tomáš Kukrálb908dac2017-03-07 18:58:35 +0100148 }
Tomáš Kukrála18de112017-03-02 13:57:47 +0100149 }
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400150 // launch stack
151 if (STACK_REUSE.toBoolean() == false) {
152 stage('Launch new Heat stack') {
153 // create stack
154 envParams = [
155 'instance_zone': HEAT_STACK_ZONE,
156 'public_net': HEAT_STACK_PUBLIC_NET
157 ]
158 try {
159 envParams.put('cfg_reclass_branch', STACK_RECLASS_BRANCH)
160 envParams.put('cfg_reclass_address', STACK_RECLASS_ADDRESS)
161 } catch (MissingPropertyException e) {
162 common.infoMsg("Property STACK_RECLASS_BRANCH or STACK_RECLASS_ADDRESS not found! Using default values from template.")
163 }
164 openstack.createHeatStack(openstackCloud, STACK_NAME, STACK_TEMPLATE, envParams, HEAT_STACK_ENVIRONMENT, openstackEnv)
165 }
166 }
167
168 // get SALT_MASTER_URL
169 saltMasterHost = openstack.getHeatStackOutputParam(openstackCloud, STACK_NAME, 'salt_master_ip', openstackEnv)
170 currentBuild.description = "${STACK_NAME}: ${saltMasterHost}"
171
172 SALT_MASTER_URL = "http://${saltMasterHost}:6969"
173 }
174 }
175
176 //
177 // Connect to Salt master
178 //
179
180 def saltMaster
181 stage('Connect to Salt API') {
182 saltMaster = salt.connection(SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
183 }
184
185 // Set up override params
186 if (env.getEnvironment().containsKey('SALT_OVERRIDES')) {
187 stage('Set Salt overrides') {
188 salt.setSaltOverrides(saltMaster, SALT_OVERRIDES)
189 }
190 }
191
192 //
193 // Install
194 //
195
196 if (common.checkContains('STACK_INSTALL', 'core')) {
197 stage('Install core infrastructure') {
198 orchestrate.installFoundationInfra(saltMaster)
199
200 if (common.checkContains('STACK_INSTALL', 'kvm')) {
201 orchestrate.installInfraKvm(saltMaster)
202 orchestrate.installFoundationInfra(saltMaster)
203 }
204
205 orchestrate.validateFoundationInfra(saltMaster)
206 }
207 }
208
209 // install k8s
210 if (common.checkContains('STACK_INSTALL', 'k8s')) {
211
212 // install infra libs for k8s
213 stage('Install Kubernetes infra') {
214 orchestrate.installKubernetesInfra(saltMaster)
215 }
216
217 // If k8s install with contrail network manager then contrail need to be install first
218 if (common.checkContains('STACK_INSTALL', 'contrail')) {
219 stage('Install Contrail for Kubernetes') {
220 orchestrate.installContrailNetwork(saltMaster)
221 orchestrate.installContrailCompute(saltMaster)
222 orchestrate.installKubernetesContrailCompute(saltMaster)
223 }
224 }
225
226 stage('Install Kubernetes control') {
227 orchestrate.installKubernetesControl(saltMaster)
228 }
229 }
230
231 // install openstack
232 if (common.checkContains('STACK_INSTALL', 'openstack')) {
233 // install Infra and control, tests, ...
234
235 stage('Install OpenStack infra') {
236 orchestrate.installOpenstackInfra(saltMaster)
237 }
238
239 stage('Install OpenStack control') {
240 orchestrate.installOpenstackControl(saltMaster)
241 }
242
243 stage('Install OpenStack network') {
244
245 if (common.checkContains('STACK_INSTALL', 'contrail')) {
246 orchestrate.installContrailNetwork(saltMaster)
247 } else if (common.checkContains('STACK_INSTALL', 'ovs')) {
248 orchestrate.installOpenstackNetwork(saltMaster)
249 }
250
Jakub Josef2c21c6c2018-02-08 18:51:42 +0100251 salt.cmdRun(saltMaster, 'I@keystone:server', '. /root/keystonerc; neutron net-list')
252 salt.cmdRun(saltMaster, 'I@keystone:server', '. /root/keystonerc; nova net-list')
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400253 }
254
255 if (salt.testTarget(saltMaster, 'I@ironic:conductor')){
256 stage('Install OpenStack Ironic conductor') {
257 orchestrate.installIronicConductor(saltMaster)
258 }
259 }
260
261
262 stage('Install OpenStack compute') {
263 orchestrate.installOpenstackCompute(saltMaster)
264
265 if (common.checkContains('STACK_INSTALL', 'contrail')) {
266 orchestrate.installContrailCompute(saltMaster)
267 }
268 }
269
270 }
271
272
273 if (common.checkContains('STACK_INSTALL', 'sl-legacy')) {
274 stage('Install StackLight v1') {
275 orchestrate.installStacklightv1Control(saltMaster)
276 orchestrate.installStacklightv1Client(saltMaster)
277 }
278 }
279
280 if (common.checkContains('STACK_INSTALL', 'stacklight')) {
281 stage('Install StackLight') {
282 orchestrate.installDockerSwarm(saltMaster)
283 orchestrate.installStacklight(saltMaster)
284 }
285 }
286
287 //
288 // Test
289 //
290 def artifacts_dir = '_artifacts/'
291
292 if (common.checkContains('STACK_TEST', 'k8s')) {
293 stage('Run k8s bootstrap tests') {
294 def image = 'tomkukral/k8s-scripts'
295 def output_file = image.replaceAll('/', '-') + '.output'
296
297 // run image
Tetiana Korchak225abad2017-09-28 16:16:47 -0700298 test.runConformanceTests(saltMaster, 'ctl01*', TEST_K8S_API_SERVER, image)
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400299
300 // collect output
301 sh "mkdir -p ${artifacts_dir}"
302 file_content = salt.getFileContent(saltMaster, 'ctl01*', '/tmp/' + output_file)
303 writeFile file: "${artifacts_dir}${output_file}", text: file_content
304 sh "cat ${artifacts_dir}${output_file}"
305
306 // collect artifacts
307 archiveArtifacts artifacts: "${artifacts_dir}${output_file}"
308 }
309
310 stage('Run k8s conformance e2e tests') {
Tetiana Korchak225abad2017-09-28 16:16:47 -0700311 //test.runConformanceTests(saltMaster, 'ctl01*', TEST_K8S_API_SERVER, TEST_K8S_CONFORMANCE_IMAGE)
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400312
313 def image = TEST_K8S_CONFORMANCE_IMAGE
314 def output_file = image.replaceAll('/', '-') + '.output'
315
316 // run image
Tetiana Korchak225abad2017-09-28 16:16:47 -0700317 test.runConformanceTests(saltMaster, 'ctl01*', TEST_K8S_API_SERVER, image)
Ruslan Kamaldinov6feef402017-08-02 16:55:58 +0400318
319 // collect output
320 sh "mkdir -p ${artifacts_dir}"
321 file_content = salt.getFileContent(saltMaster, 'ctl01*', '/tmp/' + output_file)
322 writeFile file: "${artifacts_dir}${output_file}", text: file_content
323 sh "cat ${artifacts_dir}${output_file}"
324
325 // collect artifacts
326 archiveArtifacts artifacts: "${artifacts_dir}${output_file}"
327 }
328 }
329
330 if (common.checkContains('STACK_TEST', 'openstack')) {
331 if (common.checkContains('TEST_DOCKER_INSTALL', 'true')) {
332 test.install_docker(saltMaster, TEST_TEMPEST_TARGET)
333 }
334 stage('Run OpenStack tests') {
335 test.runTempestTests(saltMaster, TEST_TEMPEST_IMAGE, TEST_TEMPEST_TARGET, TEST_TEMPEST_PATTERN)
336 }
337
338 stage('Copy Tempest results to config node') {
339 test.copyTempestResults(saltMaster, TEST_TEMPEST_TARGET)
340 }
341 }
342
343 if (common.checkContains('STACK_INSTALL', 'finalize')) {
344 stage('Finalize') {
345 salt.runSaltProcessStep(saltMaster, '*', 'state.apply', [], null, true)
346 }
347 }
348 } catch (Throwable e) {
349 currentBuild.result = 'FAILURE'
350 throw e
351 } finally {
352
353
354 //
355 // Clean
356 //
357
358 if (STACK_TYPE == 'heat') {
359 // send notification
360 common.sendNotification(currentBuild.result, STACK_NAME, ["slack"])
361
362 if (STACK_DELETE.toBoolean() == true) {
363 common.errorMsg('Heat job cleanup triggered')
364 stage('Trigger cleanup job') {
365 build(job: STACK_CLEANUP_JOB, parameters: [
366 [$class: 'StringParameterValue', name: 'STACK_NAME', value: STACK_NAME],
367 [$class: 'StringParameterValue', name: 'STACK_TYPE', value: STACK_TYPE],
368 [$class: 'StringParameterValue', name: 'OPENSTACK_API_URL', value: OPENSTACK_API_URL],
369 [$class: 'StringParameterValue', name: 'OPENSTACK_API_CREDENTIALS', value: OPENSTACK_API_CREDENTIALS],
370 [$class: 'StringParameterValue', name: 'OPENSTACK_API_PROJECT', value: OPENSTACK_API_PROJECT],
371 [$class: 'StringParameterValue', name: 'OPENSTACK_API_PROJECT_DOMAIN', value: OPENSTACK_API_PROJECT_DOMAIN],
372 [$class: 'StringParameterValue', name: 'OPENSTACK_API_PROJECT_ID', value: OPENSTACK_API_PROJECT_ID],
373 [$class: 'StringParameterValue', name: 'OPENSTACK_API_USER_DOMAIN', value: OPENSTACK_API_USER_DOMAIN],
374 [$class: 'StringParameterValue', name: 'OPENSTACK_API_CLIENT', value: OPENSTACK_API_CLIENT],
375 [$class: 'StringParameterValue', name: 'OPENSTACK_API_VERSION', value: OPENSTACK_API_VERSION]
376 ])
377 }
378 } else {
379 if (currentBuild.result == 'FAILURE') {
380 common.errorMsg("Deploy job FAILED and was not deleted. Please fix the problem and delete stack on you own.")
381
382 if (SALT_MASTER_URL) {
383 common.errorMsg("Salt master URL: ${SALT_MASTER_URL}")
384 }
385 }
386
Tomáš Kukrál9e0fb732017-03-02 10:12:05 +0100387 }
Tomáš Kukrálb9957b32017-02-28 14:49:00 +0100388 }
389 }
390}