Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 1 | /** |
| 2 | * |
| 3 | * Filestore to Bluestore or vice versa backend migration |
| 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 | * OSD OSD ids to be migrated if single OSD host is targeted (comma-separated list - 1,2,3) |
| 11 | * TARGET Hosts (minion ids) to be targeted |
| 12 | * CLUSTER_FLAGS Comma separated list of tags to apply to cluster |
| 13 | * WAIT_FOR_HEALTHY Wait for cluster rebalance before stoping daemons |
| 14 | * ORIGIN_BACKEND Ceph backend before upgrade |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 15 | * PER_OSD_CONTROL Set to true if Ceph status verification after every osd disk migration is desired |
| 16 | * PER_OSD_HOST_CONTROL Set to true if Ceph status verificaton after whole OSD host migration is desired |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 17 | * |
| 18 | */ |
| 19 | |
| 20 | common = new com.mirantis.mk.Common() |
| 21 | salt = new com.mirantis.mk.Salt() |
| 22 | def python = new com.mirantis.mk.Python() |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 23 | ceph = new com.mirantis.mk.Ceph() |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 24 | |
| 25 | MIGRATION_METHOD = "per-osd" |
| 26 | // TBD: per-host |
| 27 | |
| 28 | def pepperEnv = "pepperEnv" |
| 29 | def flags = CLUSTER_FLAGS.tokenize(',') |
| 30 | def osds = OSD.tokenize(',') |
| 31 | |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 32 | def removeJournalOrBlockPartitions(master, target, id) { |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 33 | // remove journal, block_db, block_wal partition `parted /dev/sdj rm 3` |
| 34 | stage('Remove journal / block_db / block_wal partition') { |
| 35 | def partition_uuid = "" |
| 36 | def journal_partition_uuid = "" |
| 37 | def block_db_partition_uuid = "" |
| 38 | def block_wal_partition_uuid = "" |
| 39 | try { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 40 | journal_partition_uuid = salt.cmdRun(master, target, "ls -la /var/lib/ceph/osd/ceph-${id}/ | grep journal | grep partuuid") |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 41 | journal_partition_uuid = journal_partition_uuid.toString().trim().split("\n")[0].substring(journal_partition_uuid.toString().trim().lastIndexOf("/")+1) |
| 42 | } catch (Exception e) { |
| 43 | common.infoMsg(e) |
| 44 | } |
| 45 | try { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 46 | block_db_partition_uuid = salt.cmdRun(master, target, "ls -la /var/lib/ceph/osd/ceph-${id}/ | grep 'block.db' | grep partuuid") |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 47 | block_db_partition_uuid = block_db_partition_uuid.toString().trim().split("\n")[0].substring(block_db_partition_uuid.toString().trim().lastIndexOf("/")+1) |
| 48 | } catch (Exception e) { |
| 49 | common.infoMsg(e) |
| 50 | } |
| 51 | |
| 52 | try { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 53 | block_wal_partition_uuid = salt.cmdRun(master, target, "ls -la /var/lib/ceph/osd/ceph-${id}/ | grep 'block.wal' | grep partuuid") |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 54 | block_wal_partition_uuid = block_wal_partition_uuid.toString().trim().split("\n")[0].substring(block_wal_partition_uuid.toString().trim().lastIndexOf("/")+1) |
| 55 | } catch (Exception e) { |
| 56 | common.infoMsg(e) |
| 57 | } |
| 58 | |
| 59 | // set partition_uuid = 2c76f144-f412-481e-b150-4046212ca932 |
| 60 | if (journal_partition_uuid?.trim()) { |
| 61 | partition_uuid = journal_partition_uuid |
| 62 | } else if (block_db_partition_uuid?.trim()) { |
| 63 | partition_uuid = block_db_partition_uuid |
| 64 | } |
| 65 | |
| 66 | // if disk has journal, block_db or block_wal on different disk, then remove the partition |
| 67 | if (partition_uuid?.trim()) { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 68 | ceph.removePartition(master, target, partition_uuid) |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 69 | } |
| 70 | if (block_wal_partition_uuid?.trim()) { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 71 | ceph.removePartition(master, target, block_wal_partition_uuid) |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 72 | } |
| 73 | } |
| 74 | return |
| 75 | } |
| 76 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 77 | timeout(time: 12, unit: 'HOURS') { |
| 78 | node("python") { |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 79 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 80 | // create connection to salt master |
| 81 | python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS) |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 82 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 83 | if (MIGRATION_METHOD == 'per-osd') { |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 84 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 85 | if (flags.size() > 0) { |
| 86 | stage('Set cluster flags') { |
| 87 | for (flag in flags) { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 88 | salt.cmdRun(pepperEnv, ADMIN_HOST, 'ceph osd set ' + flag) |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 89 | } |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 90 | } |
| 91 | } |
| 92 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 93 | def target_hosts = salt.getMinions(pepperEnv, TARGET) |
mjedynski | 12955c7 | 2019-12-09 15:17:58 +0100 | [diff] [blame] | 94 | def device_grain_name = salt.getPillar(pepperEnv,"I@ceph:osd","ceph:osd:lvm_enabled")['return'].first().containsValue(true) ? "ceph_volume" : "ceph_disk" |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 95 | for (tgt in target_hosts) { |
| 96 | def osd_ids = [] |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 97 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 98 | // get list of osd disks of the tgt |
| 99 | salt.runSaltProcessStep(pepperEnv, tgt, 'saltutil.sync_grains', [], null, true, 5) |
mjedynski | 12955c7 | 2019-12-09 15:17:58 +0100 | [diff] [blame] | 100 | def ceph_disks = salt.getGrain(pepperEnv, tgt, 'ceph')['return'][0].values()[0].values()[0][device_grain_name] |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 101 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 102 | for (i in ceph_disks) { |
| 103 | def osd_id = i.getKey().toString() |
| 104 | if (osd_id in osds || OSD == '*') { |
| 105 | osd_ids.add('osd.' + osd_id) |
| 106 | print("Will migrate " + osd_id) |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 107 | } else { |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 108 | print("Skipping " + osd_id) |
| 109 | } |
| 110 | } |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 111 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 112 | for (osd_id in osd_ids) { |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 113 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 114 | def id = osd_id.replaceAll('osd.', '') |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 115 | def backend = salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph osd metadata ${id} | grep osd_objectstore")['return'][0].values()[0] |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 116 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 117 | if (backend.contains(ORIGIN_BACKEND.toLowerCase())) { |
| 118 | |
| 119 | // wait for healthy cluster before manipulating with osds |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 120 | if (WAIT_FOR_HEALTHY.toBoolean()) { |
| 121 | ceph.waitForHealthy(pepperEnv, ADMIN_HOST) |
Jiri Broulik | a657d56 | 2017-11-28 14:19:32 +0100 | [diff] [blame] | 122 | } |
Jiri Broulik | eb7b82f | 2017-11-30 13:55:40 +0100 | [diff] [blame] | 123 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 124 | // `ceph osd out <id> <id>` |
| 125 | stage('Set OSDs out') { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 126 | salt.cmdRun(pepperEnv, ADMIN_HOST, "ceph osd out ${osd_id}") |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 127 | } |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 128 | |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 129 | if (WAIT_FOR_HEALTHY.toBoolean()) { |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 130 | sleep(5) |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 131 | ceph.waitForHealthy(pepperEnv, ADMIN_HOST) |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 132 | } |
| 133 | |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 134 | // stop osd daemons |
| 135 | stage('Stop OSD daemons') { |
| 136 | salt.runSaltProcessStep(pepperEnv, tgt, 'service.stop', ['ceph-osd@' + osd_id.replaceAll('osd.', '')], null, true) |
| 137 | } |
| 138 | |
| 139 | // remove keyring `ceph auth del osd.3` |
| 140 | stage('Remove OSD keyrings from auth') { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 141 | salt.cmdRun(pepperEnv, ADMIN_HOST, 'ceph auth del ' + osd_id) |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | // remove osd `ceph osd rm osd.3` |
| 145 | stage('Remove OSDs') { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 146 | salt.cmdRun(pepperEnv, ADMIN_HOST, 'ceph osd rm ' + osd_id) |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 147 | } |
| 148 | |
| 149 | def dmcrypt = "" |
| 150 | try { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 151 | dmcrypt = salt.cmdRun(pepperEnv, tgt, "ls -la /var/lib/ceph/osd/ceph-${id}/ | grep dmcrypt")['return'][0].values()[0] |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 152 | } catch (Exception e) { |
| 153 | common.warningMsg(e) |
| 154 | } |
| 155 | |
| 156 | if (dmcrypt?.trim()) { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 157 | def mount = salt.cmdRun(pepperEnv, tgt, "lsblk -rp | grep /var/lib/ceph/osd/ceph-${id} -B1")['return'][0].values()[0] |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 158 | dev = mount.split()[0].replaceAll("[0-9]","") |
| 159 | |
| 160 | // remove partition tables |
| 161 | stage('dd part tables') { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 162 | salt.cmdRun(pepperEnv, tgt, "dd if=/dev/zero of=${dev} bs=512 count=1 conv=notrunc") |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | // remove journal, block_db, block_wal partition `parted /dev/sdj rm 3` |
| 166 | removeJournalOrBlockPartitions(pepperEnv, tgt, id) |
| 167 | |
| 168 | // reboot |
| 169 | stage('reboot and wait') { |
| 170 | salt.runSaltProcessStep(pepperEnv, tgt, 'system.reboot', null, null, true, 5) |
| 171 | salt.minionsReachable(pepperEnv, 'I@salt:master', tgt) |
| 172 | sleep(10) |
| 173 | } |
| 174 | |
| 175 | // zap disks `ceph-disk zap /dev/sdi` |
| 176 | stage('Zap devices') { |
| 177 | try { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 178 | salt.cmdRun(pepperEnv, tgt, 'ceph-disk zap ' + dev) |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 179 | } catch (Exception e) { |
| 180 | common.warningMsg(e) |
| 181 | } |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 182 | salt.cmdRun(pepperEnv, tgt, 'ceph-disk zap ' + dev) |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | } else { |
| 186 | |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 187 | def mount = salt.cmdRun(pepperEnv, tgt, "mount | grep /var/lib/ceph/osd/ceph-${id}")['return'][0].values()[0] |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 188 | dev = mount.split()[0].replaceAll("[0-9]","") |
| 189 | |
| 190 | // remove journal, block_db, block_wal partition `parted /dev/sdj rm 3` |
| 191 | removeJournalOrBlockPartitions(pepperEnv, tgt, id) |
| 192 | |
| 193 | // umount `umount /dev/sdi1` |
| 194 | stage('Umount devices') { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 195 | salt.cmdRun(pepperEnv, tgt, "umount /var/lib/ceph/osd/ceph-${id}") |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 196 | } |
| 197 | |
| 198 | // zap disks `ceph-disk zap /dev/sdi` |
| 199 | stage('Zap device') { |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 200 | salt.cmdRun(pepperEnv, tgt, 'ceph-disk zap ' + dev) |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 201 | } |
| 202 | } |
| 203 | |
| 204 | // Deploy Ceph OSD |
| 205 | stage('Deploy Ceph OSD') { |
| 206 | salt.runSaltProcessStep(pepperEnv, tgt, 'saltutil.refresh_pillar', [], null, true, 5) |
| 207 | salt.enforceState(pepperEnv, tgt, 'ceph.osd', true) |
| 208 | } |
| 209 | |
| 210 | if (PER_OSD_CONTROL.toBoolean() == true) { |
| 211 | stage("Verify backend version for osd.${id}") { |
| 212 | sleep(5) |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 213 | salt.cmdRun(pepperEnv, tgt, "ceph osd metadata ${id} | grep osd_objectstore") |
| 214 | salt.cmdRun(pepperEnv, tgt, "ceph -s") |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 215 | } |
| 216 | |
| 217 | stage('Ask for manual confirmation') { |
| 218 | input message: "From the verification commands above, please check the backend version of osd.${id} and ceph status. If it is correct, Do you want to continue to migrate next osd?" |
| 219 | } |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 220 | } |
| 221 | } |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 222 | } |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 223 | if (PER_OSD_HOST_CONTROL.toBoolean() == true) { |
| 224 | stage("Verify backend versions") { |
| 225 | sleep(5) |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 226 | salt.cmdRun(pepperEnv, tgt, "ceph osd metadata | grep osd_objectstore -B2") |
| 227 | salt.cmdRun(pepperEnv, tgt, "ceph -s") |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 228 | } |
| 229 | |
| 230 | stage('Ask for manual confirmation') { |
| 231 | input message: "From the verification command above, please check the ceph status and backend version of osds on this host. If it is correct, Do you want to continue to migrate next OSD host?" |
| 232 | } |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 233 | } |
| 234 | |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 235 | } |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 236 | // remove cluster flags |
| 237 | if (flags.size() > 0) { |
| 238 | stage('Unset cluster flags') { |
| 239 | for (flag in flags) { |
| 240 | common.infoMsg('Removing flag ' + flag) |
Ivan Berezovskiy | 19c685a | 2019-11-05 17:42:57 +0400 | [diff] [blame] | 241 | salt.cmdRun(pepperEnv, ADMIN_HOST, 'ceph osd unset ' + flag) |
Jakub Josef | a63f986 | 2018-01-11 17:58:38 +0100 | [diff] [blame] | 242 | } |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 243 | } |
| 244 | } |
| 245 | } |
| 246 | } |
| 247 | } |