blob: f124051efccab3bc43ba18d0b88cff8f8f069f43 [file] [log] [blame]
Oleksandr Bryndziif4adf252019-06-14 14:46:39 +00001/**
2 * Upgrade MySQL and Galera packages on dbs nodes.
3 * Update packages on given nodes
4 *
5 * Expected parameters:
6 * SALT_MASTER_CREDENTIALS Credentials to the Salt API.
7 * SALT_MASTER_URL Full Salt API address [http://10.10.10.15:6969].
8 * SHUTDOWN_CLUSTER Shutdown all mysql instances on target nodes at the same time.
9 * OS_DIST_UPGRADE Upgrade system packages including kernel (apt-get dist-upgrade).
10 * OS_UPGRADE Upgrade all installed applications (apt-get upgrade)
11 * TARGET_SERVERS Comma separated list of salt compound definitions to upgrade.
12 * INTERACTIVE Ask interactive questions during pipeline run (bool).
13 *
14**/
15
16def common = new com.mirantis.mk.Common()
17def salt = new com.mirantis.mk.Salt()
18def python = new com.mirantis.mk.Python()
19def debian = new com.mirantis.mk.Debian()
20def openstack = new com.mirantis.mk.Openstack()
21def galera = new com.mirantis.mk.Galera()
22def shutdownCluster = SHUTDOWN_CLUSTER.toBoolean()
23def interactive = INTERACTIVE.toBoolean()
24def LinkedHashMap upgradeStageMap = [:]
25
26upgradeStageMap.put('Pre upgrade',
27 [
28 'Description': 'Only non destructive actions will be applied during this phase. Basic service verification will be performed.',
29 'Status': 'NOT_LAUNCHED',
30 'Expected behaviors': '''
31 * No service downtime
32 * No workload downtime''',
33 'Launched actions': '''
34 * Verify API, perform basic CRUD operations for services.
35 * Verify MySQL is running and Galera cluster is operational.''',
36 'State result': 'Basic checks around wsrep Galera status are passed.'
37 ])
38
39upgradeStageMap.put('Stop MySQL service',
40 [
41 'Description': 'All MySQL services will be stopped on All TARGET_SERVERS nodes.',
42 'Status': 'NOT_LAUNCHED',
43 'Expected behaviors': '''
44 * MySQL services are stopped.
45 * OpenStack APIs are not accessible from this point.
46 * No workload downtime''',
47 'Launched actions': '''
48 * Stop MySQL services''',
49 'State result': 'MySQL service is stopped',
50 ])
51
52upgradeStageMap.put('Upgrade OS',
53 [
54 'Description': 'Optional step. OS packages will be upgraded during this phase, depending on the job parameters dist-upgrade might be called. And reboot of node executed.',
55 'Status': 'NOT_LAUNCHED',
56 'Expected behaviors': '''
57 * No workload downtime
58 * The nodes might be rebooted''',
59 'Launched actions': '''
60 * Install new version of system packages
61 * If doing dist-upgrade new kernel might be installed and node rebooted
62 * System packages are updated
63 * Node might be rebooted
64'''
65 ])
66
67upgradeStageMap.put('Upgrade MySQL server',
68 [
69 'Description': 'MySQL and Erlang code will be upgraded during this stage. No workload downtime is expected.',
70 'Status': 'NOT_LAUNCHED',
71 'Expected behaviors': '''
72 * OpenStack services loose connection to MySQL server
73 * No workload downtime''',
74 'Launched actions': '''
75 * Install new version of MySQL and Galera packages
76 * Render version of configs''',
77 'State result': '''
78 * MySQL packages are upgraded''',
79 ])
80
81upgradeStageMap.put('Start MySQL service',
82 [
83 'Description': 'All MySQL services will be running on All TARGET_SERVERS nodes.',
84 'Status': 'NOT_LAUNCHED',
85 'Expected behaviors': '''
86 * MySQL service is running.
87 * OpenStack API are accessible from this point.
88 * No workload downtime''',
89 'Launched actions': '''
90 * Start MySQL service''',
91 'State result': 'MySQL service is running',
92 ])
93
94def env = "env"
95timeout(time: 12, unit: 'HOURS') {
96 node() {
97
98 stage('Setup virtualenv for Pepper') {
99 python.setupPepperVirtualenv(env, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
100 }
101
102 def upgradeTargets = salt.getMinionsSorted(env, TARGET_SERVERS)
103
104 if (upgradeTargets.isEmpty()) {
105 error("No servers for upgrade matched by ${TARGET_SERVERS}")
106 }
107
108 def targetSecMapping = [:]
109 def secNoList = []
110 def out
111 def stopTargets = upgradeTargets.reverse()
112 common.printStageMap(upgradeStageMap)
113
114 if (interactive){
115 input message: common.getColorizedString(
116 "Above you can find detailed info this pipeline will execute.\nThe info provides brief description of each stage, actions that will be performed and service/workload impact during each stage.\nPlease read it carefully.", "yellow")
117 }
118
119 for (target in upgradeTargets) {
120 salt.runSaltProcessStep(env, target, 'saltutil.refresh_pillar', [], null, true)
121 salt.enforceState(env, target, ['linux.system.repo'])
122 common.stageWrapper(upgradeStageMap, "Pre upgrade", target, interactive) {
123 openstack.runOpenStackUpgradePhase(env, target, 'pre')
124 openstack.runOpenStackUpgradePhase(env, target, 'verify')
125 }
126 }
127
128 if (shutdownCluster){
129 for (target in stopTargets) {
130 common.stageWrapper(upgradeStageMap, "Stop MySQL service", target, interactive) {
131 openstack.runOpenStackUpgradePhase(env, target, 'service_stopped')
132 }
133 }
134 }
135
136 for (target in upgradeTargets) {
137 out = salt.cmdRun(env, target, 'cat /var/lib/mysql/grastate.dat | grep "seqno" | cut -d ":" -f2', true, null, false).get('return')[0].values()[0].replaceAll('Salt command execution success', '').trim()
138 common.infoMsg("Get seqno: ${out} for node ${target}")
139 if (!out.isNumber()){
140 out = -2
141 }
142 targetSecMapping[out.toInteger()] = target
143 secNoList.add(out.toInteger())
144 }
145
146 def masterNode = targetSecMapping[secNoList.max()]
147 common.infoMsg("Master node is: ${masterNode}")
148
149 // Make sure we start upgrade always from master node
150 upgradeTargets.remove(masterNode)
151 upgradeTargets = [masterNode] + upgradeTargets
152 common.infoMsg("Upgrade targets are: ${upgradeTargets}")
153
154 for (target in upgradeTargets) {
155
156 common.stageWrapper(upgradeStageMap, "Stop MySQL service", target, interactive) {
157 openstack.runOpenStackUpgradePhase(env, target, 'service_stopped')
158 }
159
160 common.stageWrapper(upgradeStageMap, "Upgrade OS", target, interactive) {
161 if (OS_DIST_UPGRADE.toBoolean() == true){
162 upgrade_mode = 'dist-upgrade'
163 } else if (OS_UPGRADE.toBoolean() == true){
164 upgrade_mode = 'upgrade'
165 }
166 if (OS_DIST_UPGRADE.toBoolean() == true || OS_UPGRADE.toBoolean() == true) {
167 debian.osUpgradeNode(env, target, upgrade_mode, false)
168 }
169 }
170
171 common.stageWrapper(upgradeStageMap, "Upgrade MySQL server", target, interactive) {
172 openstack.runOpenStackUpgradePhase(env, target, 'pkgs_latest')
173 openstack.runOpenStackUpgradePhase(env, target, 'render_config')
174 }
175
176 if (shutdownCluster && target == masterNode){
177 //Start first node.
178 common.stageWrapper(upgradeStageMap, "Start MySQL service", target, interactive) {
179 galera.startFirstNode(env, target)
180 }
181 }
182
183 common.stageWrapper(upgradeStageMap, "Start MySQL service", target, interactive) {
184 openstack.runOpenStackUpgradePhase(env, target, 'service_running')
185 openstack.runOpenStackUpgradePhase(env, target, 'verify')
186 }
187 }
188
189 // restart first node by applying state.
190
191 if (shutdownCluster) {
192 openstack.runOpenStackUpgradePhase(env, masterNode, 'render_config')
193 salt.cmdRun(env, masterNode, "service mysql reload")
194 openstack.runOpenStackUpgradePhase(env, masterNode, 'verify')
195 }
196
197 for (target in upgradeTargets) {
198 ensureClusterState = galera.getWsrepParameters(env, target, 'wsrep_evs_state')
199 if (ensureClusterState['wsrep_evs_state'] == 'OPERATIONAL') {
200 common.infoMsg('Node is in OPERATIONAL state.')
201 } else {
202 throw new Exception("Node is NOT in OPERATIONAL state.")
203 }
204 }
205 }
206}