Package ganeti :: Package storage :: Module drbd_cmdgen
[hide private]
[frames] | no frames]

Source Code for Module ganeti.storage.drbd_cmdgen

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30   
 31  """DRBD command generating classes""" 
 32   
 33  import logging 
 34  import shlex 
 35   
 36  from ganeti import constants 
 37  from ganeti import errors 
38 39 40 -class BaseDRBDCmdGenerator(object):
41 """Base class for DRBD command generators. 42 43 This class defines the interface for the command generators and holds shared 44 code. 45 46 """
47 - def __init__(self, version):
48 self._version = version
49
50 - def GenShowCmd(self, minor):
51 raise NotImplementedError
52
53 - def GenInitMetaCmd(self, minor, meta_dev):
54 raise NotImplementedError
55
56 - def GenLocalInitCmds(self, minor, data_dev, meta_dev, size_mb, params):
57 raise NotImplementedError
58
59 - def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol, 60 dual_pri, hmac, secret, params):
61 raise NotImplementedError
62
63 - def GenSyncParamsCmd(self, minor, params):
64 raise NotImplementedError
65
66 - def GenPauseSyncCmd(self, minor):
67 raise NotImplementedError
68
69 - def GenResumeSyncCmd(self, minor):
70 raise NotImplementedError
71
72 - def GenPrimaryCmd(self, minor, force):
73 raise NotImplementedError
74
75 - def GenSecondaryCmd(self, minor):
76 raise NotImplementedError
77
78 - def GenDetachCmd(self, minor):
79 raise NotImplementedError
80
81 - def GenDisconnectCmd(self, minor, family, lhost, lport, rhost, rport):
82 raise NotImplementedError
83
84 - def GenDownCmd(self, minor):
85 raise NotImplementedError
86
87 - def GenResizeCmd(self, minor, size_mb):
88 raise NotImplementedError
89 90 @staticmethod
91 - def _DevPath(minor):
92 """Return the path to a drbd device for a given minor. 93 94 """ 95 return "/dev/drbd%d" % minor
96
97 98 -class DRBD83CmdGenerator(BaseDRBDCmdGenerator):
99 """Generates drbdsetup commands suited for the DRBD <= 8.3 syntax. 100 101 """ 102 # command line options for barriers 103 _DISABLE_DISK_OPTION = "--no-disk-barrier" # -a 104 _DISABLE_DRAIN_OPTION = "--no-disk-drain" # -D 105 _DISABLE_FLUSH_OPTION = "--no-disk-flushes" # -i 106 _DISABLE_META_FLUSH_OPTION = "--no-md-flushes" # -m 107
108 - def __init__(self, version):
110
111 - def GenShowCmd(self, minor):
112 return ["drbdsetup", self._DevPath(minor), "show"]
113
114 - def GenInitMetaCmd(self, minor, meta_dev):
115 return ["drbdmeta", "--force", self._DevPath(minor), 116 "v08", meta_dev, "0", "create-md"]
117
118 - def GenLocalInitCmds(self, minor, data_dev, meta_dev, size_mb, params):
119 args = ["drbdsetup", self._DevPath(minor), "disk", 120 data_dev, meta_dev, "0", 121 "-e", "detach", 122 "--create-device"] 123 if size_mb: 124 args.extend(["-d", "%sm" % size_mb]) 125 126 vmaj = self._version["k_major"] 127 vmin = self._version["k_minor"] 128 vrel = self._version["k_point"] 129 130 barrier_args = \ 131 self._ComputeDiskBarrierArgs(vmaj, vmin, vrel, 132 params[constants.LDP_BARRIERS], 133 params[constants.LDP_NO_META_FLUSH]) 134 args.extend(barrier_args) 135 136 if params[constants.LDP_DISK_CUSTOM]: 137 args.extend(shlex.split(params[constants.LDP_DISK_CUSTOM])) 138 139 return [args]
140
141 - def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol, 142 dual_pri, hmac, secret, params):
143 args = ["drbdsetup", self._DevPath(minor), "net", 144 "%s:%s:%s" % (family, lhost, lport), 145 "%s:%s:%s" % (family, rhost, rport), protocol, 146 "-A", "discard-zero-changes", 147 "-B", "consensus", 148 "--create-device", 149 ] 150 if dual_pri: 151 args.append("-m") 152 if hmac and secret: 153 args.extend(["-a", hmac, "-x", secret]) 154 155 if params[constants.LDP_NET_CUSTOM]: 156 args.extend(shlex.split(params[constants.LDP_NET_CUSTOM])) 157 158 return args
159
160 - def GenSyncParamsCmd(self, minor, params):
161 args = ["drbdsetup", self._DevPath(minor), "syncer"] 162 if params[constants.LDP_DYNAMIC_RESYNC]: 163 vmin = self._version["k_minor"] 164 vrel = self._version["k_point"] 165 166 # By definition we are using 8.x, so just check the rest of the version 167 # number 168 if vmin != 3 or vrel < 9: 169 msg = ("The current DRBD version (8.%d.%d) does not support the " 170 "dynamic resync speed controller" % (vmin, vrel)) 171 logging.error(msg) 172 return [msg] 173 174 if params[constants.LDP_PLAN_AHEAD] == 0: 175 msg = ("A value of 0 for c-plan-ahead disables the dynamic sync speed" 176 " controller at DRBD level. If you want to disable it, please" 177 " set the dynamic-resync disk parameter to False.") 178 logging.error(msg) 179 return [msg] 180 181 # add the c-* parameters to args 182 args.extend(["--c-plan-ahead", params[constants.LDP_PLAN_AHEAD], 183 "--c-fill-target", params[constants.LDP_FILL_TARGET], 184 "--c-delay-target", params[constants.LDP_DELAY_TARGET], 185 "--c-max-rate", params[constants.LDP_MAX_RATE], 186 "--c-min-rate", params[constants.LDP_MIN_RATE], 187 ]) 188 189 else: 190 args.extend(["-r", "%d" % params[constants.LDP_RESYNC_RATE]]) 191 192 args.append("--create-device") 193 194 return args
195
196 - def GenPauseSyncCmd(self, minor):
197 return ["drbdsetup", self._DevPath(minor), "pause-sync"]
198
199 - def GenResumeSyncCmd(self, minor):
200 return ["drbdsetup", self._DevPath(minor), "resume-sync"]
201
202 - def GenPrimaryCmd(self, minor, force):
203 cmd = ["drbdsetup", self._DevPath(minor), "primary"] 204 205 if force: 206 cmd.append("-o") 207 208 return cmd
209
210 - def GenSecondaryCmd(self, minor):
211 return ["drbdsetup", self._DevPath(minor), "secondary"]
212
213 - def GenDetachCmd(self, minor):
214 return ["drbdsetup", self._DevPath(minor), "detach"]
215
216 - def GenDisconnectCmd(self, minor, family, lhost, lport, rhost, rport):
217 return ["drbdsetup", self._DevPath(minor), "disconnect"]
218
219 - def GenDownCmd(self, minor):
220 return ["drbdsetup", self._DevPath(minor), "down"]
221
222 - def GenResizeCmd(self, minor, size_mb):
223 return ["drbdsetup", self._DevPath(minor), "resize", "-s", "%dm" % size_mb]
224 225 @classmethod
226 - def _ComputeDiskBarrierArgs(cls, vmaj, vmin, vrel, disabled_barriers, 227 disable_meta_flush):
228 """Compute the DRBD command line parameters for disk barriers 229 230 Returns a list of the disk barrier parameters as requested via the 231 disabled_barriers and disable_meta_flush arguments, and according to the 232 supported ones in the DRBD version vmaj.vmin.vrel 233 234 If the desired option is unsupported, raises errors.BlockDeviceError. 235 236 """ 237 disabled_barriers_set = frozenset(disabled_barriers) 238 if not disabled_barriers_set in constants.DRBD_VALID_BARRIER_OPT: 239 raise errors.BlockDeviceError("%s is not a valid option set for DRBD" 240 " barriers" % disabled_barriers) 241 242 args = [] 243 244 # The following code assumes DRBD 8.x, with x < 4 and x != 1 (DRBD 8.1.x 245 # does not exist) 246 if not vmaj == 8 and vmin in (0, 2, 3): 247 raise errors.BlockDeviceError("Unsupported DRBD version: %d.%d.%d" % 248 (vmaj, vmin, vrel)) 249 250 def _AppendOrRaise(option, min_version): 251 """Helper for DRBD options""" 252 if min_version is not None and vrel >= min_version: 253 args.append(option) 254 else: 255 raise errors.BlockDeviceError("Could not use the option %s as the" 256 " DRBD version %d.%d.%d does not support" 257 " it." % (option, vmaj, vmin, vrel))
258 259 # the minimum version for each feature is encoded via pairs of (minor 260 # version -> x) where x is version in which support for the option was 261 # introduced. 262 meta_flush_supported = disk_flush_supported = { 263 0: 12, 264 2: 7, 265 3: 0, 266 } 267 268 disk_drain_supported = { 269 2: 7, 270 3: 0, 271 } 272 273 disk_barriers_supported = { 274 3: 0, 275 } 276 277 # meta flushes 278 if disable_meta_flush: 279 _AppendOrRaise(cls._DISABLE_META_FLUSH_OPTION, 280 meta_flush_supported.get(vmin, None)) 281 282 # disk flushes 283 if constants.DRBD_B_DISK_FLUSH in disabled_barriers_set: 284 _AppendOrRaise(cls._DISABLE_FLUSH_OPTION, 285 disk_flush_supported.get(vmin, None)) 286 287 # disk drain 288 if constants.DRBD_B_DISK_DRAIN in disabled_barriers_set: 289 _AppendOrRaise(cls._DISABLE_DRAIN_OPTION, 290 disk_drain_supported.get(vmin, None)) 291 292 # disk barriers 293 if constants.DRBD_B_DISK_BARRIERS in disabled_barriers_set: 294 _AppendOrRaise(cls._DISABLE_DISK_OPTION, 295 disk_barriers_supported.get(vmin, None)) 296 297 return args
298
299 300 -class DRBD84CmdGenerator(BaseDRBDCmdGenerator):
301 """Generates drbdsetup commands suited for the DRBD >= 8.4 syntax. 302 303 """ 304 # command line options for barriers 305 _DISABLE_DISK_OPTION = "--disk-barrier=no" 306 _DISABLE_DRAIN_OPTION = "--disk-drain=no" 307 _DISABLE_FLUSH_OPTION = "--disk-flushes=no" 308 _DISABLE_META_FLUSH_OPTION = "--md-flushes=no" 309
310 - def __init__(self, version):
312
313 - def GenShowCmd(self, minor):
314 return ["drbdsetup", "show", minor]
315
316 - def GenInitMetaCmd(self, minor, meta_dev):
317 return ["drbdmeta", "--force", self._DevPath(minor), 318 "v08", meta_dev, "flex-external", "create-md"]
319
320 - def GenLocalInitCmds(self, minor, data_dev, meta_dev, size_mb, params):
321 cmds = [] 322 323 cmds.append(["drbdsetup", "new-resource", self._GetResource(minor)]) 324 cmds.append(["drbdsetup", "new-minor", self._GetResource(minor), 325 str(minor), "0"]) 326 # We need to apply the activity log before attaching the disk else drbdsetup 327 # will fail. 328 cmds.append(["drbdmeta", self._DevPath(minor), 329 "v08", meta_dev, "flex-external", "apply-al"]) 330 331 attach_cmd = ["drbdsetup", "attach", minor, data_dev, meta_dev, "flexible", 332 "--on-io-error=detach"] 333 if size_mb: 334 attach_cmd.extend(["--size", "%sm" % size_mb]) 335 336 barrier_args = \ 337 self._ComputeDiskBarrierArgs(params[constants.LDP_BARRIERS], 338 params[constants.LDP_NO_META_FLUSH]) 339 attach_cmd.extend(barrier_args) 340 341 if params[constants.LDP_DISK_CUSTOM]: 342 attach_cmd.extend(shlex.split(params[constants.LDP_DISK_CUSTOM])) 343 344 cmds.append(attach_cmd) 345 346 return cmds
347
348 - def GenNetInitCmd(self, minor, family, lhost, lport, rhost, rport, protocol, 349 dual_pri, hmac, secret, params):
350 args = ["drbdsetup", "connect", self._GetResource(minor), 351 "%s:%s:%s" % (family, lhost, lport), 352 "%s:%s:%s" % (family, rhost, rport), 353 "--protocol", protocol, 354 "--after-sb-0pri", "discard-zero-changes", 355 "--after-sb-1pri", "consensus" 356 ] 357 if dual_pri: 358 args.append("--allow-two-primaries") 359 if hmac and secret: 360 args.extend(["--cram-hmac-alg", hmac, "--shared-secret", secret]) 361 362 if params[constants.LDP_NET_CUSTOM]: 363 args.extend(shlex.split(params[constants.LDP_NET_CUSTOM])) 364 365 return args
366
367 - def GenSyncParamsCmd(self, minor, params):
368 args = ["drbdsetup", "disk-options", minor] 369 if params[constants.LDP_DYNAMIC_RESYNC]: 370 if params[constants.LDP_PLAN_AHEAD] == 0: 371 msg = ("A value of 0 for c-plan-ahead disables the dynamic sync speed" 372 " controller at DRBD level. If you want to disable it, please" 373 " set the dynamic-resync disk parameter to False.") 374 logging.error(msg) 375 return [msg] 376 377 # add the c-* parameters to args 378 args.extend(["--c-plan-ahead", params[constants.LDP_PLAN_AHEAD], 379 "--c-fill-target", params[constants.LDP_FILL_TARGET], 380 "--c-delay-target", params[constants.LDP_DELAY_TARGET], 381 "--c-max-rate", params[constants.LDP_MAX_RATE], 382 "--c-min-rate", params[constants.LDP_MIN_RATE], 383 ]) 384 385 else: 386 args.extend(["--resync-rate", "%d" % params[constants.LDP_RESYNC_RATE]]) 387 388 return args
389
390 - def GenPauseSyncCmd(self, minor):
391 return ["drbdsetup", "pause-sync", minor]
392
393 - def GenResumeSyncCmd(self, minor):
394 return ["drbdsetup", "resume-sync", minor]
395
396 - def GenPrimaryCmd(self, minor, force):
397 cmd = ["drbdsetup", "primary", minor] 398 399 if force: 400 cmd.append("--force") 401 402 return cmd
403
404 - def GenSecondaryCmd(self, minor):
405 return ["drbdsetup", "secondary", minor]
406
407 - def GenDetachCmd(self, minor):
408 return ["drbdsetup", "detach", minor]
409
410 - def GenDisconnectCmd(self, minor, family, lhost, lport, rhost, rport):
411 return ["drbdsetup", "disconnect", 412 "%s:%s:%s" % (family, lhost, lport), 413 "%s:%s:%s" % (family, rhost, rport)]
414
415 - def GenDownCmd(self, minor):
416 return ["drbdsetup", "down", self._GetResource(minor)]
417
418 - def GenResizeCmd(self, minor, size_mb):
419 return ["drbdsetup", "resize", minor, "--size", "%dm" % size_mb]
420 421 @staticmethod
422 - def _GetResource(minor):
423 """Return the resource name for a given minor. 424 425 Currently we don't support DRBD volumes which share a resource, so we 426 generate the resource name based on the minor the resulting volumes is 427 assigned to. 428 429 """ 430 return "resource%d" % minor
431 432 @classmethod
433 - def _ComputeDiskBarrierArgs(cls, disabled_barriers, disable_meta_flush):
434 """Compute the DRBD command line parameters for disk barriers 435 436 """ 437 disabled_barriers_set = frozenset(disabled_barriers) 438 if not disabled_barriers_set in constants.DRBD_VALID_BARRIER_OPT: 439 raise errors.BlockDeviceError("%s is not a valid option set for DRBD" 440 " barriers" % disabled_barriers) 441 442 args = [] 443 444 # meta flushes 445 if disable_meta_flush: 446 args.append(cls._DISABLE_META_FLUSH_OPTION) 447 448 # disk flushes 449 if constants.DRBD_B_DISK_FLUSH in disabled_barriers_set: 450 args.append(cls._DISABLE_FLUSH_OPTION) 451 452 # disk drain 453 if constants.DRBD_B_DISK_DRAIN in disabled_barriers_set: 454 args.append(cls._DISABLE_DRAIN_OPTION) 455 456 # disk barriers 457 if constants.DRBD_B_DISK_BARRIERS in disabled_barriers_set: 458 args.append(cls._DISABLE_DISK_OPTION) 459 460 return args
461