blob: 5844f77cd81df7292da3d2a0498b501f23381e55 [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
12 * ORIGIN_RELEASE Ceph release version before upgrade
13 * TARGET_RELEASE Ceph release version after upgrade
14 * STAGE_UPGRADE_MON Set to True if Ceph mon nodes upgrade is desired
15 * STAGE_UPGRADE_MGR Set to True if Ceph mgr nodes upgrade or new deploy is desired
16 * STAGE_UPGRADE_OSD Set to True if Ceph osd nodes upgrade is desired
17 * STAGE_UPGRADE_RGW Set to True if Ceph rgw nodes upgrade is desired
18 * STAGE_UPGRADE_CLIENT Set to True if Ceph client nodes upgrade is desired (includes for example ctl/cmp nodes)
19 *
20 */
21
22common = new com.mirantis.mk.Common()
23salt = new com.mirantis.mk.Salt()
24def python = new com.mirantis.mk.Python()
25
26def pepperEnv = "pepperEnv"
27def flags = CLUSTER_FLAGS.tokenize(',')
28
29def runCephCommand(master, target, cmd) {
30 return salt.cmdRun(master, target, cmd)
31}
32
Jiri Broulik96c867a2017-11-07 16:14:10 +010033def waitForHealthy(master, count=0, attempts=300) {
34 // wait for healthy cluster
35 while (count<attempts) {
36 def health = runCephCommand(master, ADMIN_HOST, 'ceph health')['return'][0].values()[0]
37 if (health.contains('HEALTH_OK')) {
38 common.infoMsg('Cluster is healthy')
39 break;
40 }
41 count++
42 sleep(10)
43 }
44}
45
46def backup(master, target) {
47 stage("backup ${target}") {
48
49 def _pillar = salt.getGrain(master, 'I@salt:master', 'domain')
50 def domain = _pillar['return'][0].values()[0].values()[0]
51
52 def kvm_pillar = salt.getGrain(master, 'I@salt:control', 'id')
53 def kvm01 = kvm_pillar['return'][0].values()[0].values()[0]
54
55 def target_pillar = salt.getGrain(master, "I@ceph:${target}", 'host')
56 def minions = target_pillar['return'][0].values()
57 for (minion in minions) {
58 def minion_name = minion.values()[0]
59 def provider_pillar = salt.getPillar(master, "${kvm01}", "salt:control:cluster:internal:node:${minion_name}:provider")
60 def minionProvider = provider_pillar['return'][0].values()[0]
61
62 waitForHealthy(master)
63 try {
64 salt.cmdRun(master, "${minionProvider}", "[ ! -f /root/${minion_name}.${domain}.qcow2.bak ] && virsh destroy ${minion_name}.${domain}")
65 } catch (Exception e) {
66 common.warningMsg('Backup already exists')
67 }
68 try {
69 salt.cmdRun(master, "${minionProvider}", "[ ! -f /root/${minion_name}.${domain}.qcow2.bak ] && cp /var/lib/libvirt/images/${minion_name}.${domain}/system.qcow2 /root/${minion_name}.${domain}.qcow2.bak")
70 } catch (Exception e) {
71 common.warningMsg('Backup already exists')
72 }
73 try {
74 salt.cmdRun(master, "${minionProvider}", "virsh start ${minion_name}.${domain}")
75 } catch (Exception e) {
76 common.warningMsg(e)
77 }
78 salt.minionsReachable(master, 'I@salt:master', "${minion_name}*")
79 waitForHealthy(master)
80 }
81 }
82 return
83}
84
Jiri Broulikdc87d722017-11-03 15:43:22 +010085def upgrade(master, target) {
86
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') {
93 salt.enforceState(master, "I@ceph:mgr", "ceph.mgr", true)
94 }
95 }
Jiri Broulikdc87d722017-11-03 15:43:22 +010096 if (target == 'common') {
97 stage('Upgrade ceph-common pkgs') {
Jiri Broulik96c867a2017-11-07 16:14:10 +010098 runCephCommand(master, "I@ceph:${target}", "apt install ceph-${target} -y")
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') {
107 runCephCommand(master, "I@ceph:${target}", "apt install ${target} -y ")
108 }
109 } else {
110 stage("Upgrade ${target} pkgs on ${minion}") {
111 runCephCommand(master, "${minion}", "apt install ceph-${target} -y")
112 }
113 }
114 // restart services
115 stage("Restart ${target} services on ${minion}") {
116 runCephCommand(master, "${minion}", "systemctl restart ceph-${target}.target")
117 }
118
119 stage("Verify services for ${minion}") {
120 sleep(10)
121 runCephCommand(master, ADMIN_HOST, "ceph -s")
122 }
123
124 stage('Ask for manual confirmation') {
125 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?"
126 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100127 }
128 }
129 runCephCommand(master, ADMIN_HOST, "ceph versions")
130 sleep(5)
131 return
132}
133
134node("python") {
135
136 // create connection to salt master
137 python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
138
Jiri Broulik96c867a2017-11-07 16:14:10 +0100139 if (BACKUP_ENABLED.toBoolean() == true) {
140 if (STAGE_UPGRADE_MON.toBoolean() == true) {
141 backup(pepperEnv, 'mon')
142 }
143 if (STAGE_UPGRADE_RGW.toBoolean() == true) {
144 backup(pepperEnv, 'radosgw')
145 }
146 }
147
Jiri Broulikdc87d722017-11-03 15:43:22 +0100148 if (flags.size() > 0) {
149 stage('Set cluster flags') {
150 for (flag in flags) {
151 runCephCommand(pepperEnv, ADMIN_HOST, 'ceph osd set ' + flag)
152 }
153 }
154 }
155
156 if (STAGE_UPGRADE_MON.toBoolean() == true) {
157 upgrade(pepperEnv, 'mon')
Jiri Broulikdc87d722017-11-03 15:43:22 +0100158 }
159
160 if (STAGE_UPGRADE_MGR.toBoolean() == true) {
161 upgrade(pepperEnv, 'mgr')
Jiri Broulikdc87d722017-11-03 15:43:22 +0100162 }
163
164 if (STAGE_UPGRADE_OSD.toBoolean() == true) {
165 upgrade(pepperEnv, 'osd')
Jiri Broulikdc87d722017-11-03 15:43:22 +0100166 }
167
168 if (STAGE_UPGRADE_RGW.toBoolean() == true) {
169 upgrade(pepperEnv, 'radosgw')
Jiri Broulikdc87d722017-11-03 15:43:22 +0100170 }
171
172 if (STAGE_UPGRADE_CLIENT.toBoolean() == true) {
173 upgrade(pepperEnv, 'common')
174 }
175
176 // remove cluster flags
177 if (flags.size() > 0) {
178 stage('Unset cluster flags') {
179 for (flag in flags) {
180 if (!flag.contains('sortbitwise')) {
181 common.infoMsg('Removing flag ' + flag)
182 runCephCommand(pepperEnv, ADMIN_HOST, 'ceph osd unset ' + flag)
183 }
184
185 }
186 }
187 }
188
Jiri Broulik96c867a2017-11-07 16:14:10 +0100189 if (STAGE_FINALIZE.toBoolean() == true) {
190 stage("Finalize ceph version upgrade") {
191 runCephCommand(pepperEnv, ADMIN_HOST, "ceph osd require-osd-release ${TARGET_RELEASE}")
192 try {
193 runCephCommand(pepperEnv, ADMIN_HOST, "ceph osd set-require-min-compat-client ${ORIGIN_RELEASE}")
194 } catch (Exception e) {
195 common.warningMsg(e)
196 }
197 try {
198 runCephCommand(pepperEnv, ADMIN_HOST, "ceph osd crush tunables optimal")
199 } catch (Exception e) {
200 common.warningMsg(e)
201 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100202 }
Jiri Broulikdc87d722017-11-03 15:43:22 +0100203 }
204
205 // wait for healthy cluster
206 if (WAIT_FOR_HEALTHY.toBoolean() == true) {
Jiri Broulik96c867a2017-11-07 16:14:10 +0100207 waitForHealthy(pepperEnv)
Jiri Broulikdc87d722017-11-03 15:43:22 +0100208 }
209}