1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """DRBD command generating classes"""
23
24 import logging
25 import shlex
26
27 from ganeti import constants
28 from ganeti import errors
32 """Base class for DRBD command generators.
33
34 This class defines the interface for the command generators and holds shared
35 code.
36
37 """
39 self._version = version
40
42 raise NotImplementedError
43
46
48 raise NotImplementedError
49
50 - def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol,
51 dual_pri, hmac, secret, params):
52 raise NotImplementedError
53
55 raise NotImplementedError
56
58 raise NotImplementedError
59
61 raise NotImplementedError
62
64 raise NotImplementedError
65
67 raise NotImplementedError
68
70 raise NotImplementedError
71
73 raise NotImplementedError
74
76 raise NotImplementedError
77
79 raise NotImplementedError
80
81 @staticmethod
83 """Return the path to a drbd device for a given minor.
84
85 """
86 return "/dev/drbd%d" % minor
87
90 """Generates drbdsetup commands suited for the DRBD <= 8.3 syntax.
91
92 """
93
94 _DISABLE_DISK_OPTION = "--no-disk-barrier"
95 _DISABLE_DRAIN_OPTION = "--no-disk-drain"
96 _DISABLE_FLUSH_OPTION = "--no-disk-flushes"
97 _DISABLE_META_FLUSH_OPTION = "--no-md-flushes"
98
101
103 return ["drbdsetup", self._DevPath(minor), "show"]
104
108
110 args = ["drbdsetup", self._DevPath(minor), "disk",
111 data_dev, meta_dev, "0",
112 "-e", "detach",
113 "--create-device"]
114 if size_mb:
115 args.extend(["-d", "%sm" % size_mb])
116
117 vmaj = self._version["k_major"]
118 vmin = self._version["k_minor"]
119 vrel = self._version["k_point"]
120
121 barrier_args = \
122 self._ComputeDiskBarrierArgs(vmaj, vmin, vrel,
123 params[constants.LDP_BARRIERS],
124 params[constants.LDP_NO_META_FLUSH])
125 args.extend(barrier_args)
126
127 if params[constants.LDP_DISK_CUSTOM]:
128 args.extend(shlex.split(params[constants.LDP_DISK_CUSTOM]))
129
130 return [args]
131
132 - def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol,
133 dual_pri, hmac, secret, params):
134 args = ["drbdsetup", self._DevPath(minor), "net",
135 "%s:%s:%s" % (family, lhost, lport),
136 "%s:%s:%s" % (family, rhost, rport), protocol,
137 "-A", "discard-zero-changes",
138 "-B", "consensus",
139 "--create-device",
140 ]
141 if dual_pri:
142 args.append("-m")
143 if hmac and secret:
144 args.extend(["-a", hmac, "-x", secret])
145
146 if params[constants.LDP_NET_CUSTOM]:
147 args.extend(shlex.split(params[constants.LDP_NET_CUSTOM]))
148
149 return args
150
152 args = ["drbdsetup", self._DevPath(minor), "syncer"]
153 if params[constants.LDP_DYNAMIC_RESYNC]:
154 vmin = self._version["k_minor"]
155 vrel = self._version["k_point"]
156
157
158
159 if vmin != 3 or vrel < 9:
160 msg = ("The current DRBD version (8.%d.%d) does not support the "
161 "dynamic resync speed controller" % (vmin, vrel))
162 logging.error(msg)
163 return [msg]
164
165 if params[constants.LDP_PLAN_AHEAD] == 0:
166 msg = ("A value of 0 for c-plan-ahead disables the dynamic sync speed"
167 " controller at DRBD level. If you want to disable it, please"
168 " set the dynamic-resync disk parameter to False.")
169 logging.error(msg)
170 return [msg]
171
172
173 args.extend(["--c-plan-ahead", params[constants.LDP_PLAN_AHEAD],
174 "--c-fill-target", params[constants.LDP_FILL_TARGET],
175 "--c-delay-target", params[constants.LDP_DELAY_TARGET],
176 "--c-max-rate", params[constants.LDP_MAX_RATE],
177 "--c-min-rate", params[constants.LDP_MIN_RATE],
178 ])
179
180 else:
181 args.extend(["-r", "%d" % params[constants.LDP_RESYNC_RATE]])
182
183 args.append("--create-device")
184
185 return args
186
188 return ["drbdsetup", self._DevPath(minor), "pause-sync"]
189
191 return ["drbdsetup", self._DevPath(minor), "resume-sync"]
192
194 cmd = ["drbdsetup", self._DevPath(minor), "primary"]
195
196 if force:
197 cmd.append("-o")
198
199 return cmd
200
202 return ["drbdsetup", self._DevPath(minor), "secondary"]
203
205 return ["drbdsetup", self._DevPath(minor), "detach"]
206
208 return ["drbdsetup", self._DevPath(minor), "disconnect"]
209
211 return ["drbdsetup", self._DevPath(minor), "down"]
212
214 return ["drbdsetup", self._DevPath(minor), "resize", "-s", "%dm" % size_mb]
215
216 @classmethod
219 """Compute the DRBD command line parameters for disk barriers
220
221 Returns a list of the disk barrier parameters as requested via the
222 disabled_barriers and disable_meta_flush arguments, and according to the
223 supported ones in the DRBD version vmaj.vmin.vrel
224
225 If the desired option is unsupported, raises errors.BlockDeviceError.
226
227 """
228 disabled_barriers_set = frozenset(disabled_barriers)
229 if not disabled_barriers_set in constants.DRBD_VALID_BARRIER_OPT:
230 raise errors.BlockDeviceError("%s is not a valid option set for DRBD"
231 " barriers" % disabled_barriers)
232
233 args = []
234
235
236
237 if not vmaj == 8 and vmin in (0, 2, 3):
238 raise errors.BlockDeviceError("Unsupported DRBD version: %d.%d.%d" %
239 (vmaj, vmin, vrel))
240
241 def _AppendOrRaise(option, min_version):
242 """Helper for DRBD options"""
243 if min_version is not None and vrel >= min_version:
244 args.append(option)
245 else:
246 raise errors.BlockDeviceError("Could not use the option %s as the"
247 " DRBD version %d.%d.%d does not support"
248 " it." % (option, vmaj, vmin, vrel))
249
250
251
252
253 meta_flush_supported = disk_flush_supported = {
254 0: 12,
255 2: 7,
256 3: 0,
257 }
258
259 disk_drain_supported = {
260 2: 7,
261 3: 0,
262 }
263
264 disk_barriers_supported = {
265 3: 0,
266 }
267
268
269 if disable_meta_flush:
270 _AppendOrRaise(cls._DISABLE_META_FLUSH_OPTION,
271 meta_flush_supported.get(vmin, None))
272
273
274 if constants.DRBD_B_DISK_FLUSH in disabled_barriers_set:
275 _AppendOrRaise(cls._DISABLE_FLUSH_OPTION,
276 disk_flush_supported.get(vmin, None))
277
278
279 if constants.DRBD_B_DISK_DRAIN in disabled_barriers_set:
280 _AppendOrRaise(cls._DISABLE_DRAIN_OPTION,
281 disk_drain_supported.get(vmin, None))
282
283
284 if constants.DRBD_B_DISK_BARRIERS in disabled_barriers_set:
285 _AppendOrRaise(cls._DISABLE_DISK_OPTION,
286 disk_barriers_supported.get(vmin, None))
287
288 return args
289
292 """Generates drbdsetup commands suited for the DRBD >= 8.4 syntax.
293
294 """
295
296 _DISABLE_DISK_OPTION = "--disk-barrier=no"
297 _DISABLE_DRAIN_OPTION = "--disk-drain=no"
298 _DISABLE_FLUSH_OPTION = "--disk-flushes=no"
299 _DISABLE_META_FLUSH_OPTION = "--md-flushes=no"
300
303
305 return ["drbdsetup", "show", minor]
306
310
312 cmds = []
313
314 cmds.append(["drbdsetup", "new-resource", self._GetResource(minor)])
315 cmds.append(["drbdsetup", "new-minor", self._GetResource(minor),
316 str(minor), "0"])
317
318
319 cmds.append(["drbdmeta", self._DevPath(minor),
320 "v08", meta_dev, "flex-external", "apply-al"])
321
322 attach_cmd = ["drbdsetup", "attach", minor, data_dev, meta_dev, "flexible",
323 "--on-io-error=detach"]
324 if size_mb:
325 attach_cmd.extend(["--size", "%sm" % size_mb])
326
327 barrier_args = \
328 self._ComputeDiskBarrierArgs(params[constants.LDP_BARRIERS],
329 params[constants.LDP_NO_META_FLUSH])
330 attach_cmd.extend(barrier_args)
331
332 if params[constants.LDP_DISK_CUSTOM]:
333 attach_cmd.extend(shlex.split(params[constants.LDP_DISK_CUSTOM]))
334
335 cmds.append(attach_cmd)
336
337 return cmds
338
339 - def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol,
340 dual_pri, hmac, secret, params):
341 args = ["drbdsetup", "connect", self._GetResource(minor),
342 "%s:%s:%s" % (family, lhost, lport),
343 "%s:%s:%s" % (family, rhost, rport),
344 "--protocol", protocol,
345 "--after-sb-0pri", "discard-zero-changes",
346 "--after-sb-1pri", "consensus"
347 ]
348 if dual_pri:
349 args.append("--allow-two-primaries")
350 if hmac and secret:
351 args.extend(["--cram-hmac-alg", hmac, "--shared-secret", secret])
352
353 if params[constants.LDP_NET_CUSTOM]:
354 args.extend(shlex.split(params[constants.LDP_NET_CUSTOM]))
355
356 return args
357
359 args = ["drbdsetup", "disk-options", minor]
360 if params[constants.LDP_DYNAMIC_RESYNC]:
361 if params[constants.LDP_PLAN_AHEAD] == 0:
362 msg = ("A value of 0 for c-plan-ahead disables the dynamic sync speed"
363 " controller at DRBD level. If you want to disable it, please"
364 " set the dynamic-resync disk parameter to False.")
365 logging.error(msg)
366 return [msg]
367
368
369 args.extend(["--c-plan-ahead", params[constants.LDP_PLAN_AHEAD],
370 "--c-fill-target", params[constants.LDP_FILL_TARGET],
371 "--c-delay-target", params[constants.LDP_DELAY_TARGET],
372 "--c-max-rate", params[constants.LDP_MAX_RATE],
373 "--c-min-rate", params[constants.LDP_MIN_RATE],
374 ])
375
376 else:
377 args.extend(["--resync-rate", "%d" % params[constants.LDP_RESYNC_RATE]])
378
379 return args
380
382 return ["drbdsetup", "pause-sync", minor]
383
385 return ["drbdsetup", "resume-sync", minor]
386
388 cmd = ["drbdsetup", "primary", minor]
389
390 if force:
391 cmd.append("--force")
392
393 return cmd
394
396 return ["drbdsetup", "secondary", minor]
397
399 return ["drbdsetup", "detach", minor]
400
402 return ["drbdsetup", "disconnect",
403 "%s:%s:%s" % (family, lhost, lport),
404 "%s:%s:%s" % (family, rhost, rport)]
405
408
410 return ["drbdsetup", "resize", minor, "--size", "%dm" % size_mb]
411
412 @staticmethod
414 """Return the resource name for a given minor.
415
416 Currently we don't support DRBD volumes which share a resource, so we
417 generate the resource name based on the minor the resulting volumes is
418 assigned to.
419
420 """
421 return "resource%d" % minor
422
423 @classmethod
452