blob: 5433945effb1ae27b23653529a161f8b494597c1 [file] [log] [blame]
Filip Pytloun0a07f702017-02-24 18:26:18 +01001/**
2 *
3 * Launch heat stack with CI/CD lab infrastructure
4 *
5 * Expected parameters:
6 * HEAT_TEMPLATE_URL URL to git repo with Heat templates
7 * HEAT_TEMPLATE_CREDENTIALS Credentials to the Heat templates repo
8 * HEAT_TEMPLATE_BRANCH Heat templates repo branch
9 * HEAT_STACK_NAME Heat stack name
10 * HEAT_STACK_TEMPLATE Heat stack HOT template
11 * HEAT_STACK_ENVIRONMENT Heat stack environmental parameters
12 * HEAT_STACK_ZONE Heat stack availability zone
13 * HEAT_STACK_PUBLIC_NET Heat stack floating IP pool
14 * HEAT_STACK_DELETE Delete Heat stack when finished (bool)
15 * HEAT_STACK_CLEANUP_JOB Name of job for deleting Heat stack
16 * HEAT_STACK_REUSE Reuse Heat stack (don't create one)
17 *
18 * SALT_MASTER_CREDENTIALS Credentials to the Salt API
Filip Pytloune32fda82017-02-24 18:26:18 +010019 * SALT_MASTER_PORT Port of salt-api, defaults to 8000
Filip Pytloun0a07f702017-02-24 18:26:18 +010020 *
21 * OPENSTACK_API_URL OpenStack API address
22 * OPENSTACK_API_CREDENTIALS Credentials to the OpenStack API
23 * OPENSTACK_API_PROJECT OpenStack project to connect to
24 * OPENSTACK_API_CLIENT Versions of OpenStack python clients
25 * OPENSTACK_API_VERSION Version of the OpenStack API (2/3)
26 *
27 */
28
29git = new com.mirantis.mk.Git()
30openstack = new com.mirantis.mk.Openstack()
31salt = new com.mirantis.mk.Salt()
32orchestrate = new com.mirantis.mk.Orchestrate()
33
34node {
Filip Pytloun0a07f702017-02-24 18:26:18 +010035 // connection objects
36 def openstackCloud
37 def saltMaster
38
39 // value defaults
40 def openstackVersion = OPENSTACK_API_CLIENT ? OPENSTACK_API_CLIENT : 'liberty'
41 def openstackEnv = "${env.WORKSPACE}/venv"
42
43 if (HEAT_STACK_NAME == '') {
44 HEAT_STACK_NAME = BUILD_TAG
45 }
46
47 //
48 // Bootstrap
49 //
50
51 stage ('Download Heat templates') {
52 git.checkoutGitRepository('template', HEAT_TEMPLATE_URL, HEAT_TEMPLATE_BRANCH, HEAT_TEMPLATE_CREDENTIALS)
53 }
54
55 stage('Install OpenStack CLI') {
56 openstack.setupOpenstackVirtualenv(openstackEnv, openstackVersion)
57 }
58
59 stage('Connect to OpenStack cloud') {
60 openstackCloud = openstack.createOpenstackEnv(OPENSTACK_API_URL, OPENSTACK_API_CREDENTIALS, OPENSTACK_API_PROJECT)
61 openstack.getKeystoneToken(openstackCloud, openstackEnv)
62 }
63
64 if (HEAT_STACK_REUSE == 'false') {
65 stage('Launch new Heat stack') {
66 envParams = [
67 'instance_zone': HEAT_STACK_ZONE,
68 'public_net': HEAT_STACK_PUBLIC_NET
69 ]
70 openstack.createHeatStack(openstackCloud, HEAT_STACK_NAME, HEAT_STACK_TEMPLATE, envParams, HEAT_STACK_ENVIRONMENT, openstackEnv)
71 }
72 }
73
74 stage('Connect to Salt master') {
Filip Pytloune32fda82017-02-24 18:26:18 +010075 def saltMasterPort
76 try {
77 saltMasterPort = SALT_MASTER_PORT
78 } catch (MissingPropertyException e) {
79 saltMasterPort = 8000
80 }
Filip Pytloun0a07f702017-02-24 18:26:18 +010081 saltMasterHost = openstack.getHeatStackOutputParam(openstackCloud, HEAT_STACK_NAME, 'salt_master_ip', openstackEnv)
Filip Pytloune32fda82017-02-24 18:26:18 +010082 saltMasterUrl = "http://${saltMasterHost}:${saltMasterPort}"
Filip Pytloun0a07f702017-02-24 18:26:18 +010083 saltMaster = salt.connection(saltMasterUrl, SALT_MASTER_CREDENTIALS)
84 }
85
86 //
87 // Install
88 //
89
90 stage('Install core infra') {
91 // salt.master, reclass
92 // refresh_pillar
93 // sync_all
94 // linux,openssh,salt.minion.ntp
95
96 orchestrate.installFoundationInfra(saltMaster)
97 orchestrate.validateFoundationInfra(saltMaster)
98 }
99
100 stage("Deploy GlusterFS") {
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100101 salt.enforceState(saltMaster, 'I@glusterfs:server', 'glusterfs.server.service', true)
102 salt.enforceState(saltMaster, 'ci01*', 'glusterfs.server.setup', true)
103 sleep(5)
104 salt.enforceState(saltMaster, 'I@glusterfs:client', 'glusterfs.client', true)
Filip Pytloun2a9d78d2017-02-27 19:53:21 +0100105 print salt.cmdRun(saltMaster, 'I@glusterfs:client', 'mount|grep fuse.glusterfs || echo "Command failed"')
Filip Pytloun0a07f702017-02-24 18:26:18 +0100106 }
107
108 stage("Deploy GlusterFS") {
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100109 salt.enforceState(saltMaster, 'I@haproxy:proxy', 'haproxy,keepalived')
Filip Pytloun0a07f702017-02-24 18:26:18 +0100110 }
111
112 stage("Setup Docker Swarm") {
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100113 salt.enforceState(saltMaster, 'I@docker:host', 'docker.host', true)
114 salt.enforceState(saltMaster, 'I@docker:swarm:role:master', 'docker.swarm', true)
115 salt.enforceState(saltMaster, 'I@docker:swarm:role:master', 'salt', true)
Filip Pytloun67fc9a22017-02-27 16:49:04 +0100116 salt.runSaltProcessStep(saltMaster, 'I@docker:swarm:role:master', 'mine.flush')
117 salt.runSaltProcessStep(saltMaster, 'I@docker:swarm:role:master', 'mine.update')
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100118 salt.enforceState(saltMaster, 'I@docker:swarm', 'docker.swarm', true)
Filip Pytlound3186c12017-02-27 19:44:26 +0100119 print salt.cmdRun(saltMaster, 'I@docker:swarm:role:master', 'docker node ls')
Filip Pytloun0a07f702017-02-24 18:26:18 +0100120 }
121
122 stage("Deploy Docker services") {
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100123 salt.enforceState(saltMaster, 'I@docker:swarm:role:master', 'docker.client')
Filip Pytloun23741982017-02-27 17:43:00 +0100124
125 // XXX: Hack to fix dependency of gerrit on mysql
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100126 print salt.cmdRun(saltMaster, 'I@docker:swarm:role:master', "docker service rm gerrit; rm -rf /srv/volumes/gerrit/*")
Filip Pytloun2a9d78d2017-02-27 19:53:21 +0100127 sleep(10)
Filip Pytloun4f739a22017-02-27 18:33:09 +0100128 print salt.cmdRun(saltMaster, 'I@docker:swarm:role:master', "apt-get install -y mysql-client; mysql -ppassword -h172.16.10.254 -e'drop database gerrit;create database gerrit;'")
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100129 salt.enforceState(saltMaster, 'I@docker:swarm:role:master', 'docker.client')
130 // ---- cut here (end of hack) ----
Filip Pytloun0a07f702017-02-24 18:26:18 +0100131
132 retry(30) {
Filip Pytloun2a9d78d2017-02-27 19:53:21 +0100133 out = salt.cmdRun(saltMaster, 'I@docker:swarm:role:master', """/bin/bash -c 'docker service ls | grep -E "0/[0-9]+"' && echo 'Some services are not running'""")
134 for (entry in out['return']) {
135 for (node in entry) {
136 if (node.value =~ /Some services are not running/) {
137 throw new Exception("$node.key: $node.value)
138 } else {
139 print out
140 }
141 }
142 }
Filip Pytloun0a07f702017-02-24 18:26:18 +0100143 sleep(10)
144 }
145 }
146
147 stage("Configure CI/CD services") {
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100148 salt.enforceState(saltMaster, 'I@docker:swarm:role:master', 'aptly', true)
Filip Pytloun0a07f702017-02-24 18:26:18 +0100149 retry(2) {
150 // Needs to run twice to pass __virtual__ method of gerrit module
151 // after installation of dependencies
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100152 salt.enforceState(saltMaster, 'I@docker:swarm:role:master', 'gerrit', true)
Filip Pytloun0a07f702017-02-24 18:26:18 +0100153 }
Filip Pytloun23741982017-02-27 17:43:00 +0100154 retry(2) {
155 // Same for jenkins
Filip Pytloun89ae83a2017-02-27 18:31:55 +0100156 salt.enforceState(saltMaster, 'I@docker:swarm:role:master', 'jenkins', true)
Filip Pytloun23741982017-02-27 17:43:00 +0100157 }
Filip Pytloun0a07f702017-02-24 18:26:18 +0100158 }
159
160 //
161 // Cleanup
162 //
163
164 if (HEAT_STACK_DELETE == 'true') {
165 stage('Trigger cleanup job') {
166 build job: 'deploy_heat_cleanup', parameters: [[$class: 'StringParameterValue', name: 'HEAT_STACK_NAME', value: HEAT_STACK_NAME]]
167 }
168 }
169}