blob: 7c2a25be7d78baedccac52fdd8202412841bf992 [file] [log] [blame]
Jiri Broulik99887c82017-10-31 09:27:52 +01001/**
2 *
3 * Remove Ceph node from existing cluster
4 *
5 * Requred parameters:
6 * SALT_MASTER_URL URL of Salt master
7 * SALT_MASTER_CREDENTIALS Credentials to the Salt API
8 * HOST Host (minion id) to be removed
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +01009 * WAIT_FOR_HEALTHY Wait for cluster rebalance after a osd was removed
10 * CLUSTER_FLAGS Expected flags on the cluster during job run
11 * FAST_WIPE Clean only partition table insted of full wipe
12 * CLEAN_ORPHANS Clean ceph partition which are no longer part of the cluster
13 * OSD Coma separated list of OSDs to remove while keep the rest intact
Denis Egorenkofe8d7af2021-03-18 15:13:59 +040014 * OSD_NODE_IS_DOWN Remove unavailable (offline) osd node from cluster, provided in HOST parameter
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +010015 * GENERATE_CRUSHMAP Generate new crush map. Excludes OSD
Jiri Broulik99887c82017-10-31 09:27:52 +010016 *
17 */
18
Ivan Berezovskiy19c685a2019-11-05 17:42:57 +040019def common = new com.mirantis.mk.Common()
20def salt = new com.mirantis.mk.Salt()
21def ceph = new com.mirantis.mk.Ceph()
Jiri Broulik99887c82017-10-31 09:27:52 +010022def python = new com.mirantis.mk.Python()
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +010023
Jiri Broulik99887c82017-10-31 09:27:52 +010024def pepperEnv = "pepperEnv"
25
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +010026def osds = OSD.tokenize(',').toSet()
27def flags = CLUSTER_FLAGS.tokenize(',').toSet()
28def cleanOrphans = CLEAN_ORPHANS.toBoolean()
29def fullWipe = !FAST_WIPE.toBoolean()
30def safeRemove = WAIT_FOR_HEALTHY.toBoolean()
31
32def osdOnly = OSD.trim() as Boolean
33def generateCrushmap = osdOnly ? false : GENERATE_CRUSHMAP.toBoolean()
Denis Egorenkofe8d7af2021-03-18 15:13:59 +040034def osdNodeUnavailable = OSD_NODE_IS_DOWN.toBoolean()
Mateusz Los8b64b812020-05-11 10:33:58 +020035
Jakub Josefa63f9862018-01-11 17:58:38 +010036timeout(time: 12, unit: 'HOURS') {
37 node("python") {
Jiri Broulik96c867a2017-11-07 16:14:10 +010038
Jakub Josefa63f9862018-01-11 17:58:38 +010039 // create connection to salt master
40 python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
Jiri Broulik99887c82017-10-31 09:27:52 +010041
Denis Egorenko970233f2021-05-17 18:37:54 +040042 def target = salt.getMinions(pepperEnv, HOST)
43 if(target.isEmpty()) {
44 common.errorMsg("Host not found")
45 throw new InterruptedException()
46 }
47 else if(target.size() > 1) {
48 common.errorMsg("$HOST targeted more than one minion")
49 throw new InterruptedException()
50 }
51
Denis Egorenkofe8d7af2021-03-18 15:13:59 +040052 if (osdNodeUnavailable) {
53 stage('Remove unavailable OSD node') {
Denis Egorenko970233f2021-05-17 18:37:54 +040054 osdHostName = salt.stripDomainName("${target[0]}")
Denis Egorenkofe8d7af2021-03-18 15:13:59 +040055 osdTreeString = ceph.cmdRun(pepperEnv, "ceph osd tree --format json-pretty")
56 osdTree = common.parseJSON(osdTreeString)
57 osdIDs = []
58 for(osd in osdTree["nodes"]) {
59 if (osd["type"] == "host" && osd["name"] == osdHostName) {
60 osdIDs = osd["children"]
61 break
62 }
63 }
64 if (osdIDs.size() == 0) {
65 common.warningMsg("Can't find any OSDs placed on host ${HOST} (${osdHostName}). Is it correct name?")
66 currentBuild.result = "UNSTABLE"
67 } else {
68 common.infoMsg("Found next OSDs for host ${HOST} (${osdHostName}): ${osdIDs}")
69 input message: "Do you want to continue node remove?"
70 for (osdId in osdIDs) {
Denis Egorenko970233f2021-05-17 18:37:54 +040071 ceph.cmdRun(pepperEnv, "ceph osd purge ${osdId} --yes-i-really-mean-it", true, true)
Denis Egorenkofe8d7af2021-03-18 15:13:59 +040072 }
73 salt.cmdRun(pepperEnv, "I@salt:master", "salt-key -d ${HOST} --include-all -y")
Denis Egorenko970233f2021-05-17 18:37:54 +040074
75 if(safeRemove) {
76 ceph.waitForHealthy(pepperEnv, flags)
77 }
Denis Egorenkofe8d7af2021-03-18 15:13:59 +040078 }
79 }
80 return
81 }
82
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +010083 salt.fullRefresh(pepperEnv, HOST)
Jakub Josefa63f9862018-01-11 17:58:38 +010084
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +010085 stage('Set flags') {
86 ceph.setFlags(pepperEnv, flags)
Jiri Broulik99887c82017-10-31 09:27:52 +010087 }
88
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +010089 try {
Jakub Josefa63f9862018-01-11 17:58:38 +010090 stage('Remove OSDs') {
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +010091 if(salt.testTarget(pepperEnv, "$HOST and I@ceph:osd")) {
92 // get list of osd disks of the host
93 def cephGrain = ceph.getGrain(pepperEnv, HOST, 'ceph')
94 def cephDisks = cephGrain.get('ceph_disk',[:]).keySet()
95 if (cephGrain.isEmpty()) {
96 throw new Exception("Ceph salt grains cannot be found on $HOST")
97 }
98
Tomek Jaroszyk1f9a0c52021-02-17 15:25:06 +010099 // glob for OSD input or whole node is going to be removed
100 if(OSD == '*' || !osdOnly) {
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100101 osds = cephDisks
102 }
103
104 // discard all osds which aren't deployed on target HOST
105 osds = osds.intersect(cephDisks)
106
107 if(!osds.isEmpty()) {
108 common.infoMsg("The following osds will be removed: ${osds.join(', ')}")
109 }
110 if(osds != cephDisks) {
Tomek Jaroszyk4c13ce72022-02-01 15:10:40 +0100111 cephDisks.removeAll(osds)
112 common.infoMsg("The following osds will be skiped: ${cephDisks.join(', ')}")
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100113 }
114
115 ceph.removeOsd(pepperEnv, HOST, osds, flags, safeRemove, fullWipe)
116
117 if(cleanOrphans) {
118 ceph.removeOrphans(pepperEnv, HOST, fullWipe)
119 }
120 }
121 else {
122 common.infoMsg('Stage skipped.')
Jakub Josefa63f9862018-01-11 17:58:38 +0100123 }
124 }
125
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100126 stage('Remove keyring') {
127 // only non-osd nodes as keyrings for osds was removed already in previous step
128 if(salt.testTarget(pepperEnv, "$HOST and not I@ceph:osd")) {
129 ceph.deleteKeyrings(pepperEnv, HOST)
130 }
131 else {
132 common.infoMsg('Stage skipped.')
133 }
134 }
Jakub Josefa63f9862018-01-11 17:58:38 +0100135
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100136 stage('Update monmap') {
137 if(salt.testTarget(pepperEnv, "$HOST and I@ceph:mon")) {
138 def hostname = ceph.getGrain(pepperEnv, HOST, 'host')
139 ceph.cmdRun(pepperEnv, 'ceph mon getmap -o monmap.backup')
140 ceph.cmdRun(pepperEnv, "ceph mon remove $hostname")
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100141 }
142 else {
143 common.infoMsg('Stage skipped.')
144 }
145 }
Mateusz Los8b64b812020-05-11 10:33:58 +0200146
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100147 stage('Update Ceph configs/crushmap') {
148 //TODO: it won't remove removed mon from config
149 if(salt.testTarget(pepperEnv, "$HOST and I@ceph:mon")) {
150 salt.enforceState(pepperEnv, 'I@ceph:common', 'ceph.common', true)
151 }
152 else if (salt.testTarget(pepperEnv, "$HOST and I@ceph:osd") && salt.testTarget(pepperEnv, "I@ceph:setup:crush and not $HOST") && generateCrushmap) {
153 salt.enforceState(pepperEnv, 'I@ceph:setup:crush', 'ceph.setup.crush', true)
154 }
155 else {
156 common.infoMsg('Stage skipped.')
157 }
158 }
159
160 stage('Purge Ceph components') {
161 Set pkgs = ['ceph-base','ceph-common']
162 if(salt.testTarget(pepperEnv, "$HOST and I@ceph:osd")) {
163 pkgs.addAll(['ceph-osd','ceph-fuse','ceph-mds','python-cephfs','librados2','python-rados','python-rbd','python-rgw'])
164 }
165 //TODO: why removed pkgs on vm which will be remved as whole in next stage
166 if(salt.testTarget(pepperEnv, "$HOST and I@ceph:radosgw")) {
167 ceph.removeRgw(pepperEnv, HOST)
168 pkgs.addAll(['radosgw','libcephfs2','python-cephfs','python-rados','python-rbd','python-rgw'])
169 }
170 if(salt.testTarget(pepperEnv, "$HOST and I@ceph:mon")) {
171 pkgs.addAll(['ceph-mon','ceph-mgr','libcephfs2','python-cephfs','python-rbd','python-rgw'])
172 }
173
174 if(!osdOnly) {
Tomek Jaroszyk6a4bf642021-03-09 12:22:37 +0100175 salt.runSaltProcessStep(pepperEnv, HOST, 'pkg.purge', "pkgs='$pkgs'")
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100176 }
177 else {
178 common.infoMsg('Stage skipped.')
179 }
180 }
181
182 stage('Remove salt minion and destroy VM') {
183 if(!osdOnly) {
184 if(salt.testTarget(pepperEnv, "$HOST and I@ceph:osd")) {
185 ceph.removeSalt(pepperEnv, HOST)
Jakub Josefa63f9862018-01-11 17:58:38 +0100186 }
Mateusz Los8b64b812020-05-11 10:33:58 +0200187 else {
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100188 ceph.removeVm(pepperEnv, HOST)
Mateusz Los8b64b812020-05-11 10:33:58 +0200189 }
190 }
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100191 else {
192 common.infoMsg('Stage skipped.')
Mateusz Los8b64b812020-05-11 10:33:58 +0200193 }
Jiri Broulik3485b2c2017-11-28 15:06:12 +0100194 }
Jiri Broulik99887c82017-10-31 09:27:52 +0100195 }
Tomek Jaroszyk08ad67e2020-11-09 13:58:02 +0100196 finally {
197 stage('Unset cluster flags') {
198 ceph.unsetFlags(pepperEnv, flags)
Jakub Josefa63f9862018-01-11 17:58:38 +0100199 }
Jiri Broulik99887c82017-10-31 09:27:52 +0100200 }
201 }
202}