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() |
| 23 | |
| 24 | MIGRATION_METHOD = "per-osd" |
| 25 | // TBD: per-host |
| 26 | |
| 27 | def pepperEnv = "pepperEnv" |
| 28 | def flags = CLUSTER_FLAGS.tokenize(',') |
| 29 | def osds = OSD.tokenize(',') |
| 30 | |
Jiri Broulik | a657d56 | 2017-11-28 14:19:32 +0100 | [diff] [blame^] | 31 | def removePartition(master, target, partition_uuid) { |
| 32 | def partition = "" |
| 33 | try { |
| 34 | // partition = /dev/sdi2 |
| 35 | partition = runCephCommand(master, target, "blkid | grep ${partition_uuid} ")['return'][0].values()[0].split("(?<=[0-9])")[0] |
| 36 | } catch (Exception e) { |
| 37 | common.warningMsg(e) |
| 38 | } |
| 39 | |
| 40 | if (partition?.trim()) { |
| 41 | // dev = /dev/sdi |
| 42 | def dev = partition.replaceAll('\\d+$', "") |
| 43 | // part_id = 2 |
| 44 | def part_id = partition.substring(partition.lastIndexOf("/")+1).replaceAll("[^0-9]", "") |
| 45 | runCephCommand(master, target, "parted ${dev} rm ${part_id}") |
| 46 | } |
| 47 | return |
| 48 | } |
| 49 | |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 50 | def runCephCommand(master, target, cmd) { |
| 51 | return salt.cmdRun(master, target, cmd) |
| 52 | } |
| 53 | |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 54 | def waitForHealthy(master, count=0, attempts=300) { |
| 55 | // wait for healthy cluster |
| 56 | while (count<attempts) { |
| 57 | def health = runCephCommand(master, ADMIN_HOST, 'ceph health')['return'][0].values()[0] |
| 58 | if (health.contains('HEALTH_OK')) { |
| 59 | common.infoMsg('Cluster is healthy') |
| 60 | break; |
| 61 | } |
| 62 | count++ |
| 63 | sleep(10) |
| 64 | } |
| 65 | } |
| 66 | |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 67 | node("python") { |
| 68 | |
| 69 | // create connection to salt master |
| 70 | python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS) |
| 71 | |
| 72 | if (MIGRATION_METHOD == 'per-osd') { |
| 73 | |
| 74 | if (flags.size() > 0) { |
| 75 | stage('Set cluster flags') { |
| 76 | for (flag in flags) { |
| 77 | runCephCommand(pepperEnv, ADMIN_HOST, 'ceph osd set ' + flag) |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | def target_hosts = salt.getMinions(pepperEnv, TARGET) |
| 83 | |
| 84 | for (HOST in target_hosts) { |
| 85 | def osd_ids = [] |
| 86 | |
| 87 | // get list of osd disks of the host |
| 88 | def ceph_disks = salt.getGrain(pepperEnv, HOST, 'ceph')['return'][0].values()[0].values()[0]['ceph_disk'] |
| 89 | |
| 90 | for (i in ceph_disks) { |
| 91 | def osd_id = i.getKey().toString() |
| 92 | if (osd_id in osds || OSD == '*') { |
| 93 | osd_ids.add('osd.' + osd_id) |
| 94 | print("Will migrate " + osd_id) |
| 95 | } else { |
| 96 | print("Skipping " + osd_id) |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | for (osd_id in osd_ids) { |
| 101 | |
| 102 | def id = osd_id.replaceAll('osd.', '') |
| 103 | def backend = runCephCommand(pepperEnv, ADMIN_HOST, "ceph osd metadata ${id} | grep osd_objectstore")['return'][0].values()[0] |
| 104 | |
Jiri Broulik | a657d56 | 2017-11-28 14:19:32 +0100 | [diff] [blame^] | 105 | if (backend.contains(ORIGIN_BACKEND.toLowerCase())) { |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 106 | |
| 107 | // wait for healthy cluster before manipulating with osds |
| 108 | if (WAIT_FOR_HEALTHY.toBoolean() == true) { |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 109 | waitForHealthy(pepperEnv) |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | // `ceph osd out <id> <id>` |
| 113 | stage('Set OSDs out') { |
| 114 | runCephCommand(pepperEnv, ADMIN_HOST, "ceph osd out ${osd_id}") |
| 115 | } |
| 116 | |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 117 | if (WAIT_FOR_HEALTHY.toBoolean() == true) { |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 118 | sleep(5) |
| 119 | waitForHealthy(pepperEnv) |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | // stop osd daemons |
| 123 | stage('Stop OSD daemons') { |
| 124 | salt.runSaltProcessStep(pepperEnv, HOST, 'service.stop', ['ceph-osd@' + osd_id.replaceAll('osd.', '')], null, true) |
| 125 | } |
| 126 | |
| 127 | // remove keyring `ceph auth del osd.3` |
| 128 | stage('Remove OSD keyrings from auth') { |
| 129 | runCephCommand(pepperEnv, ADMIN_HOST, 'ceph auth del ' + osd_id) |
| 130 | } |
| 131 | |
| 132 | // remove osd `ceph osd rm osd.3` |
| 133 | stage('Remove OSDs') { |
| 134 | runCephCommand(pepperEnv, ADMIN_HOST, 'ceph osd rm ' + osd_id) |
| 135 | } |
| 136 | |
| 137 | def mount = runCephCommand(pepperEnv, HOST, "mount | grep /var/lib/ceph/osd/ceph-${id}")['return'][0].values()[0] |
| 138 | dev = mount.split()[0].replaceAll("[0-9]","") |
| 139 | |
Jiri Broulik | a657d56 | 2017-11-28 14:19:32 +0100 | [diff] [blame^] | 140 | // remove journal, block_db, block_wal partition `parted /dev/sdj rm 3` |
| 141 | stage('Remove journal / block_db / block_wal partition') { |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 142 | def partition_uuid = "" |
| 143 | def journal_partition_uuid = "" |
| 144 | def block_db_partition_uuid = "" |
Jiri Broulik | a657d56 | 2017-11-28 14:19:32 +0100 | [diff] [blame^] | 145 | def block_wal_partition_uuid = "" |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 146 | try { |
| 147 | journal_partition_uuid = runCephCommand(pepperEnv, HOST, "ls -la /var/lib/ceph/osd/ceph-${id}/ | grep journal | grep partuuid") |
| 148 | journal_partition_uuid = journal_partition_uuid.toString().trim().split("\n")[0].substring(journal_partition_uuid.toString().trim().lastIndexOf("/")+1) |
| 149 | } catch (Exception e) { |
| 150 | common.infoMsg(e) |
| 151 | } |
| 152 | try { |
| 153 | block_db_partition_uuid = runCephCommand(pepperEnv, HOST, "ls -la /var/lib/ceph/osd/ceph-${id}/ | grep 'block.db' | grep partuuid") |
| 154 | block_db_partition_uuid = block_db_partition_uuid.toString().trim().split("\n")[0].substring(block_db_partition_uuid.toString().trim().lastIndexOf("/")+1) |
| 155 | } catch (Exception e) { |
| 156 | common.infoMsg(e) |
| 157 | } |
| 158 | |
Jiri Broulik | a657d56 | 2017-11-28 14:19:32 +0100 | [diff] [blame^] | 159 | try { |
| 160 | block_wal_partition_uuid = runCephCommand(pepperEnv, HOST, "ls -la /var/lib/ceph/osd/ceph-${id}/ | grep 'block.wal' | grep partuuid") |
| 161 | block_wal_partition_uuid = block_wal_partition_uuid.toString().trim().split("\n")[0].substring(block_wal_partition_uuid.toString().trim().lastIndexOf("/")+1) |
| 162 | } catch (Exception e) { |
| 163 | common.infoMsg(e) |
| 164 | } |
| 165 | |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 166 | // set partition_uuid = 2c76f144-f412-481e-b150-4046212ca932 |
| 167 | if (journal_partition_uuid?.trim()) { |
| 168 | partition_uuid = journal_partition_uuid |
| 169 | } else if (block_db_partition_uuid?.trim()) { |
| 170 | partition_uuid = block_db_partition_uuid |
| 171 | } |
| 172 | |
Jiri Broulik | a657d56 | 2017-11-28 14:19:32 +0100 | [diff] [blame^] | 173 | // if disk has journal, block_db or block_wal on different disk, then remove the partition |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 174 | if (partition_uuid?.trim()) { |
Jiri Broulik | a657d56 | 2017-11-28 14:19:32 +0100 | [diff] [blame^] | 175 | removePartition(pepperEnv, HOST, partition_uuid) |
| 176 | } |
| 177 | if (block_wal_partition_uuid?.trim()) { |
| 178 | removePartition(pepperEnv, HOST, block_wal_partition_uuid) |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 179 | } |
| 180 | } |
| 181 | |
| 182 | // umount `umount /dev/sdi1` |
| 183 | stage('Umount devices') { |
| 184 | runCephCommand(pepperEnv, HOST, "umount /var/lib/ceph/osd/ceph-${id}") |
| 185 | } |
| 186 | |
| 187 | // zap disks `ceph-disk zap /dev/sdi` |
| 188 | stage('Zap device') { |
| 189 | runCephCommand(pepperEnv, HOST, 'ceph-disk zap ' + dev) |
| 190 | } |
| 191 | |
| 192 | // Deploy failed Ceph OSD |
| 193 | stage('Deploy Ceph OSD') { |
| 194 | salt.runSaltProcessStep(pepperEnv, HOST, 'saltutil.refresh_pillar', [], null, true, 5) |
| 195 | salt.enforceState(pepperEnv, HOST, 'ceph.osd', true) |
| 196 | } |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 197 | |
| 198 | if (PER_OSD_CONTROL.toBoolean() == true) { |
| 199 | stage("Verify backend version for osd.${id}") { |
| 200 | sleep(5) |
| 201 | runCephCommand(pepperEnv, HOST, "ceph osd metadata ${id} | grep osd_objectstore") |
| 202 | runCephCommand(pepperEnv, HOST, "ceph -s") |
| 203 | } |
| 204 | |
| 205 | stage('Ask for manual confirmation') { |
| 206 | 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?" |
| 207 | } |
| 208 | } |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 209 | } |
| 210 | } |
Jiri Broulik | 96c867a | 2017-11-07 16:14:10 +0100 | [diff] [blame] | 211 | if (PER_OSD_HOST_CONTROL.toBoolean() == true) { |
| 212 | stage("Verify backend versions") { |
| 213 | sleep(5) |
| 214 | runCephCommand(pepperEnv, HOST, "ceph osd metadata | grep osd_objectstore -B2") |
| 215 | runCephCommand(pepperEnv, HOST, "ceph -s") |
| 216 | } |
| 217 | |
| 218 | stage('Ask for manual confirmation') { |
| 219 | 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?" |
| 220 | } |
| 221 | } |
| 222 | |
Jiri Broulik | dc87d72 | 2017-11-03 15:43:22 +0100 | [diff] [blame] | 223 | } |
| 224 | // remove cluster flags |
| 225 | if (flags.size() > 0) { |
| 226 | stage('Unset cluster flags') { |
| 227 | for (flag in flags) { |
| 228 | common.infoMsg('Removing flag ' + flag) |
| 229 | runCephCommand(pepperEnv, ADMIN_HOST, 'ceph osd unset ' + flag) |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | } |
| 234 | } |