blob: 8ca8d580a51f7b3874d00ae5a0bd427048ef6199 [file] [log] [blame]
Jiri Broulikdc87d722017-11-03 15:43:22 +01001/**
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 Broulik96c867a2017-11-07 16:14:10 +010015 * 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 Broulikdc87d722017-11-03 15:43:22 +010017 *
18 */
19
20common = new com.mirantis.mk.Common()
21salt = new com.mirantis.mk.Salt()
22def python = new com.mirantis.mk.Python()
23
24MIGRATION_METHOD = "per-osd"
25// TBD: per-host
26
27def pepperEnv = "pepperEnv"
28def flags = CLUSTER_FLAGS.tokenize(',')
29def osds = OSD.tokenize(',')
30
Jiri Broulika657d562017-11-28 14:19:32 +010031def 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 Broulikdc87d722017-11-03 15:43:22 +010050def runCephCommand(master, target, cmd) {
51 return salt.cmdRun(master, target, cmd)
52}
53
Jiri Broulik96c867a2017-11-07 16:14:10 +010054def 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 Broulikdc87d722017-11-03 15:43:22 +010067node("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 Broulika657d562017-11-28 14:19:32 +0100105 if (backend.contains(ORIGIN_BACKEND.toLowerCase())) {
Jiri Broulikdc87d722017-11-03 15:43:22 +0100106
107 // wait for healthy cluster before manipulating with osds
108 if (WAIT_FOR_HEALTHY.toBoolean() == true) {
Jiri Broulik96c867a2017-11-07 16:14:10 +0100109 waitForHealthy(pepperEnv)
Jiri Broulikdc87d722017-11-03 15:43:22 +0100110 }
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 Broulikdc87d722017-11-03 15:43:22 +0100117 if (WAIT_FOR_HEALTHY.toBoolean() == true) {
Jiri Broulik96c867a2017-11-07 16:14:10 +0100118 sleep(5)
119 waitForHealthy(pepperEnv)
Jiri Broulikdc87d722017-11-03 15:43:22 +0100120 }
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 Broulika657d562017-11-28 14:19:32 +0100140 // remove journal, block_db, block_wal partition `parted /dev/sdj rm 3`
141 stage('Remove journal / block_db / block_wal partition') {
Jiri Broulikdc87d722017-11-03 15:43:22 +0100142 def partition_uuid = ""
143 def journal_partition_uuid = ""
144 def block_db_partition_uuid = ""
Jiri Broulika657d562017-11-28 14:19:32 +0100145 def block_wal_partition_uuid = ""
Jiri Broulikdc87d722017-11-03 15:43:22 +0100146 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 Broulika657d562017-11-28 14:19:32 +0100159 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 Broulikdc87d722017-11-03 15:43:22 +0100166 // 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 Broulika657d562017-11-28 14:19:32 +0100173 // if disk has journal, block_db or block_wal on different disk, then remove the partition
Jiri Broulikdc87d722017-11-03 15:43:22 +0100174 if (partition_uuid?.trim()) {
Jiri Broulika657d562017-11-28 14:19:32 +0100175 removePartition(pepperEnv, HOST, partition_uuid)
176 }
177 if (block_wal_partition_uuid?.trim()) {
178 removePartition(pepperEnv, HOST, block_wal_partition_uuid)
Jiri Broulikdc87d722017-11-03 15:43:22 +0100179 }
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 Broulik96c867a2017-11-07 16:14:10 +0100197
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 Broulikdc87d722017-11-03 15:43:22 +0100209 }
210 }
Jiri Broulik96c867a2017-11-07 16:14:10 +0100211 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 Broulikdc87d722017-11-03 15:43:22 +0100223 }
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}