blob: f71b7be8916db89875657c2dc46ece74844f21e2 [file] [log] [blame]
Anton Samoylovc6400692019-01-16 00:36:00 +04001/**
2 * Update pipeline for OpenContrail 4X versions
3 *
4 * Expected parameters:
5 * SALT_MASTER_CREDENTIALS Credentials to the Salt API.
6 * SALT_MASTER_URL Full Salt API address [http://10.10.10.1:8000].
7 * STAGE_CONTROLLERS_UPDATE Run update on OpenContrail controller and analytic nodes (bool)
8 * STAGE_COMPUTES_UPDATE Run update OpenContrail components on compute nodes (bool)
9 *
10 **/
11
12common = new com.mirantis.mk.Common()
13salt = new com.mirantis.mk.Salt()
14python = new com.mirantis.mk.Python()
15
16def pepperEnv = "pepperEnv"
Sergey Galkind4744f62019-11-25 17:22:40 +040017def askConfirmation = (env.getProperty('ASK_CONFIRMATION') ?: true).toBoolean()
Anton Samoylovc6400692019-01-16 00:36:00 +040018def supportedOcTargetVersions = ['4.0', '4.1']
19def neutronServerPkgs = 'neutron-plugin-contrail,contrail-heat,python-contrail'
20def config4Services = ['zookeeper', 'contrail-webui-middleware', 'contrail-webui', 'contrail-api', 'contrail-schema', 'contrail-svc-monitor', 'contrail-device-manager', 'contrail-config-nodemgr', 'contrail-database']
21def dashboardPanelPkg = 'openstack-dashboard-contrail-panels'
22def targetOcVersion
23
24def cmpMinions
25def cmpMinionsFirstSubset
26def cmpMinionsSecondSubset
27def cmpTargetAll
28def cmpTargetFirstSubset
29def cmpTargetSecondSubset
30
31def checkContrailServices(pepperEnv, oc_version, target) {
32
33 def checkCmd
34
35 if (oc_version.startsWith('4')) {
36
37 checkCmd = "doctrail all contrail-status | grep -v == | grep -v FOR | grep -v \\* | grep -v \'disabled on boot\' | grep -v nodemgr | grep -v active | grep -v backup | grep -v -F /var/crashes/"
38
39 if (oc_version == '4.1') {
40 def targetMinions = salt.getMinions(pepperEnv, target)
41 def collectorMinionsInTarget = targetMinions.intersect(salt.getMinions(pepperEnv, 'I@opencontrail:collector'))
42
43 if (collectorMinionsInTarget.size() != 0) {
44 def cassandraConfigYaml = readYaml text: salt.getFileContent(pepperEnv, 'I@opencontrail:control:role:primary', '/etc/cassandra/cassandra.yaml')
45
46 def currentCassandraNativeTransportPort = cassandraConfigYaml['native_transport_port'] ?: "9042"
47 def currentCassandraRpcPort = cassandraConfigYaml['rpc_port'] ?: "9160"
48
49 def cassandraNativeTransportPort = getValueForPillarKey(pepperEnv, "I@opencontrail:control:role:primary", "opencontrail:database:bind:port_configdb")
50 def cassandraCassandraRpcPort = getValueForPillarKey(pepperEnv, "I@opencontrail:control:role:primary", "opencontrail:database:bind:rpc_port_configdb")
51
52 if (currentCassandraNativeTransportPort != cassandraNativeTransportPort) {
53 checkCmd += ' | grep -v \'contrail-collector.*(Database:Cassandra connection down)\''
54 }
55
56 if (currentCassandraRpcPort != cassandraCassandraRpcPort) {
57 checkCmd += ' | grep -v \'contrail-alarm-gen.*(Database:Cassandra\\[\\] connection down)\''
58 }
59 }
60 }
61
62 } else {
63 checkCmd = "contrail-status | grep -v == | grep -v FOR | grep -v \'disabled on boot\' | grep -v nodemgr | grep -v active | grep -v backup | grep -v -F /var/crashes/"
64 }
65
66 salt.commandStatus(pepperEnv, target, checkCmd, null, false, true, null, true, 500)
67}
68
69def getValueForPillarKey(pepperEnv, target, pillarKey) {
70 def out = salt.getReturnValues(salt.getPillar(pepperEnv, target, pillarKey))
71 if (out == '') {
72 throw new Exception("Cannot get value for ${pillarKey} key on ${target} target")
73 }
74 return out.toString()
75}
76
77def cmpNodesUpdate(pepperEnv, target) {
78
79 def cmpPkgs = 'contrail-lib contrail-nodemgr contrail-utils contrail-vrouter-agent contrail-vrouter-utils python-contrail python-contrail-vrouter-api python-opencontrail-vrouter-netns contrail-vrouter-dkms'
80 def aptCmd = "export DEBIAN_FRONTEND=noninteractive; apt install -o Dpkg::Options::=\"--force-confold\" ${cmpPkgs} -y;"
81 def kernelModuleReloadCmd = 'service contrail-vrouter-agent stop; service contrail-vrouter-nodemgr stop; rmmod vrouter; sync && echo 3 > /proc/sys/vm/drop_caches && echo 1 > /proc/sys/vm/compact_memory; service contrail-vrouter-agent start; service contrail-vrouter-nodemgr start'
82 def out
83
84 try {
85 salt.runSaltProcessStep(pepperEnv, target, 'saltutil.refresh_pillar', [], null, true)
86 salt.runSaltProcessStep(pepperEnv, target, 'saltutil.sync_all', [], null, true)
87 salt.runSaltProcessStep(pepperEnv, target, 'file.remove', ["/etc/apt/sources.list.d/mcp_opencontrail.list"], null, true)
88 salt.enforceState(pepperEnv, target, 'linux.system.repo')
89 } catch (Exception er) {
90 common.errorMsg("Opencontrail component on ${target} probably failed to be replaced. Please check availability of contrail packages before continuing.")
91 throw er
92 }
93
94 out = salt.runSaltCommand(pepperEnv, 'local', ['expression': target, 'type': 'compound'], 'cmd.shell', null, aptCmd, null)
95 salt.printSaltCommandResult(out)
96
97 try {
98 salt.enforceState(pepperEnv, target, 'opencontrail')
99 } catch (Exception er) {
100 common.errorMsg("Opencontrail state was executed on ${target} and failed please fix it manually.")
101 }
102
103 salt.runSaltProcessStep(pepperEnv, target, 'cmd.shell', [kernelModuleReloadCmd], null, true)
104 salt.commandStatus(pepperEnv, target, 'contrail-status | grep -v == | grep -v active | grep -v -F /var/crashes/', null, false)
105 out = salt.runSaltCommand(pepperEnv, 'local', ['expression': target, 'type': 'compound'], 'cmd.shell', null, "contrail-status", null)
106 salt.printSaltCommandResult(out)
107}
108
109timeout(time: 12, unit: 'HOURS') {
110 node() {
111
112 stage('Setup virtualenv for Pepper') {
113 python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
114 }
115
116 if (STAGE_CONTROLLERS_UPDATE.toBoolean() == true) {
117
118 stage('Sync Salt data') {
119
120 // Sync data on minions
121 salt.runSaltProcessStep(pepperEnv, 'I@keystone:server:role:primary or I@opencontrail:database or I@neutron:server or I@horizon:server', 'saltutil.refresh_pillar', [], null, true)
122 salt.runSaltProcessStep(pepperEnv, 'I@keystone:server:role:primary or I@opencontrail:database or I@neutron:server or I@horizon:server', 'saltutil.sync_all', [], null, true)
123 }
124
125 stage('Verify OpenContrail version compatibility') {
126
127 // Verify specified target OpenContrail version before update
128 targetOcVersion = getValueForPillarKey(pepperEnv, "I@opencontrail:control:role:primary", "_param:opencontrail_version")
129 if (!supportedOcTargetVersions.contains(targetOcVersion)) {
130 throw new Exception("Specified OpenContrail version ${targetOcVersion} is not supported by update pipeline. Supported versions: ${supportedOcTargetVersions}")
131 }
132 }
133
134 stage('Opencontrail controllers health check') {
135 try {
136 salt.enforceState(pepperEnv, 'I@opencontrail:control or I@opencontrail:collector', 'opencontrail.upgrade.verify', true, true)
137 } catch (Exception er) {
138 common.errorMsg("OpenContrail controllers health check stage found issues with services. Please take a look at the logs above.")
139 throw er
140 }
141 }
142
143 stage('Update system repositories') {
144 try {
145 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:control or I@opencontrail:collector', 'file.remove', ["/etc/apt/sources.list.d/mcp_opencontrail.list"], null, true)
146 salt.enforceState(pepperEnv, 'I@opencontrail:control or I@opencontrail:collector or I@neutron:server or I@horizon:server', 'linux.system.repo')
147
148 } catch (Exception er) {
149 common.errorMsg("System repositories failed to be updated on I@opencontrail:control, I@opencontrail:collector, I@neutron:server or I@horizon:server nodes.")
150 throw er
151 }
152 }
153
154 stage('OpenContrail controllers update') {
155
156 // Make sure that dedicated opencontrail user is created
157 salt.enforceState(pepperEnv, 'I@keystone:server:role:primary', 'keystone.client.server')
158
159 // Stop neutron-server to prevent creation of new objects in contrail
160 salt.runSaltProcessStep(pepperEnv, 'I@neutron:server', 'service.stop', ['neutron-server'])
161
162 // Backup Zookeeper data
163 salt.enforceState(pepperEnv, 'I@zookeeper:backup:server', 'zookeeper.backup')
164 salt.enforceState(pepperEnv, 'I@zookeeper:backup:client', 'zookeeper.backup')
165
166 try {
167 salt.cmdRun(pepperEnv, 'I@opencontrail:control', "su root -c '/usr/local/bin/zookeeper-backup-runner.sh'")
168 } catch (Exception er) {
169 common.errorMsg('Zookeeper failed to backup. Please fix it before continuing.')
170 throw er
171 }
172
173 // Backup Cassandra DB
174 salt.enforceState(pepperEnv, 'I@cassandra:backup:server', 'cassandra.backup')
175 salt.enforceState(pepperEnv, 'I@cassandra:backup:client', 'cassandra.backup')
176
177 try {
178 salt.cmdRun(pepperEnv, 'I@cassandra:backup:client', "su root -c '/usr/local/bin/cassandra-backup-runner-call.sh'")
179 } catch (Exception er) {
180 common.errorMsg('Cassandra failed to backup. Please fix it before continuing.')
181 throw er
182 }
183
184 try {
185 // Get docker images info
186 controllerImage = getValueForPillarKey(pepperEnv, "I@opencontrail:control:role:primary", "docker:client:compose:opencontrail:service:controller:image")
187 analyticsImage = getValueForPillarKey(pepperEnv, "I@opencontrail:collector:role:primary", "docker:client:compose:opencontrail:service:analytics:image")
188 analyticsdbImage = getValueForPillarKey(pepperEnv, "I@opencontrail:collector:role:primary", "docker:client:compose:opencontrail:service:analyticsdb:image")
189
190 // Pull new docker images
191 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:control', 'dockerng.pull', [controllerImage])
192 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:collector', 'dockerng.pull', [analyticsImage])
193 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:collector', 'dockerng.pull', [analyticsdbImage])
194
195 } catch (Exception er) {
196 common.errorMsg("OpenContrail docker images failed be upgraded.")
197 throw er
198 }
199
200 try {
201 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:collector', 'cmd.shell', ['cd /etc/docker/compose/opencontrail/; docker-compose down'], null, true)
202
203 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:collector', 'state.sls', ['opencontrail', 'exclude=opencontrail.client'])
204 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:collector', 'state.sls', ['opencontrail.client'])
205
206 salt.enforceState(pepperEnv, 'I@opencontrail:collector', 'docker.client')
207 if (targetOcVersion == '4.1') {
208 sleep(15)
209 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:collector', 'cmd.shell', ["doctrail analyticsdb systemctl restart confluent-kafka"], null, true)
210 }
211 checkContrailServices(pepperEnv, targetOcVersion, 'I@opencontrail:collector')
212 } catch (Exception er) {
213 common.errorMsg("OpenContrail Analytic nodes failed to be upgraded.")
214 throw er
215 }
216
217 try {
218 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:control:role:secondary', 'cmd.shell', ['cd /etc/docker/compose/opencontrail/; docker-compose down'], null, true)
219 for (service in config4Services) {
220 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:control:role:primary', 'cmd.shell', ["doctrail controller systemctl stop ${service}"], null, true)
221 }
222 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:control:role:secondary', 'state.sls', ['opencontrail', 'exclude=opencontrail.client'])
223
224 salt.enforceState(pepperEnv, 'I@opencontrail:control:role:secondary', 'docker.client')
225 checkContrailServices(pepperEnv, targetOcVersion, 'I@opencontrail:control:role:secondary')
226
227 sleep(120)
228
229 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:control:role:primary', 'cmd.shell', ['cd /etc/docker/compose/opencontrail/; docker-compose down'], null, true)
230 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:control:role:primary', 'state.sls', ['opencontrail', 'exclude=opencontrail.client'])
231
232 salt.enforceState(pepperEnv, 'I@opencontrail:control:role:primary', 'docker.client')
233 checkContrailServices(pepperEnv, targetOcVersion, 'I@opencontrail:control:role:primary')
234 } catch (Exception er) {
235 common.errorMsg("OpenContrail Controller nodes failed to be upgraded.")
236 throw er
237 }
238
239 // Run opencontrail.client state once contrail-api is ready to service requests from clients
240 salt.runSaltProcessStep(pepperEnv, 'I@opencontrail:control or I@opencontrail:collector', 'state.sls', ['opencontrail.client'])
241
242 try {
243 salt.runSaltProcessStep(pepperEnv, 'I@neutron:server', 'pkg.install', [neutronServerPkgs])
244 salt.runSaltProcessStep(pepperEnv, 'I@horizon:server', 'pkg.install', [dashboardPanelPkg])
245 salt.runSaltProcessStep(pepperEnv, 'I@neutron:server', 'service.start', ['neutron-server'])
246 salt.enforceState(pepperEnv, 'I@horizon:server', 'horizon')
247 } catch (Exception er) {
248 common.errorMsg("Update of packages on neutron and horizon nodes has been failed")
249 throw er
250 }
251 }
252 }
253
254 if (STAGE_COMPUTES_UPDATE.toBoolean() == true) {
255
256 try {
257 stage('List targeted compute servers') {
258 cmpMinions = salt.getMinions(pepperEnv, COMPUTE_TARGET_SERVERS)
259 cmpMinionsFirstSubset = cmpMinions[0..<Integer.valueOf(COMPUTE_TARGET_SUBSET_LIVE)]
260 cmpMinionsSecondSubset = cmpMinions - cmpMinionsFirstSubset
261
262 if (cmpMinions.isEmpty()) {
263 throw new Exception("No minions were found by specified target")
264 }
265
266 common.infoMsg("Found nodes: ${cmpMinions}")
267 common.infoMsg("Selected sample nodes: ${cmpMinionsFirstSubset}")
268
269 cmpTargetAll = cmpMinions.join(' or ')
270 cmpTargetFirstSubset = cmpMinionsFirstSubset.join(' or ')
271 cmpTargetSecondSubset = cmpMinionsSecondSubset.join(' or ')
272 }
273
274 stage('Compute nodes health check') {
275 try {
276 salt.enforceState(pepperEnv, cmpTargetAll, 'opencontrail.upgrade.verify', true, true)
277 } catch (Exception er) {
278 common.errorMsg("Opencontrail compute nodes health check stage found issues with services. Please take a look at the logs above.")
279 throw er
280 }
281 }
282
283 stage('Confirm update on sample nodes') {
Sergey Galkind4744f62019-11-25 17:22:40 +0400284 if (askConfirmation) {
285 input message: "Do you want to continue with the Opencontrail components update on compute sample nodes? ${cmpTargetFirstSubset}"
286 }
Anton Samoylovc6400692019-01-16 00:36:00 +0400287 }
288
289 stage("Opencontrail compute update on sample nodes") {
290
291 cmpNodesUpdate(pepperEnv, cmpTargetFirstSubset)
292 }
293
294 stage('Confirm update on all remaining target nodes') {
Sergey Galkind4744f62019-11-25 17:22:40 +0400295 if (askConfirmation) {
296 input message: "Do you want to continue with the Opencontrail components update on all targeted compute nodes? Node list: ${cmpTargetSecondSubset}"
297 }
Anton Samoylovc6400692019-01-16 00:36:00 +0400298 }
299
300 stage("Opencontrail compute update on all targeted nodes") {
301
302 cmpNodesUpdate(pepperEnv, cmpTargetSecondSubset)
303 }
304
305 } catch (Throwable e) {
306 // If there was an error or exception thrown, the build failed
307 currentBuild.result = "FAILURE"
308 currentBuild.description = currentBuild.description ? e.message + " " + currentBuild.description : e.message
309 throw e
310 }
311 }
312 }
313}