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  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, but 
 12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14  # General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 19  # 02110-1301, USA. 
 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 
29 30 31 -class BaseDRBDCmdGenerator(object):
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 """
38 - def __init__(self, version):
39 self._version = version
40
41 - def GenShowCmd(self, minor):
42 raise NotImplementedError
43
44 - def GenInitMetaCmd(self, minor, meta_dev):
45 raise NotImplementedError
46
47 - def GenLocalInitCmds(self, minor, data_dev, meta_dev, size_mb, params):
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
54 - def GenSyncParamsCmd(self, minor, params):
55 raise NotImplementedError
56
57 - def GenPauseSyncCmd(self, minor):
58 raise NotImplementedError
59
60 - def GenResumeSyncCmd(self, minor):
61 raise NotImplementedError
62
63 - def GenPrimaryCmd(self, minor, force):
64 raise NotImplementedError
65
66 - def GenSecondaryCmd(self, minor):
67 raise NotImplementedError
68
69 - def GenDetachCmd(self, minor):
70 raise NotImplementedError
71
72 - def GenDisconnectCmd(self, minor, family, lhost, lport, rhost, rport):
73 raise NotImplementedError
74
75 - def GenDownCmd(self, minor):
76 raise NotImplementedError
77
78 - def GenResizeCmd(self, minor, size_mb):
79 raise NotImplementedError
80 81 @staticmethod
82 - def _DevPath(minor):
83 """Return the path to a drbd device for a given minor. 84 85 """ 86 return "/dev/drbd%d" % minor
87
88 89 -class DRBD83CmdGenerator(BaseDRBDCmdGenerator):
90 """Generates drbdsetup commands suited for the DRBD <= 8.3 syntax. 91 92 """ 93 # command line options for barriers 94 _DISABLE_DISK_OPTION = "--no-disk-barrier" # -a 95 _DISABLE_DRAIN_OPTION = "--no-disk-drain" # -D 96 _DISABLE_FLUSH_OPTION = "--no-disk-flushes" # -i 97 _DISABLE_META_FLUSH_OPTION = "--no-md-flushes" # -m 98
99 - def __init__(self, version):
100 super(DRBD83CmdGenerator, self).__init__(version)
101
102 - def GenShowCmd(self, minor):
103 return ["drbdsetup", self._DevPath(minor), "show"]
104
105 - def GenInitMetaCmd(self, minor, meta_dev):
106 return ["drbdmeta", "--force", self._DevPath(minor), 107 "v08", meta_dev, "0", "create-md"]
108
109 - def GenLocalInitCmds(self, minor, data_dev, meta_dev, size_mb, params):
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
151 - def GenSyncParamsCmd(self, minor, params):
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 # By definition we are using 8.x, so just check the rest of the version 158 # number 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 # add the c-* parameters to args 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
187 - def GenPauseSyncCmd(self, minor):
188 return ["drbdsetup", self._DevPath(minor), "pause-sync"]
189
190 - def GenResumeSyncCmd(self, minor):
191 return ["drbdsetup", self._DevPath(minor), "resume-sync"]
192
193 - def GenPrimaryCmd(self, minor, force):
194 cmd = ["drbdsetup", self._DevPath(minor), "primary"] 195 196 if force: 197 cmd.append("-o") 198 199 return cmd
200
201 - def GenSecondaryCmd(self, minor):
202 return ["drbdsetup", self._DevPath(minor), "secondary"]
203
204 - def GenDetachCmd(self, minor):
205 return ["drbdsetup", self._DevPath(minor), "detach"]
206
207 - def GenDisconnectCmd(self, minor, family, lhost, lport, rhost, rport):
208 return ["drbdsetup", self._DevPath(minor), "disconnect"]
209
210 - def GenDownCmd(self, minor):
211 return ["drbdsetup", self._DevPath(minor), "down"]
212
213 - def GenResizeCmd(self, minor, size_mb):
214 return ["drbdsetup", self._DevPath(minor), "resize", "-s", "%dm" % size_mb]
215 216 @classmethod
217 - def _ComputeDiskBarrierArgs(cls, vmaj, vmin, vrel, disabled_barriers, 218 disable_meta_flush):
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 # The following code assumes DRBD 8.x, with x < 4 and x != 1 (DRBD 8.1.x 236 # does not exist) 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 # the minimum version for each feature is encoded via pairs of (minor 251 # version -> x) where x is version in which support for the option was 252 # introduced. 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 # meta flushes 269 if disable_meta_flush: 270 _AppendOrRaise(cls._DISABLE_META_FLUSH_OPTION, 271 meta_flush_supported.get(vmin, None)) 272 273 # disk flushes 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 # disk drain 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 # disk barriers 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
290 291 -class DRBD84CmdGenerator(BaseDRBDCmdGenerator):
292 """Generates drbdsetup commands suited for the DRBD >= 8.4 syntax. 293 294 """ 295 # command line options for barriers 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
301 - def __init__(self, version):
302 super(DRBD84CmdGenerator, self).__init__(version)
303
304 - def GenShowCmd(self, minor):
305 return ["drbdsetup", "show", minor]
306
307 - def GenInitMetaCmd(self, minor, meta_dev):
308 return ["drbdmeta", "--force", self._DevPath(minor), 309 "v08", meta_dev, "flex-external", "create-md"]
310
311 - def GenLocalInitCmds(self, minor, data_dev, meta_dev, size_mb, params):
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 # We need to apply the activity log before attaching the disk else drbdsetup 318 # will fail. 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
358 - def GenSyncParamsCmd(self, minor, params):
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 # add the c-* parameters to args 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
381 - def GenPauseSyncCmd(self, minor):
382 return ["drbdsetup", "pause-sync", minor]
383
384 - def GenResumeSyncCmd(self, minor):
385 return ["drbdsetup", "resume-sync", minor]
386
387 - def GenPrimaryCmd(self, minor, force):
388 cmd = ["drbdsetup", "primary", minor] 389 390 if force: 391 cmd.append("--force") 392 393 return cmd
394
395 - def GenSecondaryCmd(self, minor):
396 return ["drbdsetup", "secondary", minor]
397
398 - def GenDetachCmd(self, minor):
399 return ["drbdsetup", "detach", minor]
400
401 - def GenDisconnectCmd(self, minor, family, lhost, lport, rhost, rport):
402 return ["drbdsetup", "disconnect", 403 "%s:%s:%s" % (family, lhost, lport), 404 "%s:%s:%s" % (family, rhost, rport)]
405
406 - def GenDownCmd(self, minor):
407 return ["drbdsetup", "down", self._GetResource(minor)]
408
409 - def GenResizeCmd(self, minor, size_mb):
410 return ["drbdsetup", "resize", minor, "--size", "%dm" % size_mb]
411 412 @staticmethod
413 - def _GetResource(minor):
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
424 - def _ComputeDiskBarrierArgs(cls, disabled_barriers, disable_meta_flush):
425 """Compute the DRBD command line parameters for disk barriers 426 427 """ 428 disabled_barriers_set = frozenset(disabled_barriers) 429 if not disabled_barriers_set in constants.DRBD_VALID_BARRIER_OPT: 430 raise errors.BlockDeviceError("%s is not a valid option set for DRBD" 431 " barriers" % disabled_barriers) 432 433 args = [] 434 435 # meta flushes 436 if disable_meta_flush: 437 args.append(cls._DISABLE_META_FLUSH_OPTION) 438 439 # disk flushes 440 if constants.DRBD_B_DISK_FLUSH in disabled_barriers_set: 441 args.append(cls._DISABLE_FLUSH_OPTION) 442 443 # disk drain 444 if constants.DRBD_B_DISK_DRAIN in disabled_barriers_set: 445 args.append(cls._DISABLE_DRAIN_OPTION) 446 447 # disk barriers 448 if constants.DRBD_B_DISK_BARRIERS in disabled_barriers_set: 449 args.append(cls._DISABLE_DISK_OPTION) 450 451 return args
452