blob: d323f1df9d1aec761aeafe772fc42f4fde2d818b [file] [log] [blame]
Jiri Broulikdc87d722017-11-03 15:43:22 +01001/**
2 *
3 * Upgrade Ceph mon/mgr/osd/rgw/client
4 *
5 * Requred parameters:
6 * SALT_MASTER_URL URL of Salt master
7 * SALT_MASTER_CREDENTIALS Credentials to the Salt API
8 *
Jiri Broulikdc87d722017-11-03 15:43:22 +01009 * CLUSTER_FLAGS Comma separated list of tags to apply to cluster
10 * WAIT_FOR_HEALTHY Wait for cluster rebalance before stoping daemons
Denis Egorenkoa5594de2021-01-11 15:24:45 +040011 * ASK_CONFIRMATION Ask for manual confirmation
Jiri Broulikdc87d722017-11-03 15:43:22 +010012 * ORIGIN_RELEASE Ceph release version before upgrade
13 * TARGET_RELEASE Ceph release version after upgrade
14 * STAGE_UPGRADE_MON Set to True if Ceph mon nodes upgrade is desired
15 * STAGE_UPGRADE_MGR Set to True if Ceph mgr nodes upgrade or new deploy is desired
16 * STAGE_UPGRADE_OSD Set to True if Ceph osd nodes upgrade is desired
17 * STAGE_UPGRADE_RGW Set to True if Ceph rgw nodes upgrade is desired
18 * STAGE_UPGRADE_CLIENT Set to True if Ceph client nodes upgrade is desired (includes for example ctl/cmp nodes)
Michael Vollmanbcec46f2019-05-07 08:10:00 -040019 * STAGE_FINALIZE Set to True if configs recommended for TARGET_RELEASE should be set after upgrade is done
20 * BACKUP_ENABLED Select to copy the disks of Ceph VMs before upgrade and backup Ceph directories on OSD nodes
21 * BACKUP_DIR Select the target dir to backup to when BACKUP_ENABLED
Jiri Broulikdc87d722017-11-03 15:43:22 +010022 *
23 */
24
25common = new com.mirantis.mk.Common()
26salt = new com.mirantis.mk.Salt()
27def python = new com.mirantis.mk.Python()
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040028ceph = new com.mirantis.mk.Ceph()
Vladimir Khlyunevfe415cc2022-08-02 13:58:43 +040029upgradeChecks = new com.mirantis.mcp.UpgradeChecks()
Denis Egorenkoa5594de2021-01-11 15:24:45 +040030askConfirmation = (env.getProperty('ASK_CONFIRMATION') ?: true).toBoolean()
Jiri Broulikdc87d722017-11-03 15:43:22 +010031
Tomek Jaroszykbddec292020-08-18 10:21:54 +020032pepperEnv = "pepperEnv"
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040033flags = CLUSTER_FLAGS.tokenize(',')
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010034// sortbitwise is set by default on version >jewel.
35// For jewel upgrade we will set and keep it while for other cases shouldn't be there
36flags.removeElement('sortbitwise')
Jiri Broulikdc87d722017-11-03 15:43:22 +010037
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040038def backup(master, target) {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010039 stage("backup $target") {
Jiri Broulik96c867a2017-11-07 16:14:10 +010040
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010041 if (target == 'osd') {
Jiri Broulik96c867a2017-11-07 16:14:10 +010042 try {
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010043 salt.enforceState(master, "I@ceph:${target}", "ceph.backup", true)
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010044 ceph.cmdRunOnTarget(master, "I@ceph:${target}", "su root -c '/usr/local/bin/ceph-backup-runner-call.sh'")
Jiri Broulik96c867a2017-11-07 16:14:10 +010045 } catch (Exception e) {
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010046 common.errorMsg(e)
47 common.errorMsg("Make sure Ceph backup on OSD nodes is enabled")
48 throw new InterruptedException()
Jiri Broulik96c867a2017-11-07 16:14:10 +010049 }
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010050 } else {
51 def _pillar = salt.getGrain(master, 'I@salt:master', 'domain')
52 def domain = _pillar['return'][0].values()[0].values()[0]
53
54 def kvm_pillar = salt.getGrain(master, 'I@salt:control', 'id')
55 def kvm01 = kvm_pillar['return'][0].values()[0].values()[0]
56
57 def target_pillar = salt.getGrain(master, "I@ceph:${target}", 'host')
58 def minions = target_pillar['return'][0].values()
59 for (minion in minions) {
60 def minion_name = minion.values()[0]
61 def provider_pillar = salt.getPillar(master, "${kvm01}", "salt:control:cluster:internal:node:${minion_name}:provider")
62 def minionProvider = provider_pillar['return'][0].values()[0]
63
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010064 ceph.waitForHealthy(master, flags)
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010065 try {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010066 ceph.cmdRunOnTarget(master, minionProvider, "[ ! -f ${BACKUP_DIR}/${minion_name}.${domain}.qcow2.bak ] && virsh destroy ${minion_name}.${domain}")
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010067 } catch (Exception e) {
68 common.warningMsg('Backup already exists')
69 }
70 try {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010071 ceph.cmdRunOnTarget(master, minionProvider, "[ ! -f ${BACKUP_DIR}/${minion_name}.${domain}.qcow2.bak ] && cp /var/lib/libvirt/images/${minion_name}.${domain}/system.qcow2 ${BACKUP_DIR}/${minion_name}.${domain}.qcow2.bak")
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010072 } catch (Exception e) {
73 common.warningMsg('Backup already exists')
74 }
75 try {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010076 ceph.cmdRunOnTarget(master, minionProvider, "virsh start ${minion_name}.${domain}")
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010077 } catch (Exception e) {
78 common.warningMsg(e)
79 }
80 salt.minionsReachable(master, 'I@salt:master', "${minion_name}*")
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010081 ceph.waitForHealthy(master, flags)
Jiri Broulik96c867a2017-11-07 16:14:10 +010082 }
Jiri Broulik96c867a2017-11-07 16:14:10 +010083 }
84 }
85 return
86}
87
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040088def upgrade(master, target) {
Jiri Broulikdc87d722017-11-03 15:43:22 +010089
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +010090 stage("Change $target repos") {
Jiri Broulikdc87d722017-11-03 15:43:22 +010091 salt.runSaltProcessStep(master, "I@ceph:${target}", 'saltutil.refresh_pillar', [], null, true, 5)
92 salt.enforceState(master, "I@ceph:${target}", 'linux.system.repo', true)
93 }
Jiri Broulikdc87d722017-11-03 15:43:22 +010094 if (target == 'mgr') {
95 stage('Run ceph mgr state') {
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +020096 salt.enforceState(master, "I@ceph:mgr", "ceph.mgr", true, failOnError=false, retries=3, retries_wait=10)
Jiri Broulikdc87d722017-11-03 15:43:22 +010097 }
98 }
Jiri Broulikdc87d722017-11-03 15:43:22 +010099 if (target == 'common') {
100 stage('Upgrade ceph-common pkgs') {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100101 salt.runSaltProcessStep(master, "I@ceph:common", 'pkg.install', ["ceph-common"], 'only_upgrade=True')
Jiri Broulikdc87d722017-11-03 15:43:22 +0100102 }
103 } else {
Jiri Broulik96c867a2017-11-07 16:14:10 +0100104 minions = salt.getMinions(master, "I@ceph:${target}")
Jiri Broulikdc87d722017-11-03 15:43:22 +0100105
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100106 def ignoreDifferentSubversions = false
Jiri Broulik96c867a2017-11-07 16:14:10 +0100107 for (minion in minions) {
108 // upgrade pkgs
109 if (target == 'radosgw') {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100110 stage("Upgrade radosgw pkgs on $minion") {
111 salt.runSaltProcessStep(master, minion, 'pkg.install', [target], 'only_upgrade=True')
Jiri Broulik96c867a2017-11-07 16:14:10 +0100112 }
113 } else {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100114 stage("Upgrade $target pkgs on $minion") {
115 salt.runSaltProcessStep(master, minion, 'pkg.install', ["ceph-${target}"], 'only_upgrade=True')
116 }
117 }
118 // check for subversion difference before restart
119 if (ignoreDifferentSubversions) {
120 targetVersion = ceph.cmdRun(master, "ceph versions | grep $TARGET_RELEASE | awk '{print \$3}' | sort -V | tail -1")
121 updatedVersion = ceph.cmdRunOnTarget(master, minion, "ceph version | awk '{print \$3}'")
122 if (targetVersion != updatedVersion) {
123 stage('Version differnce warning') {
124 common.warningMsg("A potential problem has been spotted.")
125 common.warningMsg("Some components already have $targetVersion version while ceph-$target has just been updated to $updatedVersion")
126 input message: "Do you want to proceed with restarts and silence this warning?"
127 ignoreDifferentSubversions = true
128 }
Jiri Broulik96c867a2017-11-07 16:14:10 +0100129 }
130 }
131 // restart services
132 stage("Restart ${target} services on ${minion}") {
Mateusz Losabf4ef52020-05-11 10:37:23 +0200133 if(target == 'osd') {
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +0200134 def ceph_disks = salt.getGrain(master, minion, 'ceph')['return'][0].values()[0].values()[0]['ceph_disk']
Mateusz Losb8575e62020-02-06 13:33:42 +0100135 ceph_disks.each { osd, param ->
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100136 ceph.cmdRunOnTarget(master, minion, "systemctl restart ceph-${target}@${osd}")
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400137 }
Mateusz Losabf4ef52020-05-11 10:37:23 +0200138 }
139 else {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100140 ceph.cmdRunOnTarget(master, minion, "systemctl restart ceph-${target}.target")
Mateusz Losabf4ef52020-05-11 10:37:23 +0200141 }
142
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100143 ceph.waitForHealthy(master, flags)
Jiri Broulik96c867a2017-11-07 16:14:10 +0100144 }
145
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100146 stage("Verify services for $minion") {
Jiri Broulik96c867a2017-11-07 16:14:10 +0100147 sleep(10)
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100148 ceph.cmdRunOnTarget(master, minion, "systemctl status ceph-${target}.target")
Jiri Broulik96c867a2017-11-07 16:14:10 +0100149 }
150
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100151 stage('Verify Ceph status') {
152 ceph.cmdRun(master, "ceph -s", true, true)
153 if (askConfirmation) {
154 input message: "From the verification command above, please check Ceph $target joined the cluster correctly. If so, Do you want to continue to upgrade next node?"
Denis Egorenkoa5594de2021-01-11 15:24:45 +0400155 }
Jiri Broulik96c867a2017-11-07 16:14:10 +0100156 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100157 }
158 }
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100159 ceph.cmdRun(master, "ceph versions")
Jiri Broulikdc87d722017-11-03 15:43:22 +0100160 sleep(5)
161 return
162}
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400163
Jakub Josefa63f9862018-01-11 17:58:38 +0100164timeout(time: 12, unit: 'HOURS') {
165 node("python") {
Jiri Broulikdc87d722017-11-03 15:43:22 +0100166
Jakub Josefa63f9862018-01-11 17:58:38 +0100167 // create connection to salt master
168 python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
Jiri Broulikdc87d722017-11-03 15:43:22 +0100169
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400170 stage('Check user choices') {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100171 if (STAGE_UPGRADE_RGW.toBoolean()) {
Alena Kiseleva639b0012019-01-22 17:09:33 +0300172 // if rgw, check if other stuff has required version
173 def mon_ok = true
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100174 if (!STAGE_UPGRADE_MON.toBoolean()) {
175 def mon_v = ceph.cmdRun(pepperEnv, "ceph mon versions")
Alena Kiseleva639b0012019-01-22 17:09:33 +0300176 mon_ok = mon_v.contains("${TARGET_RELEASE}") && !mon_v.contains("${ORIGIN_RELEASE}")
177 }
178 def mgr_ok = true
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100179 if (!STAGE_UPGRADE_MGR.toBoolean()) {
180 def mgr_v = ceph.cmdRun(pepperEnv, "ceph mgr versions")
Alena Kiseleva639b0012019-01-22 17:09:33 +0300181 mgr_ok = mgr_v.contains("${TARGET_RELEASE}") && !mgr_v.contains("${ORIGIN_RELEASE}")
182 }
183 def osd_ok = true
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100184 if (!STAGE_UPGRADE_OSD.toBoolean()) {
185 def osd_v = ceph.cmdRun(pepperEnv, "ceph osd versions")
Alena Kiseleva639b0012019-01-22 17:09:33 +0300186 osd_ok = osd_v.contains("${TARGET_RELEASE}") && !osd_v.contains("${ORIGIN_RELEASE}")
187 }
188 if (!mon_ok || !osd_ok || !mgr_ok) {
189 common.errorMsg('You may choose stages in any order, but RGW should be upgraded last')
190 throw new InterruptedException()
191 }
192 }
193 }
194
Vladimir Khlyunevfe415cc2022-08-02 13:58:43 +0400195 stage('Pre-validate cluster model settings'){
196 upgradeChecks.check_36461_2(salt, pepperEnv, "", true)
197 }
198
Jakub Josefa63f9862018-01-11 17:58:38 +0100199 if (BACKUP_ENABLED.toBoolean() == true) {
200 if (STAGE_UPGRADE_MON.toBoolean() == true) {
201 backup(pepperEnv, 'mon')
202 }
203 if (STAGE_UPGRADE_RGW.toBoolean() == true) {
204 backup(pepperEnv, 'radosgw')
205 }
206 if (STAGE_UPGRADE_OSD.toBoolean() == true) {
207 backup(pepperEnv, 'osd')
Jiri Broulikdc87d722017-11-03 15:43:22 +0100208 }
209 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100210
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100211 stage('Set cluster flags') {
212 ceph.setFlags(pepperEnv, flags)
213 if (ORIGIN_RELEASE == 'jewel') {
214 ceph.setFlags('sortbitwise')
Jiri Broulikdc87d722017-11-03 15:43:22 +0100215 }
216 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100217
Jakub Josefa63f9862018-01-11 17:58:38 +0100218 if (STAGE_UPGRADE_MON.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400219 upgrade(pepperEnv, 'mon')
Jakub Josefa63f9862018-01-11 17:58:38 +0100220 }
221
222 if (STAGE_UPGRADE_MGR.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400223 upgrade(pepperEnv, 'mgr')
Jakub Josefa63f9862018-01-11 17:58:38 +0100224 }
225
226 if (STAGE_UPGRADE_OSD.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400227 upgrade(pepperEnv, 'osd')
Jakub Josefa63f9862018-01-11 17:58:38 +0100228 }
229
230 if (STAGE_UPGRADE_RGW.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400231 upgrade(pepperEnv, 'radosgw')
Jakub Josefa63f9862018-01-11 17:58:38 +0100232 }
233
234 if (STAGE_UPGRADE_CLIENT.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400235 upgrade(pepperEnv, 'common')
Jakub Josefa63f9862018-01-11 17:58:38 +0100236 }
237
238 // remove cluster flags
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100239 stage('Unset cluster flags') {
240 ceph.unsetFlags(flags)
Jiri Broulikdc87d722017-11-03 15:43:22 +0100241 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100242
Jakub Josefa63f9862018-01-11 17:58:38 +0100243 if (STAGE_FINALIZE.toBoolean() == true) {
244 stage("Finalize ceph version upgrade") {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100245 ceph.cmdRun(pepperEnv, "ceph osd require-osd-release ${TARGET_RELEASE}")
Jakub Josefa63f9862018-01-11 17:58:38 +0100246 try {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100247 ceph.cmdRun(pepperEnv, "ceph osd set-require-min-compat-client ${ORIGIN_RELEASE}")
Jakub Josefa63f9862018-01-11 17:58:38 +0100248 } catch (Exception e) {
249 common.warningMsg(e)
250 }
251 try {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100252 ceph.cmdRun(pepperEnv, "ceph osd crush tunables optimal")
Jakub Josefa63f9862018-01-11 17:58:38 +0100253 } catch (Exception e) {
254 common.warningMsg(e)
255 }
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +0200256 if (TARGET_RELEASE == 'nautilus' ) {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100257 ceph.cmdRun(pepperEnv, "ceph mon enable-msgr2")
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +0200258 }
Tomek Jaroszykf3546562020-09-17 15:34:05 +0200259 salt.enforceState(pepperEnv, "I@ceph:common", "ceph.common")
Jakub Josefa63f9862018-01-11 17:58:38 +0100260 }
261 }
262
263 // wait for healthy cluster
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400264 if (WAIT_FOR_HEALTHY.toBoolean()) {
Tomek Jaroszyk8b8cd142022-02-18 14:46:34 +0100265 ceph.waitForHealthy(pepperEnv, flags)
Jakub Josefa63f9862018-01-11 17:58:38 +0100266 }
Vladimir Khlyunevfe415cc2022-08-02 13:58:43 +0400267 stage('Post-upgrade cluster model settings validation'){
268 def checkResult = upgradeChecks.check_36461_2(salt, pepperEnv, "", false)
269 common.warningMsg(checkResult.isFixed)
270 if ( checkResult.waInfo != '') {
271 common.warningMsg(checkResult.waInfo)
272 }
273 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100274 }
275}