blob: 39695f28427f1d8f58804a72d6e23552e943730c [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 *
9 * ADMIN_HOST Host (minion id) with admin keyring and /etc/crushmap file present
10 * CLUSTER_FLAGS Comma separated list of tags to apply to cluster
11 * WAIT_FOR_HEALTHY Wait for cluster rebalance before stoping daemons
Denis Egorenkoa5594de2021-01-11 15:24:45 +040012 * ASK_CONFIRMATION Ask for manual confirmation
Jiri Broulikdc87d722017-11-03 15:43:22 +010013 * ORIGIN_RELEASE Ceph release version before upgrade
14 * TARGET_RELEASE Ceph release version after upgrade
15 * STAGE_UPGRADE_MON Set to True if Ceph mon nodes upgrade is desired
16 * STAGE_UPGRADE_MGR Set to True if Ceph mgr nodes upgrade or new deploy is desired
17 * STAGE_UPGRADE_OSD Set to True if Ceph osd nodes upgrade is desired
18 * STAGE_UPGRADE_RGW Set to True if Ceph rgw nodes upgrade is desired
19 * 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 -040020 * STAGE_FINALIZE Set to True if configs recommended for TARGET_RELEASE should be set after upgrade is done
21 * BACKUP_ENABLED Select to copy the disks of Ceph VMs before upgrade and backup Ceph directories on OSD nodes
22 * BACKUP_DIR Select the target dir to backup to when BACKUP_ENABLED
Jiri Broulikdc87d722017-11-03 15:43:22 +010023 *
24 */
25
26common = new com.mirantis.mk.Common()
27salt = new com.mirantis.mk.Salt()
28def python = new com.mirantis.mk.Python()
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040029ceph = new com.mirantis.mk.Ceph()
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(',')
Jiri Broulikdc87d722017-11-03 15:43:22 +010034
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040035def backup(master, target) {
Jiri Broulik96c867a2017-11-07 16:14:10 +010036 stage("backup ${target}") {
37
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010038 if (target == 'osd') {
Jiri Broulik96c867a2017-11-07 16:14:10 +010039 try {
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010040 salt.enforceState(master, "I@ceph:${target}", "ceph.backup", true)
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040041 salt.cmdRun(master, "I@ceph:${target}", "su root -c '/usr/local/bin/ceph-backup-runner-call.sh'")
Jiri Broulik96c867a2017-11-07 16:14:10 +010042 } catch (Exception e) {
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010043 common.errorMsg(e)
44 common.errorMsg("Make sure Ceph backup on OSD nodes is enabled")
45 throw new InterruptedException()
Jiri Broulik96c867a2017-11-07 16:14:10 +010046 }
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010047 } else {
48 def _pillar = salt.getGrain(master, 'I@salt:master', 'domain')
49 def domain = _pillar['return'][0].values()[0].values()[0]
50
51 def kvm_pillar = salt.getGrain(master, 'I@salt:control', 'id')
52 def kvm01 = kvm_pillar['return'][0].values()[0].values()[0]
53
54 def target_pillar = salt.getGrain(master, "I@ceph:${target}", 'host')
55 def minions = target_pillar['return'][0].values()
56 for (minion in minions) {
57 def minion_name = minion.values()[0]
58 def provider_pillar = salt.getPillar(master, "${kvm01}", "salt:control:cluster:internal:node:${minion_name}:provider")
59 def minionProvider = provider_pillar['return'][0].values()[0]
60
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040061 ceph.waitForHealthy(master, ADMIN_HOST, flags)
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010062 try {
Michael Vollmanbcec46f2019-05-07 08:10:00 -040063 salt.cmdRun(master, "${minionProvider}", "[ ! -f ${BACKUP_DIR}/${minion_name}.${domain}.qcow2.bak ] && virsh destroy ${minion_name}.${domain}")
Jiri Broulikfd2dcaf2017-12-08 15:19:51 +010064 } catch (Exception e) {
65 common.warningMsg('Backup already exists')
66 }
67 try {
Michael Vollmanbcec46f2019-05-07 08:10:00 -040068 salt.cmdRun(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 +010069 } catch (Exception e) {
70 common.warningMsg('Backup already exists')
71 }
72 try {
73 salt.cmdRun(master, "${minionProvider}", "virsh start ${minion_name}.${domain}")
74 } catch (Exception e) {
75 common.warningMsg(e)
76 }
77 salt.minionsReachable(master, 'I@salt:master', "${minion_name}*")
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040078 ceph.waitForHealthy(master, ADMIN_HOST, flags)
Jiri Broulik96c867a2017-11-07 16:14:10 +010079 }
Jiri Broulik96c867a2017-11-07 16:14:10 +010080 }
81 }
82 return
83}
84
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +040085def upgrade(master, target) {
Jiri Broulikdc87d722017-11-03 15:43:22 +010086
87 stage("Change ${target} repos") {
88 salt.runSaltProcessStep(master, "I@ceph:${target}", 'saltutil.refresh_pillar', [], null, true, 5)
89 salt.enforceState(master, "I@ceph:${target}", 'linux.system.repo', true)
90 }
Jiri Broulikdc87d722017-11-03 15:43:22 +010091 if (target == 'mgr') {
92 stage('Run ceph mgr state') {
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +020093 salt.enforceState(master, "I@ceph:mgr", "ceph.mgr", true, failOnError=false, retries=3, retries_wait=10)
Jiri Broulikdc87d722017-11-03 15:43:22 +010094 }
95 }
Jiri Broulikdc87d722017-11-03 15:43:22 +010096 if (target == 'common') {
97 stage('Upgrade ceph-common pkgs') {
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +020098 salt.runSaltProcessStep(master, "I@ceph:${target}", 'pkg.install', ["ceph-common"], 'only_upgrade=True')
Jiri Broulikdc87d722017-11-03 15:43:22 +010099 }
100 } else {
Jiri Broulik96c867a2017-11-07 16:14:10 +0100101 minions = salt.getMinions(master, "I@ceph:${target}")
Jiri Broulikdc87d722017-11-03 15:43:22 +0100102
Jiri Broulik96c867a2017-11-07 16:14:10 +0100103 for (minion in minions) {
104 // upgrade pkgs
105 if (target == 'radosgw') {
106 stage('Upgrade radosgw pkgs') {
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +0200107 salt.runSaltProcessStep(master, "I@ceph:${target}", 'pkg.install', [target], 'only_upgrade=True')
Jiri Broulik96c867a2017-11-07 16:14:10 +0100108 }
109 } else {
110 stage("Upgrade ${target} pkgs on ${minion}") {
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +0200111 salt.runSaltProcessStep(master, "${minion}", 'pkg.install', ["ceph-${target}"], 'only_upgrade=True')
Jiri Broulik96c867a2017-11-07 16:14:10 +0100112 }
113 }
114 // restart services
115 stage("Restart ${target} services on ${minion}") {
Mateusz Losabf4ef52020-05-11 10:37:23 +0200116 if(target == 'osd') {
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +0200117 def ceph_disks = salt.getGrain(master, minion, 'ceph')['return'][0].values()[0].values()[0]['ceph_disk']
Mateusz Losb8575e62020-02-06 13:33:42 +0100118 ceph_disks.each { osd, param ->
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400119 salt.cmdRun(master, "${minion}", "systemctl restart ceph-${target}@${osd}")
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400120 }
Mateusz Losabf4ef52020-05-11 10:37:23 +0200121 }
122 else {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400123 salt.cmdRun(master, "${minion}", "systemctl restart ceph-${target}.target")
Mateusz Losabf4ef52020-05-11 10:37:23 +0200124 }
125
126 ceph.waitForHealthy(master, ADMIN_HOST, flags)
Jiri Broulik96c867a2017-11-07 16:14:10 +0100127 }
128
129 stage("Verify services for ${minion}") {
130 sleep(10)
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400131 salt.cmdRun(master, "${minion}", "systemctl status ceph-${target}.target")
Jiri Broulik96c867a2017-11-07 16:14:10 +0100132 }
133
Denis Egorenkoa5594de2021-01-11 15:24:45 +0400134 if (askConfirmation) {
135 stage('Ask for manual confirmation') {
136 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?"
137 }
Jiri Broulik96c867a2017-11-07 16:14:10 +0100138 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100139 }
140 }
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400141 salt.cmdRun(master, ADMIN_HOST, "ceph versions")
Jiri Broulikdc87d722017-11-03 15:43:22 +0100142 sleep(5)
143 return
144}
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400145
Jakub Josefa63f9862018-01-11 17:58:38 +0100146timeout(time: 12, unit: 'HOURS') {
147 node("python") {
Jiri Broulikdc87d722017-11-03 15:43:22 +0100148
Jakub Josefa63f9862018-01-11 17:58:38 +0100149 // create connection to salt master
150 python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
Jiri Broulikdc87d722017-11-03 15:43:22 +0100151
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400152 stage('Check user choices') {
Alena Kiseleva639b0012019-01-22 17:09:33 +0300153 if (STAGE_UPGRADE_RGW.toBoolean() == true) {
154 // if rgw, check if other stuff has required version
155 def mon_ok = true
156 if (STAGE_UPGRADE_MON.toBoolean() == false) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400157 def mon_v = salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph mon versions")['return'][0].values()[0]
Alena Kiseleva639b0012019-01-22 17:09:33 +0300158 mon_ok = mon_v.contains("${TARGET_RELEASE}") && !mon_v.contains("${ORIGIN_RELEASE}")
159 }
160 def mgr_ok = true
161 if (STAGE_UPGRADE_MGR.toBoolean() == false) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400162 def mgr_v = salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph mgr versions")['return'][0].values()[0]
Alena Kiseleva639b0012019-01-22 17:09:33 +0300163 mgr_ok = mgr_v.contains("${TARGET_RELEASE}") && !mgr_v.contains("${ORIGIN_RELEASE}")
164 }
165 def osd_ok = true
166 if (STAGE_UPGRADE_OSD.toBoolean() == false) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400167 def osd_v = salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph osd versions")['return'][0].values()[0]
Alena Kiseleva639b0012019-01-22 17:09:33 +0300168 osd_ok = osd_v.contains("${TARGET_RELEASE}") && !osd_v.contains("${ORIGIN_RELEASE}")
169 }
170 if (!mon_ok || !osd_ok || !mgr_ok) {
171 common.errorMsg('You may choose stages in any order, but RGW should be upgraded last')
172 throw new InterruptedException()
173 }
174 }
175 }
176
Jakub Josefa63f9862018-01-11 17:58:38 +0100177 if (BACKUP_ENABLED.toBoolean() == true) {
178 if (STAGE_UPGRADE_MON.toBoolean() == true) {
179 backup(pepperEnv, 'mon')
180 }
181 if (STAGE_UPGRADE_RGW.toBoolean() == true) {
182 backup(pepperEnv, 'radosgw')
183 }
184 if (STAGE_UPGRADE_OSD.toBoolean() == true) {
185 backup(pepperEnv, 'osd')
Jiri Broulikdc87d722017-11-03 15:43:22 +0100186 }
187 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100188
Jakub Josefa63f9862018-01-11 17:58:38 +0100189 if (flags.size() > 0) {
190 stage('Set cluster flags') {
191 for (flag in flags) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400192 salt.cmdRun(pepperEnv, ADMIN_HOST, 'ceph osd set ' + flag)
Jiri Broulikdc87d722017-11-03 15:43:22 +0100193 }
PGlazov24738da2020-02-12 18:07:04 +0400194 if (ORIGIN_RELEASE == 'jewel') {
195 salt.cmdRun(pepperEnv, ADMIN_HOST, 'ceph osd set sortbitwise')
196 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100197 }
198 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100199
Jakub Josefa63f9862018-01-11 17:58:38 +0100200 if (STAGE_UPGRADE_MON.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400201 upgrade(pepperEnv, 'mon')
Jakub Josefa63f9862018-01-11 17:58:38 +0100202 }
203
204 if (STAGE_UPGRADE_MGR.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400205 upgrade(pepperEnv, 'mgr')
Jakub Josefa63f9862018-01-11 17:58:38 +0100206 }
207
208 if (STAGE_UPGRADE_OSD.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400209 upgrade(pepperEnv, 'osd')
Jakub Josefa63f9862018-01-11 17:58:38 +0100210 }
211
212 if (STAGE_UPGRADE_RGW.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400213 upgrade(pepperEnv, 'radosgw')
Jakub Josefa63f9862018-01-11 17:58:38 +0100214 }
215
216 if (STAGE_UPGRADE_CLIENT.toBoolean() == true) {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400217 upgrade(pepperEnv, 'common')
Jakub Josefa63f9862018-01-11 17:58:38 +0100218 }
219
220 // remove cluster flags
221 if (flags.size() > 0) {
222 stage('Unset cluster flags') {
223 for (flag in flags) {
224 if (!flag.contains('sortbitwise')) {
225 common.infoMsg('Removing flag ' + flag)
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400226 salt.cmdRun(pepperEnv, ADMIN_HOST, 'ceph osd unset ' + flag)
Jakub Josefa63f9862018-01-11 17:58:38 +0100227 }
Jakub Josefa63f9862018-01-11 17:58:38 +0100228 }
Jiri Broulik96c867a2017-11-07 16:14:10 +0100229 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100230 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100231
Jakub Josefa63f9862018-01-11 17:58:38 +0100232 if (STAGE_FINALIZE.toBoolean() == true) {
233 stage("Finalize ceph version upgrade") {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400234 salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph osd require-osd-release ${TARGET_RELEASE}")
Jakub Josefa63f9862018-01-11 17:58:38 +0100235 try {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400236 salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph osd set-require-min-compat-client ${ORIGIN_RELEASE}")
Jakub Josefa63f9862018-01-11 17:58:38 +0100237 } catch (Exception e) {
238 common.warningMsg(e)
239 }
240 try {
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400241 salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph osd crush tunables optimal")
Jakub Josefa63f9862018-01-11 17:58:38 +0100242 } catch (Exception e) {
243 common.warningMsg(e)
244 }
Tomek Jaroszyk0cb83922020-04-07 11:20:31 +0200245 if (TARGET_RELEASE == 'nautilus' ) {
246 salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph mon enable-msgr2")
247 }
Tomek Jaroszykf3546562020-09-17 15:34:05 +0200248 salt.enforceState(pepperEnv, "I@ceph:common", "ceph.common")
Jakub Josefa63f9862018-01-11 17:58:38 +0100249 }
250 }
251
252 // wait for healthy cluster
Ivan Berezovskiy2325dcb2019-11-05 17:42:57 +0400253 if (WAIT_FOR_HEALTHY.toBoolean()) {
254 ceph.waitForHealthy(pepperEnv, ADMIN_HOST, flags)
Jakub Josefa63f9862018-01-11 17:58:38 +0100255 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100256 }
257}