Package CedarBackup2 :: Module config
[hide private]
[frames] | no frames]

Source Code for Module CedarBackup2.config

   1  # -*- coding: iso-8859-1 -*- 
   2  # vim: set ft=python ts=3 sw=3 expandtab: 
   3  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
   4  # 
   5  #              C E D A R 
   6  #          S O L U T I O N S       "Software done right." 
   7  #           S O F T W A R E 
   8  # 
   9  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  10  # 
  11  # Copyright (c) 2004-2008,2010 Kenneth J. Pronovici. 
  12  # All rights reserved. 
  13  # 
  14  # This program is free software; you can redistribute it and/or 
  15  # modify it under the terms of the GNU General Public License, 
  16  # Version 2, as published by the Free Software Foundation. 
  17  # 
  18  # This program is distributed in the hope that it will be useful, 
  19  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  20  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
  21  # 
  22  # Copies of the GNU General Public License are available from 
  23  # the Free Software Foundation website, http://www.gnu.org/. 
  24  # 
  25  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  26  # 
  27  # Author   : Kenneth J. Pronovici <pronovic@ieee.org> 
  28  # Language : Python 2 (>= 2.7) 
  29  # Project  : Cedar Backup, release 2 
  30  # Purpose  : Provides configuration-related objects. 
  31  # 
  32  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
  33   
  34  ######################################################################## 
  35  # Module documentation 
  36  ######################################################################## 
  37   
  38  """ 
  39  Provides configuration-related objects. 
  40   
  41  Summary 
  42  ======= 
  43   
  44     Cedar Backup stores all of its configuration in an XML document typically 
  45     called C{cback.conf}.  The standard location for this document is in 
  46     C{/etc}, but users can specify a different location if they want to. 
  47   
  48     The C{Config} class is a Python object representation of a Cedar Backup XML 
  49     configuration file.  The representation is two-way: XML data can be used to 
  50     create a C{Config} object, and then changes to the object can be propogated 
  51     back to disk.  A C{Config} object can even be used to create a configuration 
  52     file from scratch programmatically. 
  53   
  54     The C{Config} class is intended to be the only Python-language interface to 
  55     Cedar Backup configuration on disk.  Cedar Backup will use the class as its 
  56     internal representation of configuration, and applications external to Cedar 
  57     Backup itself (such as a hypothetical third-party configuration tool written 
  58     in Python or a third party extension module) should also use the class when 
  59     they need to read and write configuration files. 
  60   
  61  Backwards Compatibility 
  62  ======================= 
  63   
  64     The configuration file format has changed between Cedar Backup 1.x and Cedar 
  65     Backup 2.x.  Any Cedar Backup 1.x configuration file is also a valid Cedar 
  66     Backup 2.x configuration file.  However, it doesn't work to go the other 
  67     direction, as the 2.x configuration files contains additional configuration 
  68     is not accepted by older versions of the software. 
  69   
  70  XML Configuration Structure 
  71  =========================== 
  72   
  73     A C{Config} object can either be created "empty", or can be created based on 
  74     XML input (either in the form of a string or read in from a file on disk). 
  75     Generally speaking, the XML input I{must} result in a C{Config} object which 
  76     passes the validations laid out below in the I{Validation} section. 
  77   
  78     An XML configuration file is composed of seven sections: 
  79   
  80        - I{reference}: specifies reference information about the file (author, revision, etc) 
  81        - I{extensions}: specifies mappings to Cedar Backup extensions (external code) 
  82        - I{options}: specifies global configuration options 
  83        - I{peers}: specifies the set of peers in a master's backup pool 
  84        - I{collect}: specifies configuration related to the collect action 
  85        - I{stage}: specifies configuration related to the stage action 
  86        - I{store}: specifies configuration related to the store action 
  87        - I{purge}: specifies configuration related to the purge action 
  88   
  89     Each section is represented by an class in this module, and then the overall 
  90     C{Config} class is a composition of the various other classes. 
  91   
  92     Any configuration section that is missing in the XML document (or has not 
  93     been filled into an "empty" document) will just be set to C{None} in the 
  94     object representation.  The same goes for individual fields within each 
  95     configuration section.  Keep in mind that the document might not be 
  96     completely valid if some sections or fields aren't filled in - but that 
  97     won't matter until validation takes place (see the I{Validation} section 
  98     below). 
  99   
 100  Unicode vs. String Data 
 101  ======================= 
 102   
 103     By default, all string data that comes out of XML documents in Python is 
 104     unicode data (i.e. C{u"whatever"}).  This is fine for many things, but when 
 105     it comes to filesystem paths, it can cause us some problems.  We really want 
 106     strings to be encoded in the filesystem encoding rather than being unicode. 
 107     So, most elements in configuration which represent filesystem paths are 
 108     coverted to plain strings using L{util.encodePath}.  The main exception is 
 109     the various C{absoluteExcludePath} and C{relativeExcludePath} lists.  These 
 110     are I{not} converted, because they are generally only used for filtering, 
 111     not for filesystem operations. 
 112   
 113  Validation 
 114  ========== 
 115   
 116     There are two main levels of validation in the C{Config} class and its 
 117     children.  The first is field-level validation.  Field-level validation 
 118     comes into play when a given field in an object is assigned to or updated. 
 119     We use Python's C{property} functionality to enforce specific validations on 
 120     field values, and in some places we even use customized list classes to 
 121     enforce validations on list members.  You should expect to catch a 
 122     C{ValueError} exception when making assignments to configuration class 
 123     fields. 
 124   
 125     The second level of validation is post-completion validation.  Certain 
 126     validations don't make sense until a document is fully "complete".  We don't 
 127     want these validations to apply all of the time, because it would make 
 128     building up a document from scratch a real pain.  For instance, we might 
 129     have to do things in the right order to keep from throwing exceptions, etc. 
 130   
 131     All of these post-completion validations are encapsulated in the 
 132     L{Config.validate} method.  This method can be called at any time by a 
 133     client, and will always be called immediately after creating a C{Config} 
 134     object from XML data and before exporting a C{Config} object to XML.  This 
 135     way, we get decent ease-of-use but we also don't accept or emit invalid 
 136     configuration files. 
 137   
 138     The L{Config.validate} implementation actually takes two passes to 
 139     completely validate a configuration document.  The first pass at validation 
 140     is to ensure that the proper sections are filled into the document.  There 
 141     are default requirements, but the caller has the opportunity to override 
 142     these defaults. 
 143   
 144     The second pass at validation ensures that any filled-in section contains 
 145     valid data.  Any section which is not set to C{None} is validated according 
 146     to the rules for that section (see below). 
 147   
 148     I{Reference Validations} 
 149   
 150     No validations. 
 151   
 152     I{Extensions Validations} 
 153   
 154     The list of actions may be either C{None} or an empty list C{[]} if desired. 
 155     Each extended action must include a name, a module and a function.  Then, an 
 156     extended action must include either an index or dependency information. 
 157     Which one is required depends on which order mode is configured. 
 158   
 159     I{Options Validations} 
 160   
 161     All fields must be filled in except the rsh command.  The rcp and rsh 
 162     commands are used as default values for all remote peers.  Remote peers can 
 163     also rely on the backup user as the default remote user name if they choose. 
 164   
 165     I{Peers Validations} 
 166   
 167     Local peers must be completely filled in, including both name and collect 
 168     directory.  Remote peers must also fill in the name and collect directory, 
 169     but can leave the remote user and rcp command unset.  In this case, the 
 170     remote user is assumed to match the backup user from the options section and 
 171     rcp command is taken directly from the options section. 
 172   
 173     I{Collect Validations} 
 174   
 175     The target directory must be filled in.  The collect mode, archive mode and 
 176     ignore file are all optional.  The list of absolute paths to exclude and 
 177     patterns to exclude may be either C{None} or an empty list C{[]} if desired. 
 178   
 179     Each collect directory entry must contain an absolute path to collect, and 
 180     then must either be able to take collect mode, archive mode and ignore file 
 181     configuration from the parent C{CollectConfig} object, or must set each 
 182     value on its own.  The list of absolute paths to exclude, relative paths to 
 183     exclude and patterns to exclude may be either C{None} or an empty list C{[]} 
 184     if desired.  Any list of absolute paths to exclude or patterns to exclude 
 185     will be combined with the same list in the C{CollectConfig} object to make 
 186     the complete list for a given directory. 
 187   
 188     I{Stage Validations} 
 189   
 190     The target directory must be filled in.  There must be at least one peer 
 191     (remote or local) between the two lists of peers.  A list with no entries 
 192     can be either C{None} or an empty list C{[]} if desired. 
 193   
 194     If a set of peers is provided, this configuration completely overrides 
 195     configuration in the peers configuration section, and the same validations 
 196     apply. 
 197   
 198     I{Store Validations} 
 199   
 200     The device type and drive speed are optional, and all other values are 
 201     required (missing booleans will be set to defaults, which is OK). 
 202   
 203     The image writer functionality in the C{writer} module is supposed to be 
 204     able to handle a device speed of C{None}.  Any caller which needs a "real" 
 205     (non-C{None}) value for the device type can use C{DEFAULT_DEVICE_TYPE}, 
 206     which is guaranteed to be sensible. 
 207   
 208     I{Purge Validations} 
 209   
 210     The list of purge directories may be either C{None} or an empty list C{[]} 
 211     if desired.  All purge directories must contain a path and a retain days 
 212     value. 
 213   
 214  @sort: ActionDependencies, ActionHook, PreActionHook, PostActionHook, 
 215         ExtendedAction, CommandOverride, CollectFile, CollectDir, PurgeDir, LocalPeer, 
 216         RemotePeer, ReferenceConfig, ExtensionsConfig, OptionsConfig, PeersConfig, 
 217         CollectConfig, StageConfig, StoreConfig, PurgeConfig, Config, 
 218         DEFAULT_DEVICE_TYPE, DEFAULT_MEDIA_TYPE, 
 219         VALID_DEVICE_TYPES, VALID_MEDIA_TYPES, 
 220         VALID_COLLECT_MODES, VALID_ARCHIVE_MODES, 
 221         VALID_ORDER_MODES 
 222   
 223  @var DEFAULT_DEVICE_TYPE: The default device type. 
 224  @var DEFAULT_MEDIA_TYPE: The default media type. 
 225  @var VALID_DEVICE_TYPES: List of valid device types. 
 226  @var VALID_MEDIA_TYPES: List of valid media types. 
 227  @var VALID_COLLECT_MODES: List of valid collect modes. 
 228  @var VALID_COMPRESS_MODES: List of valid compress modes. 
 229  @var VALID_ARCHIVE_MODES: List of valid archive modes. 
 230  @var VALID_ORDER_MODES: List of valid extension order modes. 
 231   
 232  @author: Kenneth J. Pronovici <pronovic@ieee.org> 
 233  """ 
 234   
 235  ######################################################################## 
 236  # Imported modules 
 237  ######################################################################## 
 238   
 239  # System modules 
 240  import os 
 241  import re 
 242  import logging 
 243   
 244  # Cedar Backup modules 
 245  from CedarBackup2.writers.util import validateScsiId, validateDriveSpeed 
 246  from CedarBackup2.util import UnorderedList, AbsolutePathList, ObjectTypeList, parseCommaSeparatedString 
 247  from CedarBackup2.util import RegexMatchList, RegexList, encodePath, checkUnique 
 248  from CedarBackup2.util import convertSize, UNIT_BYTES, UNIT_KBYTES, UNIT_MBYTES, UNIT_GBYTES 
 249  from CedarBackup2.xmlutil import isElement, readChildren, readFirstChild 
 250  from CedarBackup2.xmlutil import readStringList, readString, readInteger, readBoolean 
 251  from CedarBackup2.xmlutil import addContainerNode, addStringNode, addIntegerNode, addBooleanNode 
 252  from CedarBackup2.xmlutil import createInputDom, createOutputDom, serializeDom 
 253   
 254   
 255  ######################################################################## 
 256  # Module-wide constants and variables 
 257  ######################################################################## 
 258   
 259  logger = logging.getLogger("CedarBackup2.log.config") 
 260   
 261  DEFAULT_DEVICE_TYPE   = "cdwriter" 
 262  DEFAULT_MEDIA_TYPE    = "cdrw-74" 
 263   
 264  VALID_DEVICE_TYPES    = [ "cdwriter", "dvdwriter", ] 
 265  VALID_CD_MEDIA_TYPES  = [ "cdr-74", "cdrw-74", "cdr-80", "cdrw-80", ] 
 266  VALID_DVD_MEDIA_TYPES = [ "dvd+r", "dvd+rw", ] 
 267  VALID_MEDIA_TYPES     = VALID_CD_MEDIA_TYPES + VALID_DVD_MEDIA_TYPES 
 268  VALID_COLLECT_MODES   = [ "daily", "weekly", "incr", ] 
 269  VALID_ARCHIVE_MODES   = [ "tar", "targz", "tarbz2", ] 
 270  VALID_COMPRESS_MODES  = [ "none", "gzip", "bzip2", ] 
 271  VALID_ORDER_MODES     = [ "index", "dependency", ] 
 272  VALID_BLANK_MODES     = [ "daily", "weekly", ] 
 273  VALID_BYTE_UNITS      = [ UNIT_BYTES, UNIT_KBYTES, UNIT_MBYTES, UNIT_GBYTES, ] 
 274  VALID_FAILURE_MODES   = [ "none", "all", "daily", "weekly", ] 
 275   
 276  REWRITABLE_MEDIA_TYPES = [ "cdrw-74", "cdrw-80", "dvd+rw", ] 
 277   
 278  ACTION_NAME_REGEX     = r"^[a-z0-9]*$" 
279 280 281 ######################################################################## 282 # ByteQuantity class definition 283 ######################################################################## 284 285 -class ByteQuantity(object):
286 287 """ 288 Class representing a byte quantity. 289 290 A byte quantity has both a quantity and a byte-related unit. Units are 291 maintained using the constants from util.py. 292 293 The quantity is maintained internally as a string so that issues of 294 precision can be avoided. It really isn't possible to store a floating 295 point number here while being able to losslessly translate back and forth 296 between XML and object representations. (Perhaps the Python 2.4 Decimal 297 class would have been an option, but I originally wanted to stay compatible 298 with Python 2.3.) 299 300 Even though the quantity is maintained as a string, the string must be in a 301 valid floating point positive number. Technically, any floating point 302 string format supported by Python is allowble. However, it does not make 303 sense to have a negative quantity of bytes in this context. 304 305 @sort: __init__, __repr__, __str__, __cmp__, quantity, units 306 """ 307
308 - def __init__(self, quantity=None, units=None):
309 """ 310 Constructor for the C{ByteQuantity} class. 311 312 @param quantity: Quantity of bytes, as string ("1.25") 313 @param units: Unit of bytes, one of VALID_BYTE_UNITS 314 315 @raise ValueError: If one of the values is invalid. 316 """ 317 self._quantity = None 318 self._units = None 319 self.quantity = quantity 320 self.units = units
321
322 - def __repr__(self):
323 """ 324 Official string representation for class instance. 325 """ 326 return "ByteQuantity(%s, %s)" % (self.quantity, self.units)
327
328 - def __str__(self):
329 """ 330 Informal string representation for class instance. 331 """ 332 return self.__repr__()
333
334 - def __cmp__(self, other):
335 """ 336 Definition of equals operator for this class. 337 Lists within this class are "unordered" for equality comparisons. 338 @param other: Other object to compare to. 339 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 340 """ 341 if other is None: 342 return 1 343 if self.quantity != other.quantity: 344 if self.quantity < other.quantity: 345 return -1 346 else: 347 return 1 348 if self.units != other.units: 349 if self.units < other.units: 350 return -1 351 else: 352 return 1 353 return 0
354
355 - def _setQuantity(self, value):
356 """ 357 Property target used to set the quantity 358 The value must be a non-empty string if it is not C{None}. 359 @raise ValueError: If the value is an empty string. 360 @raise ValueError: If the value is not a valid floating point number 361 @raise ValueError: If the value is less than zero 362 """ 363 if value is not None: 364 if len(value) < 1: 365 raise ValueError("Quantity must be a non-empty string.") 366 floatValue = float(value) 367 if floatValue < 0.0: 368 raise ValueError("Quantity cannot be negative.") 369 self._quantity = value # keep around string
370
371 - def _getQuantity(self):
372 """ 373 Property target used to get the quantity. 374 """ 375 return self._quantity
376
377 - def _setUnits(self, value):
378 """ 379 Property target used to set the units value. 380 If not C{None}, the units value must be one of the values in L{VALID_BYTE_UNITS}. 381 @raise ValueError: If the value is not valid. 382 """ 383 if value is not None: 384 if value not in VALID_BYTE_UNITS: 385 raise ValueError("Units value must be one of %s." % VALID_BYTE_UNITS) 386 self._units = value
387
388 - def _getUnits(self):
389 """ 390 Property target used to get the units value. 391 """ 392 return self._units
393
394 - def _getBytes(self):
395 """ 396 Property target used to return the byte quantity as a floating point number. 397 If there is no quantity set, then a value of 0.0 is returned. 398 """ 399 if self.quantity is not None and self.units is not None: 400 return convertSize(self.quantity, self.units, UNIT_BYTES) 401 return 0.0
402 403 quantity = property(_getQuantity, _setQuantity, None, doc="Byte quantity, as a string") 404 units = property(_getUnits, _setUnits, None, doc="Units for byte quantity, for instance UNIT_BYTES") 405 bytes = property(_getBytes, None, None, doc="Byte quantity, as a floating point number.")
406
407 408 ######################################################################## 409 # ActionDependencies class definition 410 ######################################################################## 411 412 -class ActionDependencies(object):
413 414 """ 415 Class representing dependencies associated with an extended action. 416 417 Execution ordering for extended actions is done in one of two ways: either by using 418 index values (lower index gets run first) or by having the extended action specify 419 dependencies in terms of other named actions. This class encapsulates the dependency 420 information for an extended action. 421 422 The following restrictions exist on data in this class: 423 424 - Any action name must be a non-empty string matching C{ACTION_NAME_REGEX} 425 426 @sort: __init__, __repr__, __str__, __cmp__, beforeList, afterList 427 """ 428
429 - def __init__(self, beforeList=None, afterList=None):
430 """ 431 Constructor for the C{ActionDependencies} class. 432 433 @param beforeList: List of named actions that this action must be run before 434 @param afterList: List of named actions that this action must be run after 435 436 @raise ValueError: If one of the values is invalid. 437 """ 438 self._beforeList = None 439 self._afterList = None 440 self.beforeList = beforeList 441 self.afterList = afterList
442
443 - def __repr__(self):
444 """ 445 Official string representation for class instance. 446 """ 447 return "ActionDependencies(%s, %s)" % (self.beforeList, self.afterList)
448
449 - def __str__(self):
450 """ 451 Informal string representation for class instance. 452 """ 453 return self.__repr__()
454
455 - def __cmp__(self, other):
456 """ 457 Definition of equals operator for this class. 458 @param other: Other object to compare to. 459 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 460 """ 461 if other is None: 462 return 1 463 if self.beforeList != other.beforeList: 464 if self.beforeList < other.beforeList: 465 return -1 466 else: 467 return 1 468 if self.afterList != other.afterList: 469 if self.afterList < other.afterList: 470 return -1 471 else: 472 return 1 473 return 0
474
475 - def _setBeforeList(self, value):
476 """ 477 Property target used to set the "run before" list. 478 Either the value must be C{None} or each element must be a string matching ACTION_NAME_REGEX. 479 @raise ValueError: If the value does not match the regular expression. 480 """ 481 if value is None: 482 self._beforeList = None 483 else: 484 try: 485 saved = self._beforeList 486 self._beforeList = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name") 487 self._beforeList.extend(value) 488 except Exception, e: 489 self._beforeList = saved 490 raise e
491
492 - def _getBeforeList(self):
493 """ 494 Property target used to get the "run before" list. 495 """ 496 return self._beforeList
497
498 - def _setAfterList(self, value):
499 """ 500 Property target used to set the "run after" list. 501 Either the value must be C{None} or each element must be a string matching ACTION_NAME_REGEX. 502 @raise ValueError: If the value does not match the regular expression. 503 """ 504 if value is None: 505 self._afterList = None 506 else: 507 try: 508 saved = self._afterList 509 self._afterList = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name") 510 self._afterList.extend(value) 511 except Exception, e: 512 self._afterList = saved 513 raise e
514
515 - def _getAfterList(self):
516 """ 517 Property target used to get the "run after" list. 518 """ 519 return self._afterList
520 521 beforeList = property(_getBeforeList, _setBeforeList, None, "List of named actions that this action must be run before.") 522 afterList = property(_getAfterList, _setAfterList, None, "List of named actions that this action must be run after.")
523
524 525 ######################################################################## 526 # ActionHook class definition 527 ######################################################################## 528 529 -class ActionHook(object):
530 531 """ 532 Class representing a hook associated with an action. 533 534 A hook associated with an action is a shell command to be executed either 535 before or after a named action is executed. 536 537 The following restrictions exist on data in this class: 538 539 - The action name must be a non-empty string matching C{ACTION_NAME_REGEX} 540 - The shell command must be a non-empty string. 541 542 The internal C{before} and C{after} instance variables are always set to 543 False in this parent class. 544 545 @sort: __init__, __repr__, __str__, __cmp__, action, command, before, after 546 """ 547
548 - def __init__(self, action=None, command=None):
549 """ 550 Constructor for the C{ActionHook} class. 551 552 @param action: Action this hook is associated with 553 @param command: Shell command to execute 554 555 @raise ValueError: If one of the values is invalid. 556 """ 557 self._action = None 558 self._command = None 559 self._before = False 560 self._after = False 561 self.action = action 562 self.command = command
563
564 - def __repr__(self):
565 """ 566 Official string representation for class instance. 567 """ 568 return "ActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
569
570 - def __str__(self):
571 """ 572 Informal string representation for class instance. 573 """ 574 return self.__repr__()
575
576 - def __cmp__(self, other):
577 """ 578 Definition of equals operator for this class. 579 @param other: Other object to compare to. 580 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 581 """ 582 if other is None: 583 return 1 584 if self.action != other.action: 585 if self.action < other.action: 586 return -1 587 else: 588 return 1 589 if self.command != other.command: 590 if self.command < other.command: 591 return -1 592 else: 593 return 1 594 if self.before != other.before: 595 if self.before < other.before: 596 return -1 597 else: 598 return 1 599 if self.after != other.after: 600 if self.after < other.after: 601 return -1 602 else: 603 return 1 604 return 0
605
606 - def _setAction(self, value):
607 """ 608 Property target used to set the action name. 609 The value must be a non-empty string if it is not C{None}. 610 It must also consist only of lower-case letters and digits. 611 @raise ValueError: If the value is an empty string. 612 """ 613 pattern = re.compile(ACTION_NAME_REGEX) 614 if value is not None: 615 if len(value) < 1: 616 raise ValueError("The action name must be a non-empty string.") 617 if not pattern.search(value): 618 raise ValueError("The action name must consist of only lower-case letters and digits.") 619 self._action = value
620
621 - def _getAction(self):
622 """ 623 Property target used to get the action name. 624 """ 625 return self._action
626
627 - def _setCommand(self, value):
628 """ 629 Property target used to set the command. 630 The value must be a non-empty string if it is not C{None}. 631 @raise ValueError: If the value is an empty string. 632 """ 633 if value is not None: 634 if len(value) < 1: 635 raise ValueError("The command must be a non-empty string.") 636 self._command = value
637
638 - def _getCommand(self):
639 """ 640 Property target used to get the command. 641 """ 642 return self._command
643
644 - def _getBefore(self):
645 """ 646 Property target used to get the before flag. 647 """ 648 return self._before
649
650 - def _getAfter(self):
651 """ 652 Property target used to get the after flag. 653 """ 654 return self._after
655 656 action = property(_getAction, _setAction, None, "Action this hook is associated with.") 657 command = property(_getCommand, _setCommand, None, "Shell command to execute.") 658 before = property(_getBefore, None, None, "Indicates whether command should be executed before action.") 659 after = property(_getAfter, None, None, "Indicates whether command should be executed after action.")
660
661 -class PreActionHook(ActionHook):
662 663 """ 664 Class representing a pre-action hook associated with an action. 665 666 A hook associated with an action is a shell command to be executed either 667 before or after a named action is executed. In this case, a pre-action hook 668 is executed before the named action. 669 670 The following restrictions exist on data in this class: 671 672 - The action name must be a non-empty string consisting of lower-case letters and digits. 673 - The shell command must be a non-empty string. 674 675 The internal C{before} instance variable is always set to True in this 676 class. 677 678 @sort: __init__, __repr__, __str__, __cmp__, action, command, before, after 679 """ 680
681 - def __init__(self, action=None, command=None):
682 """ 683 Constructor for the C{PreActionHook} class. 684 685 @param action: Action this hook is associated with 686 @param command: Shell command to execute 687 688 @raise ValueError: If one of the values is invalid. 689 """ 690 ActionHook.__init__(self, action, command) 691 self._before = True
692
693 - def __repr__(self):
694 """ 695 Official string representation for class instance. 696 """ 697 return "PreActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
698
699 -class PostActionHook(ActionHook):
700 701 """ 702 Class representing a pre-action hook associated with an action. 703 704 A hook associated with an action is a shell command to be executed either 705 before or after a named action is executed. In this case, a post-action hook 706 is executed after the named action. 707 708 The following restrictions exist on data in this class: 709 710 - The action name must be a non-empty string consisting of lower-case letters and digits. 711 - The shell command must be a non-empty string. 712 713 The internal C{before} instance variable is always set to True in this 714 class. 715 716 @sort: __init__, __repr__, __str__, __cmp__, action, command, before, after 717 """ 718
719 - def __init__(self, action=None, command=None):
720 """ 721 Constructor for the C{PostActionHook} class. 722 723 @param action: Action this hook is associated with 724 @param command: Shell command to execute 725 726 @raise ValueError: If one of the values is invalid. 727 """ 728 ActionHook.__init__(self, action, command) 729 self._after = True
730
731 - def __repr__(self):
732 """ 733 Official string representation for class instance. 734 """ 735 return "PostActionHook(%s, %s, %s, %s)" % (self.action, self.command, self.before, self.after)
736
737 738 ######################################################################## 739 # BlankBehavior class definition 740 ######################################################################## 741 742 -class BlankBehavior(object):
743 744 """ 745 Class representing optimized store-action media blanking behavior. 746 747 The following restrictions exist on data in this class: 748 749 - The blanking mode must be a one of the values in L{VALID_BLANK_MODES} 750 - The blanking factor must be a positive floating point number 751 752 @sort: __init__, __repr__, __str__, __cmp__, blankMode, blankFactor 753 """ 754
755 - def __init__(self, blankMode=None, blankFactor=None):
756 """ 757 Constructor for the C{BlankBehavior} class. 758 759 @param blankMode: Blanking mode 760 @param blankFactor: Blanking factor 761 762 @raise ValueError: If one of the values is invalid. 763 """ 764 self._blankMode = None 765 self._blankFactor = None 766 self.blankMode = blankMode 767 self.blankFactor = blankFactor
768
769 - def __repr__(self):
770 """ 771 Official string representation for class instance. 772 """ 773 return "BlankBehavior(%s, %s)" % (self.blankMode, self.blankFactor)
774
775 - def __str__(self):
776 """ 777 Informal string representation for class instance. 778 """ 779 return self.__repr__()
780
781 - def __cmp__(self, other):
782 """ 783 Definition of equals operator for this class. 784 @param other: Other object to compare to. 785 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 786 """ 787 if other is None: 788 return 1 789 if self.blankMode != other.blankMode: 790 if self.blankMode < other.blankMode: 791 return -1 792 else: 793 return 1 794 if self.blankFactor != other.blankFactor: 795 if self.blankFactor < other.blankFactor: 796 return -1 797 else: 798 return 1 799 return 0
800
801 - def _setBlankMode(self, value):
802 """ 803 Property target used to set the blanking mode. 804 The value must be one of L{VALID_BLANK_MODES}. 805 @raise ValueError: If the value is not valid. 806 """ 807 if value is not None: 808 if value not in VALID_BLANK_MODES: 809 raise ValueError("Blanking mode must be one of %s." % VALID_BLANK_MODES) 810 self._blankMode = value
811
812 - def _getBlankMode(self):
813 """ 814 Property target used to get the blanking mode. 815 """ 816 return self._blankMode
817
818 - def _setBlankFactor(self, value):
819 """ 820 Property target used to set the blanking factor. 821 The value must be a non-empty string if it is not C{None}. 822 @raise ValueError: If the value is an empty string. 823 @raise ValueError: If the value is not a valid floating point number 824 @raise ValueError: If the value is less than zero 825 """ 826 if value is not None: 827 if len(value) < 1: 828 raise ValueError("Blanking factor must be a non-empty string.") 829 floatValue = float(value) 830 if floatValue < 0.0: 831 raise ValueError("Blanking factor cannot be negative.") 832 self._blankFactor = value # keep around string
833
834 - def _getBlankFactor(self):
835 """ 836 Property target used to get the blanking factor. 837 """ 838 return self._blankFactor
839 840 blankMode = property(_getBlankMode, _setBlankMode, None, "Blanking mode") 841 blankFactor = property(_getBlankFactor, _setBlankFactor, None, "Blanking factor")
842
843 844 ######################################################################## 845 # ExtendedAction class definition 846 ######################################################################## 847 848 -class ExtendedAction(object):
849 850 """ 851 Class representing an extended action. 852 853 Essentially, an extended action needs to allow the following to happen:: 854 855 exec("from %s import %s" % (module, function)) 856 exec("%s(action, configPath")" % function) 857 858 The following restrictions exist on data in this class: 859 860 - The action name must be a non-empty string consisting of lower-case letters and digits. 861 - The module must be a non-empty string and a valid Python identifier. 862 - The function must be an on-empty string and a valid Python identifier. 863 - If set, the index must be a positive integer. 864 - If set, the dependencies attribute must be an C{ActionDependencies} object. 865 866 @sort: __init__, __repr__, __str__, __cmp__, name, module, function, index, dependencies 867 """ 868
869 - def __init__(self, name=None, module=None, function=None, index=None, dependencies=None):
870 """ 871 Constructor for the C{ExtendedAction} class. 872 873 @param name: Name of the extended action 874 @param module: Name of the module containing the extended action function 875 @param function: Name of the extended action function 876 @param index: Index of action, used for execution ordering 877 @param dependencies: Dependencies for action, used for execution ordering 878 879 @raise ValueError: If one of the values is invalid. 880 """ 881 self._name = None 882 self._module = None 883 self._function = None 884 self._index = None 885 self._dependencies = None 886 self.name = name 887 self.module = module 888 self.function = function 889 self.index = index 890 self.dependencies = dependencies
891
892 - def __repr__(self):
893 """ 894 Official string representation for class instance. 895 """ 896 return "ExtendedAction(%s, %s, %s, %s, %s)" % (self.name, self.module, self.function, self.index, self.dependencies)
897
898 - def __str__(self):
899 """ 900 Informal string representation for class instance. 901 """ 902 return self.__repr__()
903
904 - def __cmp__(self, other):
905 """ 906 Definition of equals operator for this class. 907 @param other: Other object to compare to. 908 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 909 """ 910 if other is None: 911 return 1 912 if self.name != other.name: 913 if self.name < other.name: 914 return -1 915 else: 916 return 1 917 if self.module != other.module: 918 if self.module < other.module: 919 return -1 920 else: 921 return 1 922 if self.function != other.function: 923 if self.function < other.function: 924 return -1 925 else: 926 return 1 927 if self.index != other.index: 928 if self.index < other.index: 929 return -1 930 else: 931 return 1 932 if self.dependencies != other.dependencies: 933 if self.dependencies < other.dependencies: 934 return -1 935 else: 936 return 1 937 return 0
938
939 - def _setName(self, value):
940 """ 941 Property target used to set the action name. 942 The value must be a non-empty string if it is not C{None}. 943 It must also consist only of lower-case letters and digits. 944 @raise ValueError: If the value is an empty string. 945 """ 946 pattern = re.compile(ACTION_NAME_REGEX) 947 if value is not None: 948 if len(value) < 1: 949 raise ValueError("The action name must be a non-empty string.") 950 if not pattern.search(value): 951 raise ValueError("The action name must consist of only lower-case letters and digits.") 952 self._name = value
953
954 - def _getName(self):
955 """ 956 Property target used to get the action name. 957 """ 958 return self._name
959
960 - def _setModule(self, value):
961 """ 962 Property target used to set the module name. 963 The value must be a non-empty string if it is not C{None}. 964 It must also be a valid Python identifier. 965 @raise ValueError: If the value is an empty string. 966 """ 967 pattern = re.compile(r"^([A-Za-z_][A-Za-z0-9_]*)(\.[A-Za-z_][A-Za-z0-9_]*)*$") 968 if value is not None: 969 if len(value) < 1: 970 raise ValueError("The module name must be a non-empty string.") 971 if not pattern.search(value): 972 raise ValueError("The module name must be a valid Python identifier.") 973 self._module = value
974
975 - def _getModule(self):
976 """ 977 Property target used to get the module name. 978 """ 979 return self._module
980
981 - def _setFunction(self, value):
982 """ 983 Property target used to set the function name. 984 The value must be a non-empty string if it is not C{None}. 985 It must also be a valid Python identifier. 986 @raise ValueError: If the value is an empty string. 987 """ 988 pattern = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$") 989 if value is not None: 990 if len(value) < 1: 991 raise ValueError("The function name must be a non-empty string.") 992 if not pattern.search(value): 993 raise ValueError("The function name must be a valid Python identifier.") 994 self._function = value
995
996 - def _getFunction(self):
997 """ 998 Property target used to get the function name. 999 """ 1000 return self._function
1001
1002 - def _setIndex(self, value):
1003 """ 1004 Property target used to set the action index. 1005 The value must be an integer >= 0. 1006 @raise ValueError: If the value is not valid. 1007 """ 1008 if value is None: 1009 self._index = None 1010 else: 1011 try: 1012 value = int(value) 1013 except TypeError: 1014 raise ValueError("Action index value must be an integer >= 0.") 1015 if value < 0: 1016 raise ValueError("Action index value must be an integer >= 0.") 1017 self._index = value
1018
1019 - def _getIndex(self):
1020 """ 1021 Property target used to get the action index. 1022 """ 1023 return self._index
1024
1025 - def _setDependencies(self, value):
1026 """ 1027 Property target used to set the action dependencies information. 1028 If not C{None}, the value must be a C{ActionDependecies} object. 1029 @raise ValueError: If the value is not a C{ActionDependencies} object. 1030 """ 1031 if value is None: 1032 self._dependencies = None 1033 else: 1034 if not isinstance(value, ActionDependencies): 1035 raise ValueError("Value must be a C{ActionDependencies} object.") 1036 self._dependencies = value
1037
1038 - def _getDependencies(self):
1039 """ 1040 Property target used to get action dependencies information. 1041 """ 1042 return self._dependencies
1043 1044 name = property(_getName, _setName, None, "Name of the extended action.") 1045 module = property(_getModule, _setModule, None, "Name of the module containing the extended action function.") 1046 function = property(_getFunction, _setFunction, None, "Name of the extended action function.") 1047 index = property(_getIndex, _setIndex, None, "Index of action, used for execution ordering.") 1048 dependencies = property(_getDependencies, _setDependencies, None, "Dependencies for action, used for execution ordering.")
1049
1050 1051 ######################################################################## 1052 # CommandOverride class definition 1053 ######################################################################## 1054 1055 -class CommandOverride(object):
1056 1057 """ 1058 Class representing a piece of Cedar Backup command override configuration. 1059 1060 The following restrictions exist on data in this class: 1061 1062 - The absolute path must be absolute 1063 1064 @note: Lists within this class are "unordered" for equality comparisons. 1065 1066 @sort: __init__, __repr__, __str__, __cmp__, command, absolutePath 1067 """ 1068
1069 - def __init__(self, command=None, absolutePath=None):
1070 """ 1071 Constructor for the C{CommandOverride} class. 1072 1073 @param command: Name of command to be overridden. 1074 @param absolutePath: Absolute path of the overrridden command. 1075 1076 @raise ValueError: If one of the values is invalid. 1077 """ 1078 self._command = None 1079 self._absolutePath = None 1080 self.command = command 1081 self.absolutePath = absolutePath
1082
1083 - def __repr__(self):
1084 """ 1085 Official string representation for class instance. 1086 """ 1087 return "CommandOverride(%s, %s)" % (self.command, self.absolutePath)
1088
1089 - def __str__(self):
1090 """ 1091 Informal string representation for class instance. 1092 """ 1093 return self.__repr__()
1094
1095 - def __cmp__(self, other):
1096 """ 1097 Definition of equals operator for this class. 1098 @param other: Other object to compare to. 1099 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1100 """ 1101 if other is None: 1102 return 1 1103 if self.command != other.command: 1104 if self.command < other.command: 1105 return -1 1106 else: 1107 return 1 1108 if self.absolutePath != other.absolutePath: 1109 if self.absolutePath < other.absolutePath: 1110 return -1 1111 else: 1112 return 1 1113 return 0
1114
1115 - def _setCommand(self, value):
1116 """ 1117 Property target used to set the command. 1118 The value must be a non-empty string if it is not C{None}. 1119 @raise ValueError: If the value is an empty string. 1120 """ 1121 if value is not None: 1122 if len(value) < 1: 1123 raise ValueError("The command must be a non-empty string.") 1124 self._command = value
1125
1126 - def _getCommand(self):
1127 """ 1128 Property target used to get the command. 1129 """ 1130 return self._command
1131
1132 - def _setAbsolutePath(self, value):
1133 """ 1134 Property target used to set the absolute path. 1135 The value must be an absolute path if it is not C{None}. 1136 It does not have to exist on disk at the time of assignment. 1137 @raise ValueError: If the value is not an absolute path. 1138 @raise ValueError: If the value cannot be encoded properly. 1139 """ 1140 if value is not None: 1141 if not os.path.isabs(value): 1142 raise ValueError("Not an absolute path: [%s]" % value) 1143 self._absolutePath = encodePath(value)
1144
1145 - def _getAbsolutePath(self):
1146 """ 1147 Property target used to get the absolute path. 1148 """ 1149 return self._absolutePath
1150 1151 command = property(_getCommand, _setCommand, None, doc="Name of command to be overridden.") 1152 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the overrridden command.")
1153
1154 1155 ######################################################################## 1156 # CollectFile class definition 1157 ######################################################################## 1158 1159 -class CollectFile(object):
1160 1161 """ 1162 Class representing a Cedar Backup collect file. 1163 1164 The following restrictions exist on data in this class: 1165 1166 - Absolute paths must be absolute 1167 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}. 1168 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}. 1169 1170 @sort: __init__, __repr__, __str__, __cmp__, absolutePath, collectMode, archiveMode 1171 """ 1172
1173 - def __init__(self, absolutePath=None, collectMode=None, archiveMode=None):
1174 """ 1175 Constructor for the C{CollectFile} class. 1176 1177 @param absolutePath: Absolute path of the file to collect. 1178 @param collectMode: Overridden collect mode for this file. 1179 @param archiveMode: Overridden archive mode for this file. 1180 1181 @raise ValueError: If one of the values is invalid. 1182 """ 1183 self._absolutePath = None 1184 self._collectMode = None 1185 self._archiveMode = None 1186 self.absolutePath = absolutePath 1187 self.collectMode = collectMode 1188 self.archiveMode = archiveMode
1189
1190 - def __repr__(self):
1191 """ 1192 Official string representation for class instance. 1193 """ 1194 return "CollectFile(%s, %s, %s)" % (self.absolutePath, self.collectMode, self.archiveMode)
1195
1196 - def __str__(self):
1197 """ 1198 Informal string representation for class instance. 1199 """ 1200 return self.__repr__()
1201
1202 - def __cmp__(self, other):
1203 """ 1204 Definition of equals operator for this class. 1205 @param other: Other object to compare to. 1206 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1207 """ 1208 if other is None: 1209 return 1 1210 if self.absolutePath != other.absolutePath: 1211 if self.absolutePath < other.absolutePath: 1212 return -1 1213 else: 1214 return 1 1215 if self.collectMode != other.collectMode: 1216 if self.collectMode < other.collectMode: 1217 return -1 1218 else: 1219 return 1 1220 if self.archiveMode != other.archiveMode: 1221 if self.archiveMode < other.archiveMode: 1222 return -1 1223 else: 1224 return 1 1225 return 0
1226
1227 - def _setAbsolutePath(self, value):
1228 """ 1229 Property target used to set the absolute path. 1230 The value must be an absolute path if it is not C{None}. 1231 It does not have to exist on disk at the time of assignment. 1232 @raise ValueError: If the value is not an absolute path. 1233 @raise ValueError: If the value cannot be encoded properly. 1234 """ 1235 if value is not None: 1236 if not os.path.isabs(value): 1237 raise ValueError("Not an absolute path: [%s]" % value) 1238 self._absolutePath = encodePath(value)
1239
1240 - def _getAbsolutePath(self):
1241 """ 1242 Property target used to get the absolute path. 1243 """ 1244 return self._absolutePath
1245
1246 - def _setCollectMode(self, value):
1247 """ 1248 Property target used to set the collect mode. 1249 If not C{None}, the mode must be one of the values in L{VALID_COLLECT_MODES}. 1250 @raise ValueError: If the value is not valid. 1251 """ 1252 if value is not None: 1253 if value not in VALID_COLLECT_MODES: 1254 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES) 1255 self._collectMode = value
1256
1257 - def _getCollectMode(self):
1258 """ 1259 Property target used to get the collect mode. 1260 """ 1261 return self._collectMode
1262
1263 - def _setArchiveMode(self, value):
1264 """ 1265 Property target used to set the archive mode. 1266 If not C{None}, the mode must be one of the values in L{VALID_ARCHIVE_MODES}. 1267 @raise ValueError: If the value is not valid. 1268 """ 1269 if value is not None: 1270 if value not in VALID_ARCHIVE_MODES: 1271 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES) 1272 self._archiveMode = value
1273
1274 - def _getArchiveMode(self):
1275 """ 1276 Property target used to get the archive mode. 1277 """ 1278 return self._archiveMode
1279 1280 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the file to collect.") 1281 collectMode = property(_getCollectMode, _setCollectMode, None, doc="Overridden collect mode for this file.") 1282 archiveMode = property(_getArchiveMode, _setArchiveMode, None, doc="Overridden archive mode for this file.")
1283
1284 1285 ######################################################################## 1286 # CollectDir class definition 1287 ######################################################################## 1288 1289 -class CollectDir(object):
1290 1291 """ 1292 Class representing a Cedar Backup collect directory. 1293 1294 The following restrictions exist on data in this class: 1295 1296 - Absolute paths must be absolute 1297 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}. 1298 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}. 1299 - The ignore file must be a non-empty string. 1300 1301 For the C{absoluteExcludePaths} list, validation is accomplished through the 1302 L{util.AbsolutePathList} list implementation that overrides common list 1303 methods and transparently does the absolute path validation for us. 1304 1305 @note: Lists within this class are "unordered" for equality comparisons. 1306 1307 @sort: __init__, __repr__, __str__, __cmp__, absolutePath, collectMode, 1308 archiveMode, ignoreFile, linkDepth, dereference, absoluteExcludePaths, 1309 relativeExcludePaths, excludePatterns 1310 """ 1311
1312 - def __init__(self, absolutePath=None, collectMode=None, archiveMode=None, ignoreFile=None, 1313 absoluteExcludePaths=None, relativeExcludePaths=None, excludePatterns=None, 1314 linkDepth=None, dereference=False, recursionLevel=None):
1315 """ 1316 Constructor for the C{CollectDir} class. 1317 1318 @param absolutePath: Absolute path of the directory to collect. 1319 @param collectMode: Overridden collect mode for this directory. 1320 @param archiveMode: Overridden archive mode for this directory. 1321 @param ignoreFile: Overidden ignore file name for this directory. 1322 @param linkDepth: Maximum at which soft links should be followed. 1323 @param dereference: Whether to dereference links that are followed. 1324 @param absoluteExcludePaths: List of absolute paths to exclude. 1325 @param relativeExcludePaths: List of relative paths to exclude. 1326 @param excludePatterns: List of regular expression patterns to exclude. 1327 1328 @raise ValueError: If one of the values is invalid. 1329 """ 1330 self._absolutePath = None 1331 self._collectMode = None 1332 self._archiveMode = None 1333 self._ignoreFile = None 1334 self._linkDepth = None 1335 self._dereference = None 1336 self._recursionLevel = None 1337 self._absoluteExcludePaths = None 1338 self._relativeExcludePaths = None 1339 self._excludePatterns = None 1340 self.absolutePath = absolutePath 1341 self.collectMode = collectMode 1342 self.archiveMode = archiveMode 1343 self.ignoreFile = ignoreFile 1344 self.linkDepth = linkDepth 1345 self.dereference = dereference 1346 self.recursionLevel = recursionLevel 1347 self.absoluteExcludePaths = absoluteExcludePaths 1348 self.relativeExcludePaths = relativeExcludePaths 1349 self.excludePatterns = excludePatterns
1350
1351 - def __repr__(self):
1352 """ 1353 Official string representation for class instance. 1354 """ 1355 return "CollectDir(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.absolutePath, self.collectMode, 1356 self.archiveMode, self.ignoreFile, 1357 self.absoluteExcludePaths, 1358 self.relativeExcludePaths, 1359 self.excludePatterns, 1360 self.linkDepth, self.dereference, 1361 self.recursionLevel)
1362
1363 - def __str__(self):
1364 """ 1365 Informal string representation for class instance. 1366 """ 1367 return self.__repr__()
1368
1369 - def __cmp__(self, other):
1370 """ 1371 Definition of equals operator for this class. 1372 Lists within this class are "unordered" for equality comparisons. 1373 @param other: Other object to compare to. 1374 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1375 """ 1376 if other is None: 1377 return 1 1378 if self.absolutePath != other.absolutePath: 1379 if self.absolutePath < other.absolutePath: 1380 return -1 1381 else: 1382 return 1 1383 if self.collectMode != other.collectMode: 1384 if self.collectMode < other.collectMode: 1385 return -1 1386 else: 1387 return 1 1388 if self.archiveMode != other.archiveMode: 1389 if self.archiveMode < other.archiveMode: 1390 return -1 1391 else: 1392 return 1 1393 if self.ignoreFile != other.ignoreFile: 1394 if self.ignoreFile < other.ignoreFile: 1395 return -1 1396 else: 1397 return 1 1398 if self.linkDepth != other.linkDepth: 1399 if self.linkDepth < other.linkDepth: 1400 return -1 1401 else: 1402 return 1 1403 if self.dereference != other.dereference: 1404 if self.dereference < other.dereference: 1405 return -1 1406 else: 1407 return 1 1408 if self.recursionLevel != other.recursionLevel: 1409 if self.recursionLevel < other.recursionLevel: 1410 return -1 1411 else: 1412 return 1 1413 if self.absoluteExcludePaths != other.absoluteExcludePaths: 1414 if self.absoluteExcludePaths < other.absoluteExcludePaths: 1415 return -1 1416 else: 1417 return 1 1418 if self.relativeExcludePaths != other.relativeExcludePaths: 1419 if self.relativeExcludePaths < other.relativeExcludePaths: 1420 return -1 1421 else: 1422 return 1 1423 if self.excludePatterns != other.excludePatterns: 1424 if self.excludePatterns < other.excludePatterns: 1425 return -1 1426 else: 1427 return 1 1428 return 0
1429
1430 - def _setAbsolutePath(self, value):
1431 """ 1432 Property target used to set the absolute path. 1433 The value must be an absolute path if it is not C{None}. 1434 It does not have to exist on disk at the time of assignment. 1435 @raise ValueError: If the value is not an absolute path. 1436 @raise ValueError: If the value cannot be encoded properly. 1437 """ 1438 if value is not None: 1439 if not os.path.isabs(value): 1440 raise ValueError("Not an absolute path: [%s]" % value) 1441 self._absolutePath = encodePath(value)
1442
1443 - def _getAbsolutePath(self):
1444 """ 1445 Property target used to get the absolute path. 1446 """ 1447 return self._absolutePath
1448
1449 - def _setCollectMode(self, value):
1450 """ 1451 Property target used to set the collect mode. 1452 If not C{None}, the mode must be one of the values in L{VALID_COLLECT_MODES}. 1453 @raise ValueError: If the value is not valid. 1454 """ 1455 if value is not None: 1456 if value not in VALID_COLLECT_MODES: 1457 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES) 1458 self._collectMode = value
1459
1460 - def _getCollectMode(self):
1461 """ 1462 Property target used to get the collect mode. 1463 """ 1464 return self._collectMode
1465
1466 - def _setArchiveMode(self, value):
1467 """ 1468 Property target used to set the archive mode. 1469 If not C{None}, the mode must be one of the values in L{VALID_ARCHIVE_MODES}. 1470 @raise ValueError: If the value is not valid. 1471 """ 1472 if value is not None: 1473 if value not in VALID_ARCHIVE_MODES: 1474 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES) 1475 self._archiveMode = value
1476
1477 - def _getArchiveMode(self):
1478 """ 1479 Property target used to get the archive mode. 1480 """ 1481 return self._archiveMode
1482
1483 - def _setIgnoreFile(self, value):
1484 """ 1485 Property target used to set the ignore file. 1486 The value must be a non-empty string if it is not C{None}. 1487 @raise ValueError: If the value is an empty string. 1488 """ 1489 if value is not None: 1490 if len(value) < 1: 1491 raise ValueError("The ignore file must be a non-empty string.") 1492 self._ignoreFile = value
1493
1494 - def _getIgnoreFile(self):
1495 """ 1496 Property target used to get the ignore file. 1497 """ 1498 return self._ignoreFile
1499
1500 - def _setLinkDepth(self, value):
1501 """ 1502 Property target used to set the link depth. 1503 The value must be an integer >= 0. 1504 @raise ValueError: If the value is not valid. 1505 """ 1506 if value is None: 1507 self._linkDepth = None 1508 else: 1509 try: 1510 value = int(value) 1511 except TypeError: 1512 raise ValueError("Link depth value must be an integer >= 0.") 1513 if value < 0: 1514 raise ValueError("Link depth value must be an integer >= 0.") 1515 self._linkDepth = value
1516
1517 - def _getLinkDepth(self):
1518 """ 1519 Property target used to get the action linkDepth. 1520 """ 1521 return self._linkDepth
1522
1523 - def _setDereference(self, value):
1524 """ 1525 Property target used to set the dereference flag. 1526 No validations, but we normalize the value to C{True} or C{False}. 1527 """ 1528 if value: 1529 self._dereference = True 1530 else: 1531 self._dereference = False
1532
1533 - def _getDereference(self):
1534 """ 1535 Property target used to get the dereference flag. 1536 """ 1537 return self._dereference
1538
1539 - def _setRecursionLevel(self, value):
1540 """ 1541 Property target used to set the recursionLevel. 1542 The value must be an integer. 1543 @raise ValueError: If the value is not valid. 1544 """ 1545 if value is None: 1546 self._recursionLevel = None 1547 else: 1548 try: 1549 value = int(value) 1550 except TypeError: 1551 raise ValueError("Recusion level value must be an integer.") 1552 self._recursionLevel = value
1553
1554 - def _getRecursionLevel(self):
1555 """ 1556 Property target used to get the action recursionLevel. 1557 """ 1558 return self._recursionLevel
1559
1560 - def _setAbsoluteExcludePaths(self, value):
1561 """ 1562 Property target used to set the absolute exclude paths list. 1563 Either the value must be C{None} or each element must be an absolute path. 1564 Elements do not have to exist on disk at the time of assignment. 1565 @raise ValueError: If the value is not an absolute path. 1566 """ 1567 if value is None: 1568 self._absoluteExcludePaths = None 1569 else: 1570 try: 1571 saved = self._absoluteExcludePaths 1572 self._absoluteExcludePaths = AbsolutePathList() 1573 self._absoluteExcludePaths.extend(value) 1574 except Exception, e: 1575 self._absoluteExcludePaths = saved 1576 raise e
1577
1578 - def _getAbsoluteExcludePaths(self):
1579 """ 1580 Property target used to get the absolute exclude paths list. 1581 """ 1582 return self._absoluteExcludePaths
1583
1584 - def _setRelativeExcludePaths(self, value):
1585 """ 1586 Property target used to set the relative exclude paths list. 1587 Elements do not have to exist on disk at the time of assignment. 1588 """ 1589 if value is None: 1590 self._relativeExcludePaths = None 1591 else: 1592 try: 1593 saved = self._relativeExcludePaths 1594 self._relativeExcludePaths = UnorderedList() 1595 self._relativeExcludePaths.extend(value) 1596 except Exception, e: 1597 self._relativeExcludePaths = saved 1598 raise e
1599
1600 - def _getRelativeExcludePaths(self):
1601 """ 1602 Property target used to get the relative exclude paths list. 1603 """ 1604 return self._relativeExcludePaths
1605
1606 - def _setExcludePatterns(self, value):
1607 """ 1608 Property target used to set the exclude patterns list. 1609 """ 1610 if value is None: 1611 self._excludePatterns = None 1612 else: 1613 try: 1614 saved = self._excludePatterns 1615 self._excludePatterns = RegexList() 1616 self._excludePatterns.extend(value) 1617 except Exception, e: 1618 self._excludePatterns = saved 1619 raise e
1620
1621 - def _getExcludePatterns(self):
1622 """ 1623 Property target used to get the exclude patterns list. 1624 """ 1625 return self._excludePatterns
1626 1627 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, doc="Absolute path of the directory to collect.") 1628 collectMode = property(_getCollectMode, _setCollectMode, None, doc="Overridden collect mode for this directory.") 1629 archiveMode = property(_getArchiveMode, _setArchiveMode, None, doc="Overridden archive mode for this directory.") 1630 ignoreFile = property(_getIgnoreFile, _setIgnoreFile, None, doc="Overridden ignore file name for this directory.") 1631 linkDepth = property(_getLinkDepth, _setLinkDepth, None, doc="Maximum at which soft links should be followed.") 1632 dereference = property(_getDereference, _setDereference, None, doc="Whether to dereference links that are followed.") 1633 recursionLevel = property(_getRecursionLevel, _setRecursionLevel, None, "Recursion level to use for recursive directory collection") 1634 absoluteExcludePaths = property(_getAbsoluteExcludePaths, _setAbsoluteExcludePaths, None, "List of absolute paths to exclude.") 1635 relativeExcludePaths = property(_getRelativeExcludePaths, _setRelativeExcludePaths, None, "List of relative paths to exclude.") 1636 excludePatterns = property(_getExcludePatterns, _setExcludePatterns, None, "List of regular expression patterns to exclude.")
1637
1638 1639 ######################################################################## 1640 # PurgeDir class definition 1641 ######################################################################## 1642 1643 -class PurgeDir(object):
1644 1645 """ 1646 Class representing a Cedar Backup purge directory. 1647 1648 The following restrictions exist on data in this class: 1649 1650 - The absolute path must be an absolute path 1651 - The retain days value must be an integer >= 0. 1652 1653 @sort: __init__, __repr__, __str__, __cmp__, absolutePath, retainDays 1654 """ 1655
1656 - def __init__(self, absolutePath=None, retainDays=None):
1657 """ 1658 Constructor for the C{PurgeDir} class. 1659 1660 @param absolutePath: Absolute path of the directory to be purged. 1661 @param retainDays: Number of days content within directory should be retained. 1662 1663 @raise ValueError: If one of the values is invalid. 1664 """ 1665 self._absolutePath = None 1666 self._retainDays = None 1667 self.absolutePath = absolutePath 1668 self.retainDays = retainDays
1669
1670 - def __repr__(self):
1671 """ 1672 Official string representation for class instance. 1673 """ 1674 return "PurgeDir(%s, %s)" % (self.absolutePath, self.retainDays)
1675
1676 - def __str__(self):
1677 """ 1678 Informal string representation for class instance. 1679 """ 1680 return self.__repr__()
1681
1682 - def __cmp__(self, other):
1683 """ 1684 Definition of equals operator for this class. 1685 @param other: Other object to compare to. 1686 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1687 """ 1688 if other is None: 1689 return 1 1690 if self.absolutePath != other.absolutePath: 1691 if self.absolutePath < other.absolutePath: 1692 return -1 1693 else: 1694 return 1 1695 if self.retainDays != other.retainDays: 1696 if self.retainDays < other.retainDays: 1697 return -1 1698 else: 1699 return 1 1700 return 0
1701
1702 - def _setAbsolutePath(self, value):
1703 """ 1704 Property target used to set the absolute path. 1705 The value must be an absolute path if it is not C{None}. 1706 It does not have to exist on disk at the time of assignment. 1707 @raise ValueError: If the value is not an absolute path. 1708 @raise ValueError: If the value cannot be encoded properly. 1709 """ 1710 if value is not None: 1711 if not os.path.isabs(value): 1712 raise ValueError("Absolute path must, er, be an absolute path.") 1713 self._absolutePath = encodePath(value)
1714
1715 - def _getAbsolutePath(self):
1716 """ 1717 Property target used to get the absolute path. 1718 """ 1719 return self._absolutePath
1720
1721 - def _setRetainDays(self, value):
1722 """ 1723 Property target used to set the retain days value. 1724 The value must be an integer >= 0. 1725 @raise ValueError: If the value is not valid. 1726 """ 1727 if value is None: 1728 self._retainDays = None 1729 else: 1730 try: 1731 value = int(value) 1732 except TypeError: 1733 raise ValueError("Retain days value must be an integer >= 0.") 1734 if value < 0: 1735 raise ValueError("Retain days value must be an integer >= 0.") 1736 self._retainDays = value
1737
1738 - def _getRetainDays(self):
1739 """ 1740 Property target used to get the absolute path. 1741 """ 1742 return self._retainDays
1743 1744 absolutePath = property(_getAbsolutePath, _setAbsolutePath, None, "Absolute path of directory to purge.") 1745 retainDays = property(_getRetainDays, _setRetainDays, None, "Number of days content within directory should be retained.")
1746
1747 1748 ######################################################################## 1749 # LocalPeer class definition 1750 ######################################################################## 1751 1752 -class LocalPeer(object):
1753 1754 """ 1755 Class representing a Cedar Backup peer. 1756 1757 The following restrictions exist on data in this class: 1758 1759 - The peer name must be a non-empty string. 1760 - The collect directory must be an absolute path. 1761 - The ignore failure mode must be one of the values in L{VALID_FAILURE_MODES}. 1762 1763 @sort: __init__, __repr__, __str__, __cmp__, name, collectDir 1764 """ 1765
1766 - def __init__(self, name=None, collectDir=None, ignoreFailureMode=None):
1767 """ 1768 Constructor for the C{LocalPeer} class. 1769 1770 @param name: Name of the peer, typically a valid hostname. 1771 @param collectDir: Collect directory to stage files from on peer. 1772 @param ignoreFailureMode: Ignore failure mode for peer. 1773 1774 @raise ValueError: If one of the values is invalid. 1775 """ 1776 self._name = None 1777 self._collectDir = None 1778 self._ignoreFailureMode = None 1779 self.name = name 1780 self.collectDir = collectDir 1781 self.ignoreFailureMode = ignoreFailureMode
1782
1783 - def __repr__(self):
1784 """ 1785 Official string representation for class instance. 1786 """ 1787 return "LocalPeer(%s, %s, %s)" % (self.name, self.collectDir, self.ignoreFailureMode)
1788
1789 - def __str__(self):
1790 """ 1791 Informal string representation for class instance. 1792 """ 1793 return self.__repr__()
1794
1795 - def __cmp__(self, other):
1796 """ 1797 Definition of equals operator for this class. 1798 @param other: Other object to compare to. 1799 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1800 """ 1801 if other is None: 1802 return 1 1803 if self.name != other.name: 1804 if self.name < other.name: 1805 return -1 1806 else: 1807 return 1 1808 if self.collectDir != other.collectDir: 1809 if self.collectDir < other.collectDir: 1810 return -1 1811 else: 1812 return 1 1813 if self.ignoreFailureMode != other.ignoreFailureMode: 1814 if self.ignoreFailureMode < other.ignoreFailureMode: 1815 return -1 1816 else: 1817 return 1 1818 return 0
1819
1820 - def _setName(self, value):
1821 """ 1822 Property target used to set the peer name. 1823 The value must be a non-empty string if it is not C{None}. 1824 @raise ValueError: If the value is an empty string. 1825 """ 1826 if value is not None: 1827 if len(value) < 1: 1828 raise ValueError("The peer name must be a non-empty string.") 1829 self._name = value
1830
1831 - def _getName(self):
1832 """ 1833 Property target used to get the peer name. 1834 """ 1835 return self._name
1836
1837 - def _setCollectDir(self, value):
1838 """ 1839 Property target used to set the collect directory. 1840 The value must be an absolute path if it is not C{None}. 1841 It does not have to exist on disk at the time of assignment. 1842 @raise ValueError: If the value is not an absolute path. 1843 @raise ValueError: If the value cannot be encoded properly. 1844 """ 1845 if value is not None: 1846 if not os.path.isabs(value): 1847 raise ValueError("Collect directory must be an absolute path.") 1848 self._collectDir = encodePath(value)
1849
1850 - def _getCollectDir(self):
1851 """ 1852 Property target used to get the collect directory. 1853 """ 1854 return self._collectDir
1855
1856 - def _setIgnoreFailureMode(self, value):
1857 """ 1858 Property target used to set the ignoreFailure mode. 1859 If not C{None}, the mode must be one of the values in L{VALID_FAILURE_MODES}. 1860 @raise ValueError: If the value is not valid. 1861 """ 1862 if value is not None: 1863 if value not in VALID_FAILURE_MODES: 1864 raise ValueError("Ignore failure mode must be one of %s." % VALID_FAILURE_MODES) 1865 self._ignoreFailureMode = value
1866
1867 - def _getIgnoreFailureMode(self):
1868 """ 1869 Property target used to get the ignoreFailure mode. 1870 """ 1871 return self._ignoreFailureMode
1872 1873 name = property(_getName, _setName, None, "Name of the peer, typically a valid hostname.") 1874 collectDir = property(_getCollectDir, _setCollectDir, None, "Collect directory to stage files from on peer.") 1875 ignoreFailureMode = property(_getIgnoreFailureMode, _setIgnoreFailureMode, None, "Ignore failure mode for peer.")
1876
1877 1878 ######################################################################## 1879 # RemotePeer class definition 1880 ######################################################################## 1881 1882 -class RemotePeer(object):
1883 1884 """ 1885 Class representing a Cedar Backup peer. 1886 1887 The following restrictions exist on data in this class: 1888 1889 - The peer name must be a non-empty string. 1890 - The collect directory must be an absolute path. 1891 - The remote user must be a non-empty string. 1892 - The rcp command must be a non-empty string. 1893 - The rsh command must be a non-empty string. 1894 - The cback command must be a non-empty string. 1895 - Any managed action name must be a non-empty string matching C{ACTION_NAME_REGEX} 1896 - The ignore failure mode must be one of the values in L{VALID_FAILURE_MODES}. 1897 1898 @sort: __init__, __repr__, __str__, __cmp__, name, collectDir, remoteUser, rcpCommand 1899 """ 1900
1901 - def __init__(self, name=None, collectDir=None, remoteUser=None, 1902 rcpCommand=None, rshCommand=None, cbackCommand=None, 1903 managed=False, managedActions=None, ignoreFailureMode=None):
1904 """ 1905 Constructor for the C{RemotePeer} class. 1906 1907 @param name: Name of the peer, must be a valid hostname. 1908 @param collectDir: Collect directory to stage files from on peer. 1909 @param remoteUser: Name of backup user on remote peer. 1910 @param rcpCommand: Overridden rcp-compatible copy command for peer. 1911 @param rshCommand: Overridden rsh-compatible remote shell command for peer. 1912 @param cbackCommand: Overridden cback-compatible command to use on remote peer. 1913 @param managed: Indicates whether this is a managed peer. 1914 @param managedActions: Overridden set of actions that are managed on the peer. 1915 @param ignoreFailureMode: Ignore failure mode for peer. 1916 1917 @raise ValueError: If one of the values is invalid. 1918 """ 1919 self._name = None 1920 self._collectDir = None 1921 self._remoteUser = None 1922 self._rcpCommand = None 1923 self._rshCommand = None 1924 self._cbackCommand = None 1925 self._managed = None 1926 self._managedActions = None 1927 self._ignoreFailureMode = None 1928 self.name = name 1929 self.collectDir = collectDir 1930 self.remoteUser = remoteUser 1931 self.rcpCommand = rcpCommand 1932 self.rshCommand = rshCommand 1933 self.cbackCommand = cbackCommand 1934 self.managed = managed 1935 self.managedActions = managedActions 1936 self.ignoreFailureMode = ignoreFailureMode
1937
1938 - def __repr__(self):
1939 """ 1940 Official string representation for class instance. 1941 """ 1942 return "RemotePeer(%s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.name, self.collectDir, self.remoteUser, 1943 self.rcpCommand, self.rshCommand, self.cbackCommand, 1944 self.managed, self.managedActions, self.ignoreFailureMode)
1945
1946 - def __str__(self):
1947 """ 1948 Informal string representation for class instance. 1949 """ 1950 return self.__repr__()
1951
1952 - def __cmp__(self, other):
1953 """ 1954 Definition of equals operator for this class. 1955 @param other: Other object to compare to. 1956 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 1957 """ 1958 if other is None: 1959 return 1 1960 if self.name != other.name: 1961 if self.name < other.name: 1962 return -1 1963 else: 1964 return 1 1965 if self.collectDir != other.collectDir: 1966 if self.collectDir < other.collectDir: 1967 return -1 1968 else: 1969 return 1 1970 if self.remoteUser != other.remoteUser: 1971 if self.remoteUser < other.remoteUser: 1972 return -1 1973 else: 1974 return 1 1975 if self.rcpCommand != other.rcpCommand: 1976 if self.rcpCommand < other.rcpCommand: 1977 return -1 1978 else: 1979 return 1 1980 if self.rshCommand != other.rshCommand: 1981 if self.rshCommand < other.rshCommand: 1982 return -1 1983 else: 1984 return 1 1985 if self.cbackCommand != other.cbackCommand: 1986 if self.cbackCommand < other.cbackCommand: 1987 return -1 1988 else: 1989 return 1 1990 if self.managed != other.managed: 1991 if self.managed < other.managed: 1992 return -1 1993 else: 1994 return 1 1995 if self.managedActions != other.managedActions: 1996 if self.managedActions < other.managedActions: 1997 return -1 1998 else: 1999 return 1 2000 if self.ignoreFailureMode != other.ignoreFailureMode: 2001 if self.ignoreFailureMode < other.ignoreFailureMode: 2002 return -1 2003 else: 2004 return 1 2005 return 0
2006
2007 - def _setName(self, value):
2008 """ 2009 Property target used to set the peer name. 2010 The value must be a non-empty string if it is not C{None}. 2011 @raise ValueError: If the value is an empty string. 2012 """ 2013 if value is not None: 2014 if len(value) < 1: 2015 raise ValueError("The peer name must be a non-empty string.") 2016 self._name = value
2017
2018 - def _getName(self):
2019 """ 2020 Property target used to get the peer name. 2021 """ 2022 return self._name
2023
2024 - def _setCollectDir(self, value):
2025 """ 2026 Property target used to set the collect directory. 2027 The value must be an absolute path if it is not C{None}. 2028 It does not have to exist on disk at the time of assignment. 2029 @raise ValueError: If the value is not an absolute path. 2030 @raise ValueError: If the value cannot be encoded properly. 2031 """ 2032 if value is not None: 2033 if not os.path.isabs(value): 2034 raise ValueError("Collect directory must be an absolute path.") 2035 self._collectDir = encodePath(value)
2036
2037 - def _getCollectDir(self):
2038 """ 2039 Property target used to get the collect directory. 2040 """ 2041 return self._collectDir
2042
2043 - def _setRemoteUser(self, value):
2044 """ 2045 Property target used to set the remote user. 2046 The value must be a non-empty string if it is not C{None}. 2047 @raise ValueError: If the value is an empty string. 2048 """ 2049 if value is not None: 2050 if len(value) < 1: 2051 raise ValueError("The remote user must be a non-empty string.") 2052 self._remoteUser = value
2053
2054 - def _getRemoteUser(self):
2055 """ 2056 Property target used to get the remote user. 2057 """ 2058 return self._remoteUser
2059
2060 - def _setRcpCommand(self, value):
2061 """ 2062 Property target used to set the rcp command. 2063 The value must be a non-empty string if it is not C{None}. 2064 @raise ValueError: If the value is an empty string. 2065 """ 2066 if value is not None: 2067 if len(value) < 1: 2068 raise ValueError("The rcp command must be a non-empty string.") 2069 self._rcpCommand = value
2070
2071 - def _getRcpCommand(self):
2072 """ 2073 Property target used to get the rcp command. 2074 """ 2075 return self._rcpCommand
2076
2077 - def _setRshCommand(self, value):
2078 """ 2079 Property target used to set the rsh command. 2080 The value must be a non-empty string if it is not C{None}. 2081 @raise ValueError: If the value is an empty string. 2082 """ 2083 if value is not None: 2084 if len(value) < 1: 2085 raise ValueError("The rsh command must be a non-empty string.") 2086 self._rshCommand = value
2087
2088 - def _getRshCommand(self):
2089 """ 2090 Property target used to get the rsh command. 2091 """ 2092 return self._rshCommand
2093
2094 - def _setCbackCommand(self, value):
2095 """ 2096 Property target used to set the cback command. 2097 The value must be a non-empty string if it is not C{None}. 2098 @raise ValueError: If the value is an empty string. 2099 """ 2100 if value is not None: 2101 if len(value) < 1: 2102 raise ValueError("The cback command must be a non-empty string.") 2103 self._cbackCommand = value
2104
2105 - def _getCbackCommand(self):
2106 """ 2107 Property target used to get the cback command. 2108 """ 2109 return self._cbackCommand
2110
2111 - def _setManaged(self, value):
2112 """ 2113 Property target used to set the managed flag. 2114 No validations, but we normalize the value to C{True} or C{False}. 2115 """ 2116 if value: 2117 self._managed = True 2118 else: 2119 self._managed = False
2120
2121 - def _getManaged(self):
2122 """ 2123 Property target used to get the managed flag. 2124 """ 2125 return self._managed
2126
2127 - def _setManagedActions(self, value):
2128 """ 2129 Property target used to set the managed actions list. 2130 Elements do not have to exist on disk at the time of assignment. 2131 """ 2132 if value is None: 2133 self._managedActions = None 2134 else: 2135 try: 2136 saved = self._managedActions 2137 self._managedActions = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name") 2138 self._managedActions.extend(value) 2139 except Exception, e: 2140 self._managedActions = saved 2141 raise e
2142
2143 - def _getManagedActions(self):
2144 """ 2145 Property target used to get the managed actions list. 2146 """ 2147 return self._managedActions
2148
2149 - def _setIgnoreFailureMode(self, value):
2150 """ 2151 Property target used to set the ignoreFailure mode. 2152 If not C{None}, the mode must be one of the values in L{VALID_FAILURE_MODES}. 2153 @raise ValueError: If the value is not valid. 2154 """ 2155 if value is not None: 2156 if value not in VALID_FAILURE_MODES: 2157 raise ValueError("Ignore failure mode must be one of %s." % VALID_FAILURE_MODES) 2158 self._ignoreFailureMode = value
2159
2160 - def _getIgnoreFailureMode(self):
2161 """ 2162 Property target used to get the ignoreFailure mode. 2163 """ 2164 return self._ignoreFailureMode
2165 2166 name = property(_getName, _setName, None, "Name of the peer, must be a valid hostname.") 2167 collectDir = property(_getCollectDir, _setCollectDir, None, "Collect directory to stage files from on peer.") 2168 remoteUser = property(_getRemoteUser, _setRemoteUser, None, "Name of backup user on remote peer.") 2169 rcpCommand = property(_getRcpCommand, _setRcpCommand, None, "Overridden rcp-compatible copy command for peer.") 2170 rshCommand = property(_getRshCommand, _setRshCommand, None, "Overridden rsh-compatible remote shell command for peer.") 2171 cbackCommand = property(_getCbackCommand, _setCbackCommand, None, "Overridden cback-compatible command to use on remote peer.") 2172 managed = property(_getManaged, _setManaged, None, "Indicates whether this is a managed peer.") 2173 managedActions = property(_getManagedActions, _setManagedActions, None, "Overridden set of actions that are managed on the peer.") 2174 ignoreFailureMode = property(_getIgnoreFailureMode, _setIgnoreFailureMode, None, "Ignore failure mode for peer.")
2175
2176 2177 ######################################################################## 2178 # ReferenceConfig class definition 2179 ######################################################################## 2180 2181 -class ReferenceConfig(object):
2182 2183 """ 2184 Class representing a Cedar Backup reference configuration. 2185 2186 The reference information is just used for saving off metadata about 2187 configuration and exists mostly for backwards-compatibility with Cedar 2188 Backup 1.x. 2189 2190 @sort: __init__, __repr__, __str__, __cmp__, author, revision, description, generator 2191 """ 2192
2193 - def __init__(self, author=None, revision=None, description=None, generator=None):
2194 """ 2195 Constructor for the C{ReferenceConfig} class. 2196 2197 @param author: Author of the configuration file. 2198 @param revision: Revision of the configuration file. 2199 @param description: Description of the configuration file. 2200 @param generator: Tool that generated the configuration file. 2201 """ 2202 self._author = None 2203 self._revision = None 2204 self._description = None 2205 self._generator = None 2206 self.author = author 2207 self.revision = revision 2208 self.description = description 2209 self.generator = generator
2210
2211 - def __repr__(self):
2212 """ 2213 Official string representation for class instance. 2214 """ 2215 return "ReferenceConfig(%s, %s, %s, %s)" % (self.author, self.revision, self.description, self.generator)
2216
2217 - def __str__(self):
2218 """ 2219 Informal string representation for class instance. 2220 """ 2221 return self.__repr__()
2222
2223 - def __cmp__(self, other):
2224 """ 2225 Definition of equals operator for this class. 2226 @param other: Other object to compare to. 2227 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2228 """ 2229 if other is None: 2230 return 1 2231 if self.author != other.author: 2232 if self.author < other.author: 2233 return -1 2234 else: 2235 return 1 2236 if self.revision != other.revision: 2237 if self.revision < other.revision: 2238 return -1 2239 else: 2240 return 1 2241 if self.description != other.description: 2242 if self.description < other.description: 2243 return -1 2244 else: 2245 return 1 2246 if self.generator != other.generator: 2247 if self.generator < other.generator: 2248 return -1 2249 else: 2250 return 1 2251 return 0
2252
2253 - def _setAuthor(self, value):
2254 """ 2255 Property target used to set the author value. 2256 No validations. 2257 """ 2258 self._author = value
2259
2260 - def _getAuthor(self):
2261 """ 2262 Property target used to get the author value. 2263 """ 2264 return self._author
2265
2266 - def _setRevision(self, value):
2267 """ 2268 Property target used to set the revision value. 2269 No validations. 2270 """ 2271 self._revision = value
2272
2273 - def _getRevision(self):
2274 """ 2275 Property target used to get the revision value. 2276 """ 2277 return self._revision
2278
2279 - def _setDescription(self, value):
2280 """ 2281 Property target used to set the description value. 2282 No validations. 2283 """ 2284 self._description = value
2285
2286 - def _getDescription(self):
2287 """ 2288 Property target used to get the description value. 2289 """ 2290 return self._description
2291
2292 - def _setGenerator(self, value):
2293 """ 2294 Property target used to set the generator value. 2295 No validations. 2296 """ 2297 self._generator = value
2298
2299 - def _getGenerator(self):
2300 """ 2301 Property target used to get the generator value. 2302 """ 2303 return self._generator
2304 2305 author = property(_getAuthor, _setAuthor, None, "Author of the configuration file.") 2306 revision = property(_getRevision, _setRevision, None, "Revision of the configuration file.") 2307 description = property(_getDescription, _setDescription, None, "Description of the configuration file.") 2308 generator = property(_getGenerator, _setGenerator, None, "Tool that generated the configuration file.")
2309
2310 2311 ######################################################################## 2312 # ExtensionsConfig class definition 2313 ######################################################################## 2314 2315 -class ExtensionsConfig(object):
2316 2317 """ 2318 Class representing Cedar Backup extensions configuration. 2319 2320 Extensions configuration is used to specify "extended actions" implemented 2321 by code external to Cedar Backup. For instance, a hypothetical third party 2322 might write extension code to collect database repository data. If they 2323 write a properly-formatted extension function, they can use the extension 2324 configuration to map a command-line Cedar Backup action (i.e. "database") 2325 to their function. 2326 2327 The following restrictions exist on data in this class: 2328 2329 - If set, the order mode must be one of the values in C{VALID_ORDER_MODES} 2330 - The actions list must be a list of C{ExtendedAction} objects. 2331 2332 @sort: __init__, __repr__, __str__, __cmp__, orderMode, actions 2333 """ 2334
2335 - def __init__(self, actions=None, orderMode=None):
2336 """ 2337 Constructor for the C{ExtensionsConfig} class. 2338 @param actions: List of extended actions 2339 """ 2340 self._orderMode = None 2341 self._actions = None 2342 self.orderMode = orderMode 2343 self.actions = actions
2344
2345 - def __repr__(self):
2346 """ 2347 Official string representation for class instance. 2348 """ 2349 return "ExtensionsConfig(%s, %s)" % (self.orderMode, self.actions)
2350
2351 - def __str__(self):
2352 """ 2353 Informal string representation for class instance. 2354 """ 2355 return self.__repr__()
2356
2357 - def __cmp__(self, other):
2358 """ 2359 Definition of equals operator for this class. 2360 @param other: Other object to compare to. 2361 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2362 """ 2363 if other is None: 2364 return 1 2365 if self.orderMode != other.orderMode: 2366 if self.orderMode < other.orderMode: 2367 return -1 2368 else: 2369 return 1 2370 if self.actions != other.actions: 2371 if self.actions < other.actions: 2372 return -1 2373 else: 2374 return 1 2375 return 0
2376
2377 - def _setOrderMode(self, value):
2378 """ 2379 Property target used to set the order mode. 2380 The value must be one of L{VALID_ORDER_MODES}. 2381 @raise ValueError: If the value is not valid. 2382 """ 2383 if value is not None: 2384 if value not in VALID_ORDER_MODES: 2385 raise ValueError("Order mode must be one of %s." % VALID_ORDER_MODES) 2386 self._orderMode = value
2387
2388 - def _getOrderMode(self):
2389 """ 2390 Property target used to get the order mode. 2391 """ 2392 return self._orderMode
2393
2394 - def _setActions(self, value):
2395 """ 2396 Property target used to set the actions list. 2397 Either the value must be C{None} or each element must be an C{ExtendedAction}. 2398 @raise ValueError: If the value is not a C{ExtendedAction} 2399 """ 2400 if value is None: 2401 self._actions = None 2402 else: 2403 try: 2404 saved = self._actions 2405 self._actions = ObjectTypeList(ExtendedAction, "ExtendedAction") 2406 self._actions.extend(value) 2407 except Exception, e: 2408 self._actions = saved 2409 raise e
2410
2411 - def _getActions(self):
2412 """ 2413 Property target used to get the actions list. 2414 """ 2415 return self._actions
2416 2417 orderMode = property(_getOrderMode, _setOrderMode, None, "Order mode for extensions, to control execution ordering.") 2418 actions = property(_getActions, _setActions, None, "List of extended actions.")
2419
2420 2421 ######################################################################## 2422 # OptionsConfig class definition 2423 ######################################################################## 2424 2425 -class OptionsConfig(object):
2426 2427 """ 2428 Class representing a Cedar Backup global options configuration. 2429 2430 The options section is used to store global configuration options and 2431 defaults that can be applied to other sections. 2432 2433 The following restrictions exist on data in this class: 2434 2435 - The working directory must be an absolute path. 2436 - The starting day must be a day of the week in English, i.e. C{"monday"}, C{"tuesday"}, etc. 2437 - All of the other values must be non-empty strings if they are set to something other than C{None}. 2438 - The overrides list must be a list of C{CommandOverride} objects. 2439 - The hooks list must be a list of C{ActionHook} objects. 2440 - The cback command must be a non-empty string. 2441 - Any managed action name must be a non-empty string matching C{ACTION_NAME_REGEX} 2442 2443 @sort: __init__, __repr__, __str__, __cmp__, startingDay, workingDir, 2444 backupUser, backupGroup, rcpCommand, rshCommand, overrides 2445 """ 2446
2447 - def __init__(self, startingDay=None, workingDir=None, backupUser=None, 2448 backupGroup=None, rcpCommand=None, overrides=None, 2449 hooks=None, rshCommand=None, cbackCommand=None, 2450 managedActions=None):
2451 """ 2452 Constructor for the C{OptionsConfig} class. 2453 2454 @param startingDay: Day that starts the week. 2455 @param workingDir: Working (temporary) directory to use for backups. 2456 @param backupUser: Effective user that backups should run as. 2457 @param backupGroup: Effective group that backups should run as. 2458 @param rcpCommand: Default rcp-compatible copy command for staging. 2459 @param rshCommand: Default rsh-compatible command to use for remote shells. 2460 @param cbackCommand: Default cback-compatible command to use on managed remote peers. 2461 @param overrides: List of configured command path overrides, if any. 2462 @param hooks: List of configured pre- and post-action hooks. 2463 @param managedActions: Default set of actions that are managed on remote peers. 2464 2465 @raise ValueError: If one of the values is invalid. 2466 """ 2467 self._startingDay = None 2468 self._workingDir = None 2469 self._backupUser = None 2470 self._backupGroup = None 2471 self._rcpCommand = None 2472 self._rshCommand = None 2473 self._cbackCommand = None 2474 self._overrides = None 2475 self._hooks = None 2476 self._managedActions = None 2477 self.startingDay = startingDay 2478 self.workingDir = workingDir 2479 self.backupUser = backupUser 2480 self.backupGroup = backupGroup 2481 self.rcpCommand = rcpCommand 2482 self.rshCommand = rshCommand 2483 self.cbackCommand = cbackCommand 2484 self.overrides = overrides 2485 self.hooks = hooks 2486 self.managedActions = managedActions
2487
2488 - def __repr__(self):
2489 """ 2490 Official string representation for class instance. 2491 """ 2492 return "OptionsConfig(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.startingDay, self.workingDir, 2493 self.backupUser, self.backupGroup, 2494 self.rcpCommand, self.overrides, 2495 self.hooks, self.rshCommand, 2496 self.cbackCommand, self.managedActions)
2497
2498 - def __str__(self):
2499 """ 2500 Informal string representation for class instance. 2501 """ 2502 return self.__repr__()
2503
2504 - def __cmp__(self, other):
2505 """ 2506 Definition of equals operator for this class. 2507 @param other: Other object to compare to. 2508 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2509 """ 2510 if other is None: 2511 return 1 2512 if self.startingDay != other.startingDay: 2513 if self.startingDay < other.startingDay: 2514 return -1 2515 else: 2516 return 1 2517 if self.workingDir != other.workingDir: 2518 if self.workingDir < other.workingDir: 2519 return -1 2520 else: 2521 return 1 2522 if self.backupUser != other.backupUser: 2523 if self.backupUser < other.backupUser: 2524 return -1 2525 else: 2526 return 1 2527 if self.backupGroup != other.backupGroup: 2528 if self.backupGroup < other.backupGroup: 2529 return -1 2530 else: 2531 return 1 2532 if self.rcpCommand != other.rcpCommand: 2533 if self.rcpCommand < other.rcpCommand: 2534 return -1 2535 else: 2536 return 1 2537 if self.rshCommand != other.rshCommand: 2538 if self.rshCommand < other.rshCommand: 2539 return -1 2540 else: 2541 return 1 2542 if self.cbackCommand != other.cbackCommand: 2543 if self.cbackCommand < other.cbackCommand: 2544 return -1 2545 else: 2546 return 1 2547 if self.overrides != other.overrides: 2548 if self.overrides < other.overrides: 2549 return -1 2550 else: 2551 return 1 2552 if self.hooks != other.hooks: 2553 if self.hooks < other.hooks: 2554 return -1 2555 else: 2556 return 1 2557 if self.managedActions != other.managedActions: 2558 if self.managedActions < other.managedActions: 2559 return -1 2560 else: 2561 return 1 2562 return 0
2563
2564 - def addOverride(self, command, absolutePath):
2565 """ 2566 If no override currently exists for the command, add one. 2567 @param command: Name of command to be overridden. 2568 @param absolutePath: Absolute path of the overrridden command. 2569 """ 2570 override = CommandOverride(command, absolutePath) 2571 if self.overrides is None: 2572 self.overrides = [ override, ] 2573 else: 2574 exists = False 2575 for obj in self.overrides: 2576 if obj.command == override.command: 2577 exists = True 2578 break 2579 if not exists: 2580 self.overrides.append(override)
2581
2582 - def replaceOverride(self, command, absolutePath):
2583 """ 2584 If override currently exists for the command, replace it; otherwise add it. 2585 @param command: Name of command to be overridden. 2586 @param absolutePath: Absolute path of the overrridden command. 2587 """ 2588 override = CommandOverride(command, absolutePath) 2589 if self.overrides is None: 2590 self.overrides = [ override, ] 2591 else: 2592 exists = False 2593 for obj in self.overrides: 2594 if obj.command == override.command: 2595 exists = True 2596 obj.absolutePath = override.absolutePath 2597 break 2598 if not exists: 2599 self.overrides.append(override)
2600
2601 - def _setStartingDay(self, value):
2602 """ 2603 Property target used to set the starting day. 2604 If it is not C{None}, the value must be a valid English day of the week, 2605 one of C{"monday"}, C{"tuesday"}, C{"wednesday"}, etc. 2606 @raise ValueError: If the value is not a valid day of the week. 2607 """ 2608 if value is not None: 2609 if value not in ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", ]: 2610 raise ValueError("Starting day must be an English day of the week, i.e. \"monday\".") 2611 self._startingDay = value
2612
2613 - def _getStartingDay(self):
2614 """ 2615 Property target used to get the starting day. 2616 """ 2617 return self._startingDay
2618
2619 - def _setWorkingDir(self, value):
2620 """ 2621 Property target used to set the working directory. 2622 The value must be an absolute path if it is not C{None}. 2623 It does not have to exist on disk at the time of assignment. 2624 @raise ValueError: If the value is not an absolute path. 2625 @raise ValueError: If the value cannot be encoded properly. 2626 """ 2627 if value is not None: 2628 if not os.path.isabs(value): 2629 raise ValueError("Working directory must be an absolute path.") 2630 self._workingDir = encodePath(value)
2631
2632 - def _getWorkingDir(self):
2633 """ 2634 Property target used to get the working directory. 2635 """ 2636 return self._workingDir
2637
2638 - def _setBackupUser(self, value):
2639 """ 2640 Property target used to set the backup user. 2641 The value must be a non-empty string if it is not C{None}. 2642 @raise ValueError: If the value is an empty string. 2643 """ 2644 if value is not None: 2645 if len(value) < 1: 2646 raise ValueError("Backup user must be a non-empty string.") 2647 self._backupUser = value
2648
2649 - def _getBackupUser(self):
2650 """ 2651 Property target used to get the backup user. 2652 """ 2653 return self._backupUser
2654
2655 - def _setBackupGroup(self, value):
2656 """ 2657 Property target used to set the backup group. 2658 The value must be a non-empty string if it is not C{None}. 2659 @raise ValueError: If the value is an empty string. 2660 """ 2661 if value is not None: 2662 if len(value) < 1: 2663 raise ValueError("Backup group must be a non-empty string.") 2664 self._backupGroup = value
2665
2666 - def _getBackupGroup(self):
2667 """ 2668 Property target used to get the backup group. 2669 """ 2670 return self._backupGroup
2671
2672 - def _setRcpCommand(self, value):
2673 """ 2674 Property target used to set the rcp command. 2675 The value must be a non-empty string if it is not C{None}. 2676 @raise ValueError: If the value is an empty string. 2677 """ 2678 if value is not None: 2679 if len(value) < 1: 2680 raise ValueError("The rcp command must be a non-empty string.") 2681 self._rcpCommand = value
2682
2683 - def _getRcpCommand(self):
2684 """ 2685 Property target used to get the rcp command. 2686 """ 2687 return self._rcpCommand
2688
2689 - def _setRshCommand(self, value):
2690 """ 2691 Property target used to set the rsh command. 2692 The value must be a non-empty string if it is not C{None}. 2693 @raise ValueError: If the value is an empty string. 2694 """ 2695 if value is not None: 2696 if len(value) < 1: 2697 raise ValueError("The rsh command must be a non-empty string.") 2698 self._rshCommand = value
2699
2700 - def _getRshCommand(self):
2701 """ 2702 Property target used to get the rsh command. 2703 """ 2704 return self._rshCommand
2705
2706 - def _setCbackCommand(self, value):
2707 """ 2708 Property target used to set the cback command. 2709 The value must be a non-empty string if it is not C{None}. 2710 @raise ValueError: If the value is an empty string. 2711 """ 2712 if value is not None: 2713 if len(value) < 1: 2714 raise ValueError("The cback command must be a non-empty string.") 2715 self._cbackCommand = value
2716
2717 - def _getCbackCommand(self):
2718 """ 2719 Property target used to get the cback command. 2720 """ 2721 return self._cbackCommand
2722
2723 - def _setOverrides(self, value):
2724 """ 2725 Property target used to set the command path overrides list. 2726 Either the value must be C{None} or each element must be a C{CommandOverride}. 2727 @raise ValueError: If the value is not a C{CommandOverride} 2728 """ 2729 if value is None: 2730 self._overrides = None 2731 else: 2732 try: 2733 saved = self._overrides 2734 self._overrides = ObjectTypeList(CommandOverride, "CommandOverride") 2735 self._overrides.extend(value) 2736 except Exception, e: 2737 self._overrides = saved 2738 raise e
2739
2740 - def _getOverrides(self):
2741 """ 2742 Property target used to get the command path overrides list. 2743 """ 2744 return self._overrides
2745
2746 - def _setHooks(self, value):
2747 """ 2748 Property target used to set the pre- and post-action hooks list. 2749 Either the value must be C{None} or each element must be an C{ActionHook}. 2750 @raise ValueError: If the value is not a C{CommandOverride} 2751 """ 2752 if value is None: 2753 self._hooks = None 2754 else: 2755 try: 2756 saved = self._hooks 2757 self._hooks = ObjectTypeList(ActionHook, "ActionHook") 2758 self._hooks.extend(value) 2759 except Exception, e: 2760 self._hooks = saved 2761 raise e
2762
2763 - def _getHooks(self):
2764 """ 2765 Property target used to get the command path hooks list. 2766 """ 2767 return self._hooks
2768
2769 - def _setManagedActions(self, value):
2770 """ 2771 Property target used to set the managed actions list. 2772 Elements do not have to exist on disk at the time of assignment. 2773 """ 2774 if value is None: 2775 self._managedActions = None 2776 else: 2777 try: 2778 saved = self._managedActions 2779 self._managedActions = RegexMatchList(ACTION_NAME_REGEX, emptyAllowed=False, prefix="Action name") 2780 self._managedActions.extend(value) 2781 except Exception, e: 2782 self._managedActions = saved 2783 raise e
2784
2785 - def _getManagedActions(self):
2786 """ 2787 Property target used to get the managed actions list. 2788 """ 2789 return self._managedActions
2790 2791 startingDay = property(_getStartingDay, _setStartingDay, None, "Day that starts the week.") 2792 workingDir = property(_getWorkingDir, _setWorkingDir, None, "Working (temporary) directory to use for backups.") 2793 backupUser = property(_getBackupUser, _setBackupUser, None, "Effective user that backups should run as.") 2794 backupGroup = property(_getBackupGroup, _setBackupGroup, None, "Effective group that backups should run as.") 2795 rcpCommand = property(_getRcpCommand, _setRcpCommand, None, "Default rcp-compatible copy command for staging.") 2796 rshCommand = property(_getRshCommand, _setRshCommand, None, "Default rsh-compatible command to use for remote shells.") 2797 cbackCommand = property(_getCbackCommand, _setCbackCommand, None, "Default cback-compatible command to use on managed remote peers.") 2798 overrides = property(_getOverrides, _setOverrides, None, "List of configured command path overrides, if any.") 2799 hooks = property(_getHooks, _setHooks, None, "List of configured pre- and post-action hooks.") 2800 managedActions = property(_getManagedActions, _setManagedActions, None, "Default set of actions that are managed on remote peers.")
2801
2802 2803 ######################################################################## 2804 # PeersConfig class definition 2805 ######################################################################## 2806 2807 -class PeersConfig(object):
2808 2809 """ 2810 Class representing Cedar Backup global peer configuration. 2811 2812 This section contains a list of local and remote peers in a master's backup 2813 pool. The section is optional. If a master does not define this section, 2814 then all peers are unmanaged, and the stage configuration section must 2815 explicitly list any peer that is to be staged. If this section is 2816 configured, then peers may be managed or unmanaged, and the stage section 2817 peer configuration (if any) completely overrides this configuration. 2818 2819 The following restrictions exist on data in this class: 2820 2821 - The list of local peers must contain only C{LocalPeer} objects 2822 - The list of remote peers must contain only C{RemotePeer} objects 2823 2824 @note: Lists within this class are "unordered" for equality comparisons. 2825 2826 @sort: __init__, __repr__, __str__, __cmp__, localPeers, remotePeers 2827 """ 2828
2829 - def __init__(self, localPeers=None, remotePeers=None):
2830 """ 2831 Constructor for the C{PeersConfig} class. 2832 2833 @param localPeers: List of local peers. 2834 @param remotePeers: List of remote peers. 2835 2836 @raise ValueError: If one of the values is invalid. 2837 """ 2838 self._localPeers = None 2839 self._remotePeers = None 2840 self.localPeers = localPeers 2841 self.remotePeers = remotePeers
2842
2843 - def __repr__(self):
2844 """ 2845 Official string representation for class instance. 2846 """ 2847 return "PeersConfig(%s, %s)" % (self.localPeers, self.remotePeers)
2848
2849 - def __str__(self):
2850 """ 2851 Informal string representation for class instance. 2852 """ 2853 return self.__repr__()
2854
2855 - def __cmp__(self, other):
2856 """ 2857 Definition of equals operator for this class. 2858 Lists within this class are "unordered" for equality comparisons. 2859 @param other: Other object to compare to. 2860 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 2861 """ 2862 if other is None: 2863 return 1 2864 if self.localPeers != other.localPeers: 2865 if self.localPeers < other.localPeers: 2866 return -1 2867 else: 2868 return 1 2869 if self.remotePeers != other.remotePeers: 2870 if self.remotePeers < other.remotePeers: 2871 return -1 2872 else: 2873 return 1 2874 return 0
2875
2876 - def hasPeers(self):
2877 """ 2878 Indicates whether any peers are filled into this object. 2879 @return: Boolean true if any local or remote peers are filled in, false otherwise. 2880 """ 2881 return ((self.localPeers is not None and len(self.localPeers) > 0) or 2882 (self.remotePeers is not None and len(self.remotePeers) > 0))
2883
2884 - def _setLocalPeers(self, value):
2885 """ 2886 Property target used to set the local peers list. 2887 Either the value must be C{None} or each element must be a C{LocalPeer}. 2888 @raise ValueError: If the value is not an absolute path. 2889 """ 2890 if value is None: 2891 self._localPeers = None 2892 else: 2893 try: 2894 saved = self._localPeers 2895 self._localPeers = ObjectTypeList(LocalPeer, "LocalPeer") 2896 self._localPeers.extend(value) 2897 except Exception, e: 2898 self._localPeers = saved 2899 raise e
2900
2901 - def _getLocalPeers(self):
2902 """ 2903 Property target used to get the local peers list. 2904 """ 2905 return self._localPeers
2906
2907 - def _setRemotePeers(self, value):
2908 """ 2909 Property target used to set the remote peers list. 2910 Either the value must be C{None} or each element must be a C{RemotePeer}. 2911 @raise ValueError: If the value is not a C{RemotePeer} 2912 """ 2913 if value is None: 2914 self._remotePeers = None 2915 else: 2916 try: 2917 saved = self._remotePeers 2918 self._remotePeers = ObjectTypeList(RemotePeer, "RemotePeer") 2919 self._remotePeers.extend(value) 2920 except Exception, e: 2921 self._remotePeers = saved 2922 raise e
2923
2924 - def _getRemotePeers(self):
2925 """ 2926 Property target used to get the remote peers list. 2927 """ 2928 return self._remotePeers
2929 2930 localPeers = property(_getLocalPeers, _setLocalPeers, None, "List of local peers.") 2931 remotePeers = property(_getRemotePeers, _setRemotePeers, None, "List of remote peers.")
2932
2933 2934 ######################################################################## 2935 # CollectConfig class definition 2936 ######################################################################## 2937 2938 -class CollectConfig(object):
2939 2940 """ 2941 Class representing a Cedar Backup collect configuration. 2942 2943 The following restrictions exist on data in this class: 2944 2945 - The target directory must be an absolute path. 2946 - The collect mode must be one of the values in L{VALID_COLLECT_MODES}. 2947 - The archive mode must be one of the values in L{VALID_ARCHIVE_MODES}. 2948 - The ignore file must be a non-empty string. 2949 - Each of the paths in C{absoluteExcludePaths} must be an absolute path 2950 - The collect file list must be a list of C{CollectFile} objects. 2951 - The collect directory list must be a list of C{CollectDir} objects. 2952 2953 For the C{absoluteExcludePaths} list, validation is accomplished through the 2954 L{util.AbsolutePathList} list implementation that overrides common list 2955 methods and transparently does the absolute path validation for us. 2956 2957 For the C{collectFiles} and C{collectDirs} list, validation is accomplished 2958 through the L{util.ObjectTypeList} list implementation that overrides common 2959 list methods and transparently ensures that each element has an appropriate 2960 type. 2961 2962 @note: Lists within this class are "unordered" for equality comparisons. 2963 2964 @sort: __init__, __repr__, __str__, __cmp__, targetDir, 2965 collectMode, archiveMode, ignoreFile, absoluteExcludePaths, 2966 excludePatterns, collectFiles, collectDirs 2967 """ 2968
2969 - def __init__(self, targetDir=None, collectMode=None, archiveMode=None, ignoreFile=None, 2970 absoluteExcludePaths=None, excludePatterns=None, collectFiles=None, 2971 collectDirs=None):
2972 """ 2973 Constructor for the C{CollectConfig} class. 2974 2975 @param targetDir: Directory to collect files into. 2976 @param collectMode: Default collect mode. 2977 @param archiveMode: Default archive mode for collect files. 2978 @param ignoreFile: Default ignore file name. 2979 @param absoluteExcludePaths: List of absolute paths to exclude. 2980 @param excludePatterns: List of regular expression patterns to exclude. 2981 @param collectFiles: List of collect files. 2982 @param collectDirs: List of collect directories. 2983 2984 @raise ValueError: If one of the values is invalid. 2985 """ 2986 self._targetDir = None 2987 self._collectMode = None 2988 self._archiveMode = None 2989 self._ignoreFile = None 2990 self._absoluteExcludePaths = None 2991 self._excludePatterns = None 2992 self._collectFiles = None 2993 self._collectDirs = None 2994 self.targetDir = targetDir 2995 self.collectMode = collectMode 2996 self.archiveMode = archiveMode 2997 self.ignoreFile = ignoreFile 2998 self.absoluteExcludePaths = absoluteExcludePaths 2999 self.excludePatterns = excludePatterns 3000 self.collectFiles = collectFiles 3001 self.collectDirs = collectDirs
3002
3003 - def __repr__(self):
3004 """ 3005 Official string representation for class instance. 3006 """ 3007 return "CollectConfig(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.targetDir, self.collectMode, self.archiveMode, 3008 self.ignoreFile, self.absoluteExcludePaths, 3009 self.excludePatterns, self.collectFiles, self.collectDirs)
3010
3011 - def __str__(self):
3012 """ 3013 Informal string representation for class instance. 3014 """ 3015 return self.__repr__()
3016
3017 - def __cmp__(self, other):
3018 """ 3019 Definition of equals operator for this class. 3020 Lists within this class are "unordered" for equality comparisons. 3021 @param other: Other object to compare to. 3022 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 3023 """ 3024 if other is None: 3025 return 1 3026 if self.targetDir != other.targetDir: 3027 if self.targetDir < other.targetDir: 3028 return -1 3029 else: 3030 return 1 3031 if self.collectMode != other.collectMode: 3032 if self.collectMode < other.collectMode: 3033 return -1 3034 else: 3035 return 1 3036 if self.archiveMode != other.archiveMode: 3037 if self.archiveMode < other.archiveMode: 3038 return -1 3039 else: 3040 return 1 3041 if self.ignoreFile != other.ignoreFile: 3042 if self.ignoreFile < other.ignoreFile: 3043 return -1 3044 else: 3045 return 1 3046 if self.absoluteExcludePaths != other.absoluteExcludePaths: 3047 if self.absoluteExcludePaths < other.absoluteExcludePaths: 3048 return -1 3049 else: 3050 return 1 3051 if self.excludePatterns != other.excludePatterns: 3052 if self.excludePatterns < other.excludePatterns: 3053 return -1 3054 else: 3055 return 1 3056 if self.collectFiles != other.collectFiles: 3057 if self.collectFiles < other.collectFiles: 3058 return -1 3059 else: 3060 return 1 3061 if self.collectDirs != other.collectDirs: 3062 if self.collectDirs < other.collectDirs: 3063 return -1 3064 else: 3065 return 1 3066 return 0
3067
3068 - def _setTargetDir(self, value):
3069 """ 3070 Property target used to set the target directory. 3071 The value must be an absolute path if it is not C{None}. 3072 It does not have to exist on disk at the time of assignment. 3073 @raise ValueError: If the value is not an absolute path. 3074 @raise ValueError: If the value cannot be encoded properly. 3075 """ 3076 if value is not None: 3077 if not os.path.isabs(value): 3078 raise ValueError("Target directory must be an absolute path.") 3079 self._targetDir = encodePath(value)
3080
3081 - def _getTargetDir(self):
3082 """ 3083 Property target used to get the target directory. 3084 """ 3085 return self._targetDir
3086
3087 - def _setCollectMode(self, value):
3088 """ 3089 Property target used to set the collect mode. 3090 If not C{None}, the mode must be one of L{VALID_COLLECT_MODES}. 3091 @raise ValueError: If the value is not valid. 3092 """ 3093 if value is not None: 3094 if value not in VALID_COLLECT_MODES: 3095 raise ValueError("Collect mode must be one of %s." % VALID_COLLECT_MODES) 3096 self._collectMode = value
3097
3098 - def _getCollectMode(self):
3099 """ 3100 Property target used to get the collect mode. 3101 """ 3102 return self._collectMode
3103
3104 - def _setArchiveMode(self, value):
3105 """ 3106 Property target used to set the archive mode. 3107 If not C{None}, the mode must be one of L{VALID_ARCHIVE_MODES}. 3108 @raise ValueError: If the value is not valid. 3109 """ 3110 if value is not None: 3111 if value not in VALID_ARCHIVE_MODES: 3112 raise ValueError("Archive mode must be one of %s." % VALID_ARCHIVE_MODES) 3113 self._archiveMode = value
3114
3115 - def _getArchiveMode(self):
3116 """ 3117 Property target used to get the archive mode. 3118 """ 3119 return self._archiveMode
3120
3121 - def _setIgnoreFile(self, value):
3122 """ 3123 Property target used to set the ignore file. 3124 The value must be a non-empty string if it is not C{None}. 3125 @raise ValueError: If the value is an empty string. 3126 @raise ValueError: If the value cannot be encoded properly. 3127 """ 3128 if value is not None: 3129 if len(value) < 1: 3130 raise ValueError("The ignore file must be a non-empty string.") 3131 self._ignoreFile = encodePath(value)
3132
3133 - def _getIgnoreFile(self):
3134 """ 3135 Property target used to get the ignore file. 3136 """ 3137 return self._ignoreFile
3138
3139 - def _setAbsoluteExcludePaths(self, value):
3140 """ 3141 Property target used to set the absolute exclude paths list. 3142 Either the value must be C{None} or each element must be an absolute path. 3143 Elements do not have to exist on disk at the time of assignment. 3144 @raise ValueError: If the value is not an absolute path. 3145 """ 3146 if value is None: 3147 self._absoluteExcludePaths = None 3148 else: 3149 try: 3150 saved = self._absoluteExcludePaths 3151 self._absoluteExcludePaths = AbsolutePathList() 3152 self._absoluteExcludePaths.extend(value) 3153 except Exception, e: 3154 self._absoluteExcludePaths = saved 3155 raise e
3156
3157 - def _getAbsoluteExcludePaths(self):
3158 """ 3159 Property target used to get the absolute exclude paths list. 3160 """ 3161 return self._absoluteExcludePaths
3162
3163 - def _setExcludePatterns(self, value):
3164 """ 3165 Property target used to set the exclude patterns list. 3166 """ 3167 if value is None: 3168 self._excludePatterns = None 3169 else: 3170 try: 3171 saved = self._excludePatterns 3172 self._excludePatterns = RegexList() 3173 self._excludePatterns.extend(value) 3174 except Exception, e: 3175 self._excludePatterns = saved 3176 raise e
3177
3178 - def _getExcludePatterns(self):
3179 """ 3180 Property target used to get the exclude patterns list. 3181 """ 3182 return self._excludePatterns
3183
3184 - def _setCollectFiles(self, value):
3185 """ 3186 Property target used to set the collect files list. 3187 Either the value must be C{None} or each element must be a C{CollectFile}. 3188 @raise ValueError: If the value is not a C{CollectFile} 3189 """ 3190 if value is None: 3191 self._collectFiles = None 3192 else: 3193 try: 3194 saved = self._collectFiles 3195 self._collectFiles = ObjectTypeList(CollectFile, "CollectFile") 3196 self._collectFiles.extend(value) 3197 except Exception, e: 3198 self._collectFiles = saved 3199 raise e
3200
3201 - def _getCollectFiles(self):
3202 """ 3203 Property target used to get the collect files list. 3204 """ 3205 return self._collectFiles
3206
3207 - def _setCollectDirs(self, value):
3208 """ 3209 Property target used to set the collect dirs list. 3210 Either the value must be C{None} or each element must be a C{CollectDir}. 3211 @raise ValueError: If the value is not a C{CollectDir} 3212 """ 3213 if value is None: 3214 self._collectDirs = None 3215 else: 3216 try: 3217 saved = self._collectDirs 3218 self._collectDirs = ObjectTypeList(CollectDir, "CollectDir") 3219 self._collectDirs.extend(value) 3220 except Exception, e: 3221 self._collectDirs = saved 3222 raise e
3223
3224 - def _getCollectDirs(self):
3225 """ 3226 Property target used to get the collect dirs list. 3227 """ 3228 return self._collectDirs
3229 3230 targetDir = property(_getTargetDir, _setTargetDir, None, "Directory to collect files into.") 3231 collectMode = property(_getCollectMode, _setCollectMode, None, "Default collect mode.") 3232 archiveMode = property(_getArchiveMode, _setArchiveMode, None, "Default archive mode for collect files.") 3233 ignoreFile = property(_getIgnoreFile, _setIgnoreFile, None, "Default ignore file name.") 3234 absoluteExcludePaths = property(_getAbsoluteExcludePaths, _setAbsoluteExcludePaths, None, "List of absolute paths to exclude.") 3235 excludePatterns = property(_getExcludePatterns, _setExcludePatterns, None, "List of regular expressions patterns to exclude.") 3236 collectFiles = property(_getCollectFiles, _setCollectFiles, None, "List of collect files.") 3237 collectDirs = property(_getCollectDirs, _setCollectDirs, None, "List of collect directories.")
3238
3239 3240 ######################################################################## 3241 # StageConfig class definition 3242 ######################################################################## 3243 3244 -class StageConfig(object):
3245 3246 """ 3247 Class representing a Cedar Backup stage configuration. 3248 3249 The following restrictions exist on data in this class: 3250 3251 - The target directory must be an absolute path 3252 - The list of local peers must contain only C{LocalPeer} objects 3253 - The list of remote peers must contain only C{RemotePeer} objects 3254 3255 @note: Lists within this class are "unordered" for equality comparisons. 3256 3257 @sort: __init__, __repr__, __str__, __cmp__, targetDir, localPeers, remotePeers 3258 """ 3259
3260 - def __init__(self, targetDir=None, localPeers=None, remotePeers=None):
3261 """ 3262 Constructor for the C{StageConfig} class. 3263 3264 @param targetDir: Directory to stage files into, by peer name. 3265 @param localPeers: List of local peers. 3266 @param remotePeers: List of remote peers. 3267 3268 @raise ValueError: If one of the values is invalid. 3269 """ 3270 self._targetDir = None 3271 self._localPeers = None 3272 self._remotePeers = None 3273 self.targetDir = targetDir 3274 self.localPeers = localPeers 3275 self.remotePeers = remotePeers
3276
3277 - def __repr__(self):
3278 """ 3279 Official string representation for class instance. 3280 """ 3281 return "StageConfig(%s, %s, %s)" % (self.targetDir, self.localPeers, self.remotePeers)
3282
3283 - def __str__(self):
3284 """ 3285 Informal string representation for class instance. 3286 """ 3287 return self.__repr__()
3288
3289 - def __cmp__(self, other):
3290 """ 3291 Definition of equals operator for this class. 3292 Lists within this class are "unordered" for equality comparisons. 3293 @param other: Other object to compare to. 3294 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 3295 """ 3296 if other is None: 3297 return 1 3298 if self.targetDir != other.targetDir: 3299 if self.targetDir < other.targetDir: 3300 return -1 3301 else: 3302 return 1 3303 if self.localPeers != other.localPeers: 3304 if self.localPeers < other.localPeers: 3305 return -1 3306 else: 3307 return 1 3308 if self.remotePeers != other.remotePeers: 3309 if self.remotePeers < other.remotePeers: 3310 return -1 3311 else: 3312 return 1 3313 return 0
3314
3315 - def hasPeers(self):
3316 """ 3317 Indicates whether any peers are filled into this object. 3318 @return: Boolean true if any local or remote peers are filled in, false otherwise. 3319 """ 3320 return ((self.localPeers is not None and len(self.localPeers) > 0) or 3321 (self.remotePeers is not None and len(self.remotePeers) > 0))
3322
3323 - def _setTargetDir(self, value):
3324 """ 3325 Property target used to set the target directory. 3326 The value must be an absolute path if it is not C{None}. 3327 It does not have to exist on disk at the time of assignment. 3328 @raise ValueError: If the value is not an absolute path. 3329 @raise ValueError: If the value cannot be encoded properly. 3330 """ 3331 if value is not None: 3332 if not os.path.isabs(value): 3333 raise ValueError("Target directory must be an absolute path.") 3334 self._targetDir = encodePath(value)
3335
3336 - def _getTargetDir(self):
3337 """ 3338 Property target used to get the target directory. 3339 """ 3340 return self._targetDir
3341
3342 - def _setLocalPeers(self, value):
3343 """ 3344 Property target used to set the local peers list. 3345 Either the value must be C{None} or each element must be a C{LocalPeer}. 3346 @raise ValueError: If the value is not an absolute path. 3347 """ 3348 if value is None: 3349 self._localPeers = None 3350 else: 3351 try: 3352 saved = self._localPeers 3353 self._localPeers = ObjectTypeList(LocalPeer, "LocalPeer") 3354 self._localPeers.extend(value) 3355 except Exception, e: 3356 self._localPeers = saved 3357 raise e
3358
3359 - def _getLocalPeers(self):
3360 """ 3361 Property target used to get the local peers list. 3362 """ 3363 return self._localPeers
3364
3365 - def _setRemotePeers(self, value):
3366 """ 3367 Property target used to set the remote peers list. 3368 Either the value must be C{None} or each element must be a C{RemotePeer}. 3369 @raise ValueError: If the value is not a C{RemotePeer} 3370 """ 3371 if value is None: 3372 self._remotePeers = None 3373 else: 3374 try: 3375 saved = self._remotePeers 3376 self._remotePeers = ObjectTypeList(RemotePeer, "RemotePeer") 3377 self._remotePeers.extend(value) 3378 except Exception, e: 3379 self._remotePeers = saved 3380 raise e
3381
3382 - def _getRemotePeers(self):
3383 """ 3384 Property target used to get the remote peers list. 3385 """ 3386 return self._remotePeers
3387 3388 targetDir = property(_getTargetDir, _setTargetDir, None, "Directory to stage files into, by peer name.") 3389 localPeers = property(_getLocalPeers, _setLocalPeers, None, "List of local peers.") 3390 remotePeers = property(_getRemotePeers, _setRemotePeers, None, "List of remote peers.")
3391
3392 3393 ######################################################################## 3394 # StoreConfig class definition 3395 ######################################################################## 3396 3397 -class StoreConfig(object):
3398 3399 """ 3400 Class representing a Cedar Backup store configuration. 3401 3402 The following restrictions exist on data in this class: 3403 3404 - The source directory must be an absolute path. 3405 - The media type must be one of the values in L{VALID_MEDIA_TYPES}. 3406 - The device type must be one of the values in L{VALID_DEVICE_TYPES}. 3407 - The device path must be an absolute path. 3408 - The SCSI id, if provided, must be in the form specified by L{validateScsiId}. 3409 - The drive speed must be an integer >= 1 3410 - The blanking behavior must be a C{BlankBehavior} object 3411 - The refresh media delay must be an integer >= 0 3412 - The eject delay must be an integer >= 0 3413 3414 Note that although the blanking factor must be a positive floating point 3415 number, it is stored as a string. This is done so that we can losslessly go 3416 back and forth between XML and object representations of configuration. 3417 3418 @sort: __init__, __repr__, __str__, __cmp__, sourceDir, 3419 mediaType, deviceType, devicePath, deviceScsiId, 3420 driveSpeed, checkData, checkMedia, warnMidnite, noEject, 3421 blankBehavior, refreshMediaDelay, ejectDelay 3422 """ 3423
3424 - def __init__(self, sourceDir=None, mediaType=None, deviceType=None, 3425 devicePath=None, deviceScsiId=None, driveSpeed=None, 3426 checkData=False, warnMidnite=False, noEject=False, 3427 checkMedia=False, blankBehavior=None, refreshMediaDelay=None, 3428 ejectDelay=None):
3429 """ 3430 Constructor for the C{StoreConfig} class. 3431 3432 @param sourceDir: Directory whose contents should be written to media. 3433 @param mediaType: Type of the media (see notes above). 3434 @param deviceType: Type of the device (optional, see notes above). 3435 @param devicePath: Filesystem device name for writer device, i.e. C{/dev/cdrw}. 3436 @param deviceScsiId: SCSI id for writer device, i.e. C{[<method>:]scsibus,target,lun}. 3437 @param driveSpeed: Speed of the drive, i.e. C{2} for 2x drive, etc. 3438 @param checkData: Whether resulting image should be validated. 3439 @param checkMedia: Whether media should be checked before being written to. 3440 @param warnMidnite: Whether to generate warnings for crossing midnite. 3441 @param noEject: Indicates that the writer device should not be ejected. 3442 @param blankBehavior: Controls optimized blanking behavior. 3443 @param refreshMediaDelay: Delay, in seconds, to add after refreshing media 3444 @param ejectDelay: Delay, in seconds, to add after ejecting media before closing the tray 3445 3446 @raise ValueError: If one of the values is invalid. 3447 """ 3448 self._sourceDir = None 3449 self._mediaType = None 3450 self._deviceType = None 3451 self._devicePath = None 3452 self._deviceScsiId = None 3453 self._driveSpeed = None 3454 self._checkData = None 3455 self._checkMedia = None 3456 self._warnMidnite = None 3457 self._noEject = None 3458 self._blankBehavior = None 3459 self._refreshMediaDelay = None 3460 self._ejectDelay = None 3461 self.sourceDir = sourceDir 3462 self.mediaType = mediaType 3463 self.deviceType = deviceType 3464 self.devicePath = devicePath 3465 self.deviceScsiId = deviceScsiId 3466 self.driveSpeed = driveSpeed 3467 self.checkData = checkData 3468 self.checkMedia = checkMedia 3469 self.warnMidnite = warnMidnite 3470 self.noEject = noEject 3471 self.blankBehavior = blankBehavior 3472 self.refreshMediaDelay = refreshMediaDelay 3473 self.ejectDelay = ejectDelay
3474
3475 - def __repr__(self):
3476 """ 3477 Official string representation for class instance. 3478 """ 3479 return "StoreConfig(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % ( 3480 self.sourceDir, self.mediaType, self.deviceType, 3481 self.devicePath, self.deviceScsiId, self.driveSpeed, 3482 self.checkData, self.warnMidnite, self.noEject, 3483 self.checkMedia, self.blankBehavior, self.refreshMediaDelay, 3484 self.ejectDelay)
3485
3486 - def __str__(self):
3487 """ 3488 Informal string representation for class instance. 3489 """ 3490 return self.__repr__()
3491
3492 - def __cmp__(self, other):
3493 """ 3494 Definition of equals operator for this class. 3495 @param other: Other object to compare to. 3496 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 3497 """ 3498 if other is None: 3499 return 1 3500 if self.sourceDir != other.sourceDir: 3501 if self.sourceDir < other.sourceDir: 3502 return -1 3503 else: 3504 return 1 3505 if self.mediaType != other.mediaType: 3506 if self.mediaType < other.mediaType: 3507 return -1 3508 else: 3509 return 1 3510 if self.deviceType != other.deviceType: 3511 if self.deviceType < other.deviceType: 3512 return -1 3513 else: 3514 return 1 3515 if self.devicePath != other.devicePath: 3516 if self.devicePath < other.devicePath: 3517 return -1 3518 else: 3519 return 1 3520 if self.deviceScsiId != other.deviceScsiId: 3521 if self.deviceScsiId < other.deviceScsiId: 3522 return -1 3523 else: 3524 return 1 3525 if self.driveSpeed != other.driveSpeed: 3526 if self.driveSpeed < other.driveSpeed: 3527 return -1 3528 else: 3529 return 1 3530 if self.checkData != other.checkData: 3531 if self.checkData < other.checkData: 3532 return -1 3533 else: 3534 return 1 3535 if self.checkMedia != other.checkMedia: 3536 if self.checkMedia < other.checkMedia: 3537 return -1 3538 else: 3539 return 1 3540 if self.warnMidnite != other.warnMidnite: 3541 if self.warnMidnite < other.warnMidnite: 3542 return -1 3543 else: 3544 return 1 3545 if self.noEject != other.noEject: 3546 if self.noEject < other.noEject: 3547 return -1 3548 else: 3549 return 1 3550 if self.blankBehavior != other.blankBehavior: 3551 if self.blankBehavior < other.blankBehavior: 3552 return -1 3553 else: 3554 return 1 3555 if self.refreshMediaDelay != other.refreshMediaDelay: 3556 if self.refreshMediaDelay < other.refreshMediaDelay: 3557 return -1 3558 else: 3559 return 1 3560 if self.ejectDelay != other.ejectDelay: 3561 if self.ejectDelay < other.ejectDelay: 3562 return -1 3563 else: 3564 return 1 3565 return 0
3566
3567 - def _setSourceDir(self, value):
3568 """ 3569 Property target used to set the source directory. 3570 The value must be an absolute path if it is not C{None}. 3571 It does not have to exist on disk at the time of assignment. 3572 @raise ValueError: If the value is not an absolute path. 3573 @raise ValueError: If the value cannot be encoded properly. 3574 """ 3575 if value is not None: 3576 if not os.path.isabs(value): 3577 raise ValueError("Source directory must be an absolute path.") 3578 self._sourceDir = encodePath(value)
3579
3580 - def _getSourceDir(self):
3581 """ 3582 Property target used to get the source directory. 3583 """ 3584 return self._sourceDir
3585
3586 - def _setMediaType(self, value):
3587 """ 3588 Property target used to set the media type. 3589 The value must be one of L{VALID_MEDIA_TYPES}. 3590 @raise ValueError: If the value is not valid. 3591 """ 3592 if value is not None: 3593 if value not in VALID_MEDIA_TYPES: 3594 raise ValueError("Media type must be one of %s." % VALID_MEDIA_TYPES) 3595 self._mediaType = value
3596
3597 - def _getMediaType(self):
3598 """ 3599 Property target used to get the media type. 3600 """ 3601 return self._mediaType
3602
3603 - def _setDeviceType(self, value):
3604 """ 3605 Property target used to set the device type. 3606 The value must be one of L{VALID_DEVICE_TYPES}. 3607 @raise ValueError: If the value is not valid. 3608 """ 3609 if value is not None: 3610 if value not in VALID_DEVICE_TYPES: 3611 raise ValueError("Device type must be one of %s." % VALID_DEVICE_TYPES) 3612 self._deviceType = value
3613
3614 - def _getDeviceType(self):
3615 """ 3616 Property target used to get the device type. 3617 """ 3618 return self._deviceType
3619
3620 - def _setDevicePath(self, value):
3621 """ 3622 Property target used to set the device path. 3623 The value must be an absolute path if it is not C{None}. 3624 It does not have to exist on disk at the time of assignment. 3625 @raise ValueError: If the value is not an absolute path. 3626 @raise ValueError: If the value cannot be encoded properly. 3627 """ 3628 if value is not None: 3629 if not os.path.isabs(value): 3630 raise ValueError("Device path must be an absolute path.") 3631 self._devicePath = encodePath(value)
3632
3633 - def _getDevicePath(self):
3634 """ 3635 Property target used to get the device path. 3636 """ 3637 return self._devicePath
3638
3639 - def _setDeviceScsiId(self, value):
3640 """ 3641 Property target used to set the SCSI id 3642 The SCSI id must be valid per L{validateScsiId}. 3643 @raise ValueError: If the value is not valid. 3644 """ 3645 if value is None: 3646 self._deviceScsiId = None 3647 else: 3648 self._deviceScsiId = validateScsiId(value)
3649
3650 - def _getDeviceScsiId(self):
3651 """ 3652 Property target used to get the SCSI id. 3653 """ 3654 return self._deviceScsiId
3655
3656 - def _setDriveSpeed(self, value):
3657 """ 3658 Property target used to set the drive speed. 3659 The drive speed must be valid per L{validateDriveSpeed}. 3660 @raise ValueError: If the value is not valid. 3661 """ 3662 self._driveSpeed = validateDriveSpeed(value)
3663
3664 - def _getDriveSpeed(self):
3665 """ 3666 Property target used to get the drive speed. 3667 """ 3668 return self._driveSpeed
3669
3670 - def _setCheckData(self, value):
3671 """ 3672 Property target used to set the check data flag. 3673 No validations, but we normalize the value to C{True} or C{False}. 3674 """ 3675 if value: 3676 self._checkData = True 3677 else: 3678 self._checkData = False
3679
3680 - def _getCheckData(self):
3681 """ 3682 Property target used to get the check data flag. 3683 """ 3684 return self._checkData
3685
3686 - def _setCheckMedia(self, value):
3687 """ 3688 Property target used to set the check media flag. 3689 No validations, but we normalize the value to C{True} or C{False}. 3690 """ 3691 if value: 3692 self._checkMedia = True 3693 else: 3694 self._checkMedia = False
3695
3696 - def _getCheckMedia(self):
3697 """ 3698 Property target used to get the check media flag. 3699 """ 3700 return self._checkMedia
3701
3702 - def _setWarnMidnite(self, value):
3703 """ 3704 Property target used to set the midnite warning flag. 3705 No validations, but we normalize the value to C{True} or C{False}. 3706 """ 3707 if value: 3708 self._warnMidnite = True 3709 else: 3710 self._warnMidnite = False
3711
3712 - def _getWarnMidnite(self):
3713 """ 3714 Property target used to get the midnite warning flag. 3715 """ 3716 return self._warnMidnite
3717
3718 - def _setNoEject(self, value):
3719 """ 3720 Property target used to set the no-eject flag. 3721 No validations, but we normalize the value to C{True} or C{False}. 3722 """ 3723 if value: 3724 self._noEject = True 3725 else: 3726 self._noEject = False
3727
3728 - def _getNoEject(self):
3729 """ 3730 Property target used to get the no-eject flag. 3731 """ 3732 return self._noEject
3733
3734 - def _setBlankBehavior(self, value):
3735 """ 3736 Property target used to set blanking behavior configuration. 3737 If not C{None}, the value must be a C{BlankBehavior} object. 3738 @raise ValueError: If the value is not a C{BlankBehavior} 3739 """ 3740 if value is None: 3741 self._blankBehavior = None 3742 else: 3743 if not isinstance(value, BlankBehavior): 3744 raise ValueError("Value must be a C{BlankBehavior} object.") 3745 self._blankBehavior = value
3746
3747 - def _getBlankBehavior(self):
3748 """ 3749 Property target used to get the blanking behavior configuration. 3750 """ 3751 return self._blankBehavior
3752
3753 - def _setRefreshMediaDelay(self, value):
3754 """ 3755 Property target used to set the refreshMediaDelay. 3756 The value must be an integer >= 0. 3757 @raise ValueError: If the value is not valid. 3758 """ 3759 if value is None: 3760 self._refreshMediaDelay = None 3761 else: 3762 try: 3763 value = int(value) 3764 except TypeError: 3765 raise ValueError("Action refreshMediaDelay value must be an integer >= 0.") 3766 if value < 0: 3767 raise ValueError("Action refreshMediaDelay value must be an integer >= 0.") 3768 if value == 0: 3769 value = None # normalize this out, since it's the default 3770 self._refreshMediaDelay = value
3771
3772 - def _getRefreshMediaDelay(self):
3773 """ 3774 Property target used to get the action refreshMediaDelay. 3775 """ 3776 return self._refreshMediaDelay
3777
3778 - def _setEjectDelay(self, value):
3779 """ 3780 Property target used to set the ejectDelay. 3781 The value must be an integer >= 0. 3782 @raise ValueError: If the value is not valid. 3783 """ 3784 if value is None: 3785 self._ejectDelay = None 3786 else: 3787 try: 3788 value = int(value) 3789 except TypeError: 3790 raise ValueError("Action ejectDelay value must be an integer >= 0.") 3791 if value < 0: 3792 raise ValueError("Action ejectDelay value must be an integer >= 0.") 3793 if value == 0: 3794 value = None # normalize this out, since it's the default 3795 self._ejectDelay = value
3796
3797 - def _getEjectDelay(self):
3798 """ 3799 Property target used to get the action ejectDelay. 3800 """ 3801 return self._ejectDelay
3802 3803 sourceDir = property(_getSourceDir, _setSourceDir, None, "Directory whose contents should be written to media.") 3804 mediaType = property(_getMediaType, _setMediaType, None, "Type of the media (see notes above).") 3805 deviceType = property(_getDeviceType, _setDeviceType, None, "Type of the device (optional, see notes above).") 3806 devicePath = property(_getDevicePath, _setDevicePath, None, "Filesystem device name for writer device.") 3807 deviceScsiId = property(_getDeviceScsiId, _setDeviceScsiId, None, "SCSI id for writer device (optional, see notes above).") 3808 driveSpeed = property(_getDriveSpeed, _setDriveSpeed, None, "Speed of the drive.") 3809 checkData = property(_getCheckData, _setCheckData, None, "Whether resulting image should be validated.") 3810 checkMedia = property(_getCheckMedia, _setCheckMedia, None, "Whether media should be checked before being written to.") 3811 warnMidnite = property(_getWarnMidnite, _setWarnMidnite, None, "Whether to generate warnings for crossing midnite.") 3812 noEject = property(_getNoEject, _setNoEject, None, "Indicates that the writer device should not be ejected.") 3813 blankBehavior = property(_getBlankBehavior, _setBlankBehavior, None, "Controls optimized blanking behavior.") 3814 refreshMediaDelay = property(_getRefreshMediaDelay, _setRefreshMediaDelay, None, "Delay, in seconds, to add after refreshing media.") 3815 ejectDelay = property(_getEjectDelay, _setEjectDelay, None, "Delay, in seconds, to add after ejecting media before closing the tray")
3816
3817 3818 ######################################################################## 3819 # PurgeConfig class definition 3820 ######################################################################## 3821 3822 -class PurgeConfig(object):
3823 3824 """ 3825 Class representing a Cedar Backup purge configuration. 3826 3827 The following restrictions exist on data in this class: 3828 3829 - The purge directory list must be a list of C{PurgeDir} objects. 3830 3831 For the C{purgeDirs} list, validation is accomplished through the 3832 L{util.ObjectTypeList} list implementation that overrides common list 3833 methods and transparently ensures that each element is a C{PurgeDir}. 3834 3835 @note: Lists within this class are "unordered" for equality comparisons. 3836 3837 @sort: __init__, __repr__, __str__, __cmp__, purgeDirs 3838 """ 3839
3840 - def __init__(self, purgeDirs=None):
3841 """ 3842 Constructor for the C{Purge} class. 3843 @param purgeDirs: List of purge directories. 3844 @raise ValueError: If one of the values is invalid. 3845 """ 3846 self._purgeDirs = None 3847 self.purgeDirs = purgeDirs
3848
3849 - def __repr__(self):
3850 """ 3851 Official string representation for class instance. 3852 """ 3853 return "PurgeConfig(%s)" % self.purgeDirs
3854
3855 - def __str__(self):
3856 """ 3857 Informal string representation for class instance. 3858 """ 3859 return self.__repr__()
3860
3861 - def __cmp__(self, other):
3862 """ 3863 Definition of equals operator for this class. 3864 Lists within this class are "unordered" for equality comparisons. 3865 @param other: Other object to compare to. 3866 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 3867 """ 3868 if other is None: 3869 return 1 3870 if self.purgeDirs != other.purgeDirs: 3871 if self.purgeDirs < other.purgeDirs: 3872 return -1 3873 else: 3874 return 1 3875 return 0
3876
3877 - def _setPurgeDirs(self, value):
3878 """ 3879 Property target used to set the purge dirs list. 3880 Either the value must be C{None} or each element must be a C{PurgeDir}. 3881 @raise ValueError: If the value is not a C{PurgeDir} 3882 """ 3883 if value is None: 3884 self._purgeDirs = None 3885 else: 3886 try: 3887 saved = self._purgeDirs 3888 self._purgeDirs = ObjectTypeList(PurgeDir, "PurgeDir") 3889 self._purgeDirs.extend(value) 3890 except Exception, e: 3891 self._purgeDirs = saved 3892 raise e
3893
3894 - def _getPurgeDirs(self):
3895 """ 3896 Property target used to get the purge dirs list. 3897 """ 3898 return self._purgeDirs
3899 3900 purgeDirs = property(_getPurgeDirs, _setPurgeDirs, None, "List of directories to purge.")
3901
3902 3903 ######################################################################## 3904 # Config class definition 3905 ######################################################################## 3906 3907 -class Config(object):
3908 3909 ###################### 3910 # Class documentation 3911 ###################### 3912 3913 """ 3914 Class representing a Cedar Backup XML configuration document. 3915 3916 The C{Config} class is a Python object representation of a Cedar Backup XML 3917 configuration file. It is intended to be the only Python-language interface 3918 to Cedar Backup configuration on disk for both Cedar Backup itself and for 3919 external applications. 3920 3921 The object representation is two-way: XML data can be used to create a 3922 C{Config} object, and then changes to the object can be propogated back to 3923 disk. A C{Config} object can even be used to create a configuration file 3924 from scratch programmatically. 3925 3926 This class and the classes it is composed from often use Python's 3927 C{property} construct to validate input and limit access to values. Some 3928 validations can only be done once a document is considered "complete" 3929 (see module notes for more details). 3930 3931 Assignments to the various instance variables must match the expected 3932 type, i.e. C{reference} must be a C{ReferenceConfig}. The internal check 3933 uses the built-in C{isinstance} function, so it should be OK to use 3934 subclasses if you want to. 3935 3936 If an instance variable is not set, its value will be C{None}. When an 3937 object is initialized without using an XML document, all of the values 3938 will be C{None}. Even when an object is initialized using XML, some of 3939 the values might be C{None} because not every section is required. 3940 3941 @note: Lists within this class are "unordered" for equality comparisons. 3942 3943 @sort: __init__, __repr__, __str__, __cmp__, extractXml, validate, 3944 reference, extensions, options, collect, stage, store, purge, 3945 _getReference, _setReference, _getExtensions, _setExtensions, 3946 _getOptions, _setOptions, _getPeers, _setPeers, _getCollect, 3947 _setCollect, _getStage, _setStage, _getStore, _setStore, 3948 _getPurge, _setPurge 3949 """ 3950 3951 ############## 3952 # Constructor 3953 ############## 3954
3955 - def __init__(self, xmlData=None, xmlPath=None, validate=True):
3956 """ 3957 Initializes a configuration object. 3958 3959 If you initialize the object without passing either C{xmlData} or 3960 C{xmlPath}, then configuration will be empty and will be invalid until it 3961 is filled in properly. 3962 3963 No reference to the original XML data or original path is saved off by 3964 this class. Once the data has been parsed (successfully or not) this 3965 original information is discarded. 3966 3967 Unless the C{validate} argument is C{False}, the L{Config.validate} 3968 method will be called (with its default arguments) against configuration 3969 after successfully parsing any passed-in XML. Keep in mind that even if 3970 C{validate} is C{False}, it might not be possible to parse the passed-in 3971 XML document if lower-level validations fail. 3972 3973 @note: It is strongly suggested that the C{validate} option always be set 3974 to C{True} (the default) unless there is a specific need to read in 3975 invalid configuration from disk. 3976 3977 @param xmlData: XML data representing configuration. 3978 @type xmlData: String data. 3979 3980 @param xmlPath: Path to an XML file on disk. 3981 @type xmlPath: Absolute path to a file on disk. 3982 3983 @param validate: Validate the document after parsing it. 3984 @type validate: Boolean true/false. 3985 3986 @raise ValueError: If both C{xmlData} and C{xmlPath} are passed-in. 3987 @raise ValueError: If the XML data in C{xmlData} or C{xmlPath} cannot be parsed. 3988 @raise ValueError: If the parsed configuration document is not valid. 3989 """ 3990 self._reference = None 3991 self._extensions = None 3992 self._options = None 3993 self._peers = None 3994 self._collect = None 3995 self._stage = None 3996 self._store = None 3997 self._purge = None 3998 self.reference = None 3999 self.extensions = None 4000 self.options = None 4001 self.peers = None 4002 self.collect = None 4003 self.stage = None 4004 self.store = None 4005 self.purge = None 4006 if xmlData is not None and xmlPath is not None: 4007 raise ValueError("Use either xmlData or xmlPath, but not both.") 4008 if xmlData is not None: 4009 self._parseXmlData(xmlData) 4010 if validate: 4011 self.validate() 4012 elif xmlPath is not None: 4013 xmlData = open(xmlPath).read() 4014 self._parseXmlData(xmlData) 4015 if validate: 4016 self.validate()
4017 4018 4019 ######################### 4020 # String representations 4021 ######################### 4022
4023 - def __repr__(self):
4024 """ 4025 Official string representation for class instance. 4026 """ 4027 return "Config(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.reference, self.extensions, self.options, 4028 self.peers, self.collect, self.stage, self.store, 4029 self.purge)
4030
4031 - def __str__(self):
4032 """ 4033 Informal string representation for class instance. 4034 """ 4035 return self.__repr__()
4036 4037 4038 ############################# 4039 # Standard comparison method 4040 ############################# 4041
4042 - def __cmp__(self, other):
4043 """ 4044 Definition of equals operator for this class. 4045 Lists within this class are "unordered" for equality comparisons. 4046 @param other: Other object to compare to. 4047 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 4048 """ 4049 if other is None: 4050 return 1 4051 if self.reference != other.reference: 4052 if self.reference < other.reference: 4053 return -1 4054 else: 4055 return 1 4056 if self.extensions != other.extensions: 4057 if self.extensions < other.extensions: 4058 return -1 4059 else: 4060 return 1 4061 if self.options != other.options: 4062 if self.options < other.options: 4063 return -1 4064 else: 4065 return 1 4066 if self.peers != other.peers: 4067 if self.peers < other.peers: 4068 return -1 4069 else: 4070 return 1 4071 if self.collect != other.collect: 4072 if self.collect < other.collect: 4073 return -1 4074 else: 4075 return 1 4076 if self.stage != other.stage: 4077 if self.stage < other.stage: 4078 return -1 4079 else: 4080 return 1 4081 if self.store != other.store: 4082 if self.store < other.store: 4083 return -1 4084 else: 4085 return 1 4086 if self.purge != other.purge: 4087 if self.purge < other.purge: 4088 return -1 4089 else: 4090 return 1 4091 return 0
4092 4093 4094 ############# 4095 # Properties 4096 ############# 4097
4098 - def _setReference(self, value):
4099 """ 4100 Property target used to set the reference configuration value. 4101 If not C{None}, the value must be a C{ReferenceConfig} object. 4102 @raise ValueError: If the value is not a C{ReferenceConfig} 4103 """ 4104 if value is None: 4105 self._reference = None 4106 else: 4107 if not isinstance(value, ReferenceConfig): 4108 raise ValueError("Value must be a C{ReferenceConfig} object.") 4109 self._reference = value
4110
4111 - def _getReference(self):
4112 """ 4113 Property target used to get the reference configuration value. 4114 """ 4115 return self._reference
4116
4117 - def _setExtensions(self, value):
4118 """ 4119 Property target used to set the extensions configuration value. 4120 If not C{None}, the value must be a C{ExtensionsConfig} object. 4121 @raise ValueError: If the value is not a C{ExtensionsConfig} 4122 """ 4123 if value is None: 4124 self._extensions = None 4125 else: 4126 if not isinstance(value, ExtensionsConfig): 4127 raise ValueError("Value must be a C{ExtensionsConfig} object.") 4128 self._extensions = value
4129
4130 - def _getExtensions(self):
4131 """ 4132 Property target used to get the extensions configuration value. 4133 """ 4134 return self._extensions
4135
4136 - def _setOptions(self, value):
4137 """ 4138 Property target used to set the options configuration value. 4139 If not C{None}, the value must be an C{OptionsConfig} object. 4140 @raise ValueError: If the value is not a C{OptionsConfig} 4141 """ 4142 if value is None: 4143 self._options = None 4144 else: 4145 if not isinstance(value, OptionsConfig): 4146 raise ValueError("Value must be a C{OptionsConfig} object.") 4147 self._options = value
4148
4149 - def _getOptions(self):
4150 """ 4151 Property target used to get the options configuration value. 4152 """ 4153 return self._options
4154
4155 - def _setPeers(self, value):
4156 """ 4157 Property target used to set the peers configuration value. 4158 If not C{None}, the value must be an C{PeersConfig} object. 4159 @raise ValueError: If the value is not a C{PeersConfig} 4160 """ 4161 if value is None: 4162 self._peers = None 4163 else: 4164 if not isinstance(value, PeersConfig): 4165 raise ValueError("Value must be a C{PeersConfig} object.") 4166 self._peers = value
4167
4168 - def _getPeers(self):
4169 """ 4170 Property target used to get the peers configuration value. 4171 """ 4172 return self._peers
4173
4174 - def _setCollect(self, value):
4175 """ 4176 Property target used to set the collect configuration value. 4177 If not C{None}, the value must be a C{CollectConfig} object. 4178 @raise ValueError: If the value is not a C{CollectConfig} 4179 """ 4180 if value is None: 4181 self._collect = None 4182 else: 4183 if not isinstance(value, CollectConfig): 4184 raise ValueError("Value must be a C{CollectConfig} object.") 4185 self._collect = value
4186
4187 - def _getCollect(self):
4188 """ 4189 Property target used to get the collect configuration value. 4190 """ 4191 return self._collect
4192
4193 - def _setStage(self, value):
4194 """ 4195 Property target used to set the stage configuration value. 4196 If not C{None}, the value must be a C{StageConfig} object. 4197 @raise ValueError: If the value is not a C{StageConfig} 4198 """ 4199 if value is None: 4200 self._stage = None 4201 else: 4202 if not isinstance(value, StageConfig): 4203 raise ValueError("Value must be a C{StageConfig} object.") 4204 self._stage = value
4205
4206 - def _getStage(self):
4207 """ 4208 Property target used to get the stage configuration value. 4209 """ 4210 return self._stage
4211
4212 - def _setStore(self, value):
4213 """ 4214 Property target used to set the store configuration value. 4215 If not C{None}, the value must be a C{StoreConfig} object. 4216 @raise ValueError: If the value is not a C{StoreConfig} 4217 """ 4218 if value is None: 4219 self._store = None 4220 else: 4221 if not isinstance(value, StoreConfig): 4222 raise ValueError("Value must be a C{StoreConfig} object.") 4223 self._store = value
4224
4225 - def _getStore(self):
4226 """ 4227 Property target used to get the store configuration value. 4228 """ 4229 return self._store
4230
4231 - def _setPurge(self, value):
4232 """ 4233 Property target used to set the purge configuration value. 4234 If not C{None}, the value must be a C{PurgeConfig} object. 4235 @raise ValueError: If the value is not a C{PurgeConfig} 4236 """ 4237 if value is None: 4238 self._purge = None 4239 else: 4240 if not isinstance(value, PurgeConfig): 4241 raise ValueError("Value must be a C{PurgeConfig} object.") 4242 self._purge = value
4243
4244 - def _getPurge(self):
4245 """ 4246 Property target used to get the purge configuration value. 4247 """ 4248 return self._purge
4249 4250 reference = property(_getReference, _setReference, None, "Reference configuration in terms of a C{ReferenceConfig} object.") 4251 extensions = property(_getExtensions, _setExtensions, None, "Extensions configuration in terms of a C{ExtensionsConfig} object.") 4252 options = property(_getOptions, _setOptions, None, "Options configuration in terms of a C{OptionsConfig} object.") 4253 peers = property(_getPeers, _setPeers, None, "Peers configuration in terms of a C{PeersConfig} object.") 4254 collect = property(_getCollect, _setCollect, None, "Collect configuration in terms of a C{CollectConfig} object.") 4255 stage = property(_getStage, _setStage, None, "Stage configuration in terms of a C{StageConfig} object.") 4256 store = property(_getStore, _setStore, None, "Store configuration in terms of a C{StoreConfig} object.") 4257 purge = property(_getPurge, _setPurge, None, "Purge configuration in terms of a C{PurgeConfig} object.") 4258 4259 4260 ################# 4261 # Public methods 4262 ################# 4263
4264 - def extractXml(self, xmlPath=None, validate=True):
4265 """ 4266 Extracts configuration into an XML document. 4267 4268 If C{xmlPath} is not provided, then the XML document will be returned as 4269 a string. If C{xmlPath} is provided, then the XML document will be written 4270 to the file and C{None} will be returned. 4271 4272 Unless the C{validate} parameter is C{False}, the L{Config.validate} 4273 method will be called (with its default arguments) against the 4274 configuration before extracting the XML. If configuration is not valid, 4275 then an XML document will not be extracted. 4276 4277 @note: It is strongly suggested that the C{validate} option always be set 4278 to C{True} (the default) unless there is a specific need to write an 4279 invalid configuration file to disk. 4280 4281 @param xmlPath: Path to an XML file to create on disk. 4282 @type xmlPath: Absolute path to a file. 4283 4284 @param validate: Validate the document before extracting it. 4285 @type validate: Boolean true/false. 4286 4287 @return: XML string data or C{None} as described above. 4288 4289 @raise ValueError: If configuration within the object is not valid. 4290 @raise IOError: If there is an error writing to the file. 4291 @raise OSError: If there is an error writing to the file. 4292 """ 4293 if validate: 4294 self.validate() 4295 xmlData = self._extractXml() 4296 if xmlPath is not None: 4297 open(xmlPath, "w").write(xmlData) 4298 return None 4299 else: 4300 return xmlData
4301
4302 - def validate(self, requireOneAction=True, requireReference=False, requireExtensions=False, requireOptions=True, 4303 requireCollect=False, requireStage=False, requireStore=False, requirePurge=False, requirePeers=False):
4304 """ 4305 Validates configuration represented by the object. 4306 4307 This method encapsulates all of the validations that should apply to a 4308 fully "complete" document but are not already taken care of by earlier 4309 validations. It also provides some extra convenience functionality which 4310 might be useful to some people. The process of validation is laid out in 4311 the I{Validation} section in the class notes (above). 4312 4313 @param requireOneAction: Require at least one of the collect, stage, store or purge sections. 4314 @param requireReference: Require the reference section. 4315 @param requireExtensions: Require the extensions section. 4316 @param requireOptions: Require the options section. 4317 @param requirePeers: Require the peers section. 4318 @param requireCollect: Require the collect section. 4319 @param requireStage: Require the stage section. 4320 @param requireStore: Require the store section. 4321 @param requirePurge: Require the purge section. 4322 4323 @raise ValueError: If one of the validations fails. 4324 """ 4325 if requireOneAction and (self.collect, self.stage, self.store, self.purge) == (None, None, None, None): 4326 raise ValueError("At least one of the collect, stage, store and purge sections is required.") 4327 if requireReference and self.reference is None: 4328 raise ValueError("The reference is section is required.") 4329 if requireExtensions and self.extensions is None: 4330 raise ValueError("The extensions is section is required.") 4331 if requireOptions and self.options is None: 4332 raise ValueError("The options is section is required.") 4333 if requirePeers and self.peers is None: 4334 raise ValueError("The peers is section is required.") 4335 if requireCollect and self.collect is None: 4336 raise ValueError("The collect is section is required.") 4337 if requireStage and self.stage is None: 4338 raise ValueError("The stage is section is required.") 4339 if requireStore and self.store is None: 4340 raise ValueError("The store is section is required.") 4341 if requirePurge and self.purge is None: 4342 raise ValueError("The purge is section is required.") 4343 self._validateContents()
4344 4345 4346 ##################################### 4347 # High-level methods for parsing XML 4348 ##################################### 4349
4350 - def _parseXmlData(self, xmlData):
4351 """ 4352 Internal method to parse an XML string into the object. 4353 4354 This method parses the XML document into a DOM tree (C{xmlDom}) and then 4355 calls individual static methods to parse each of the individual 4356 configuration sections. 4357 4358 Most of the validation we do here has to do with whether the document can 4359 be parsed and whether any values which exist are valid. We don't do much 4360 validation as to whether required elements actually exist unless we have 4361 to to make sense of the document (instead, that's the job of the 4362 L{validate} method). 4363 4364 @param xmlData: XML data to be parsed 4365 @type xmlData: String data 4366 4367 @raise ValueError: If the XML cannot be successfully parsed. 4368 """ 4369 (xmlDom, parentNode) = createInputDom(xmlData) 4370 self._reference = Config._parseReference(parentNode) 4371 self._extensions = Config._parseExtensions(parentNode) 4372 self._options = Config._parseOptions(parentNode) 4373 self._peers = Config._parsePeers(parentNode) 4374 self._collect = Config._parseCollect(parentNode) 4375 self._stage = Config._parseStage(parentNode) 4376 self._store = Config._parseStore(parentNode) 4377 self._purge = Config._parsePurge(parentNode)
4378 4379 @staticmethod
4380 - def _parseReference(parentNode):
4381 """ 4382 Parses a reference configuration section. 4383 4384 We read the following fields:: 4385 4386 author //cb_config/reference/author 4387 revision //cb_config/reference/revision 4388 description //cb_config/reference/description 4389 generator //cb_config/reference/generator 4390 4391 @param parentNode: Parent node to search beneath. 4392 4393 @return: C{ReferenceConfig} object or C{None} if the section does not exist. 4394 @raise ValueError: If some filled-in value is invalid. 4395 """ 4396 reference = None 4397 sectionNode = readFirstChild(parentNode, "reference") 4398 if sectionNode is not None: 4399 reference = ReferenceConfig() 4400 reference.author = readString(sectionNode, "author") 4401 reference.revision = readString(sectionNode, "revision") 4402 reference.description = readString(sectionNode, "description") 4403 reference.generator = readString(sectionNode, "generator") 4404 return reference
4405 4406 @staticmethod
4407 - def _parseExtensions(parentNode):
4408 """ 4409 Parses an extensions configuration section. 4410 4411 We read the following fields:: 4412 4413 orderMode //cb_config/extensions/order_mode 4414 4415 We also read groups of the following items, one list element per item:: 4416 4417 name //cb_config/extensions/action/name 4418 module //cb_config/extensions/action/module 4419 function //cb_config/extensions/action/function 4420 index //cb_config/extensions/action/index 4421 dependencies //cb_config/extensions/action/depends 4422 4423 The extended actions are parsed by L{_parseExtendedActions}. 4424 4425 @param parentNode: Parent node to search beneath. 4426 4427 @return: C{ExtensionsConfig} object or C{None} if the section does not exist. 4428 @raise ValueError: If some filled-in value is invalid. 4429 """ 4430 extensions = None 4431 sectionNode = readFirstChild(parentNode, "extensions") 4432 if sectionNode is not None: 4433 extensions = ExtensionsConfig() 4434 extensions.orderMode = readString(sectionNode, "order_mode") 4435 extensions.actions = Config._parseExtendedActions(sectionNode) 4436 return extensions
4437 4438 @staticmethod
4439 - def _parseOptions(parentNode):
4440 """ 4441 Parses a options configuration section. 4442 4443 We read the following fields:: 4444 4445 startingDay //cb_config/options/starting_day 4446 workingDir //cb_config/options/working_dir 4447 backupUser //cb_config/options/backup_user 4448 backupGroup //cb_config/options/backup_group 4449 rcpCommand //cb_config/options/rcp_command 4450 rshCommand //cb_config/options/rsh_command 4451 cbackCommand //cb_config/options/cback_command 4452 managedActions //cb_config/options/managed_actions 4453 4454 The list of managed actions is a comma-separated list of action names. 4455 4456 We also read groups of the following items, one list element per 4457 item:: 4458 4459 overrides //cb_config/options/override 4460 hooks //cb_config/options/hook 4461 4462 The overrides are parsed by L{_parseOverrides} and the hooks are parsed 4463 by L{_parseHooks}. 4464 4465 @param parentNode: Parent node to search beneath. 4466 4467 @return: C{OptionsConfig} object or C{None} if the section does not exist. 4468 @raise ValueError: If some filled-in value is invalid. 4469 """ 4470 options = None 4471 sectionNode = readFirstChild(parentNode, "options") 4472 if sectionNode is not None: 4473 options = OptionsConfig() 4474 options.startingDay = readString(sectionNode, "starting_day") 4475 options.workingDir = readString(sectionNode, "working_dir") 4476 options.backupUser = readString(sectionNode, "backup_user") 4477 options.backupGroup = readString(sectionNode, "backup_group") 4478 options.rcpCommand = readString(sectionNode, "rcp_command") 4479 options.rshCommand = readString(sectionNode, "rsh_command") 4480 options.cbackCommand = readString(sectionNode, "cback_command") 4481 options.overrides = Config._parseOverrides(sectionNode) 4482 options.hooks = Config._parseHooks(sectionNode) 4483 managedActions = readString(sectionNode, "managed_actions") 4484 options.managedActions = parseCommaSeparatedString(managedActions) 4485 return options
4486 4487 @staticmethod
4488 - def _parsePeers(parentNode):
4489 """ 4490 Parses a peers configuration section. 4491 4492 We read groups of the following items, one list element per 4493 item:: 4494 4495 localPeers //cb_config/stage/peer 4496 remotePeers //cb_config/stage/peer 4497 4498 The individual peer entries are parsed by L{_parsePeerList}. 4499 4500 @param parentNode: Parent node to search beneath. 4501 4502 @return: C{StageConfig} object or C{None} if the section does not exist. 4503 @raise ValueError: If some filled-in value is invalid. 4504 """ 4505 peers = None 4506 sectionNode = readFirstChild(parentNode, "peers") 4507 if sectionNode is not None: 4508 peers = PeersConfig() 4509 (peers.localPeers, peers.remotePeers) = Config._parsePeerList(sectionNode) 4510 return peers
4511 4512 @staticmethod
4513 - def _parseCollect(parentNode):
4514 """ 4515 Parses a collect configuration section. 4516 4517 We read the following individual fields:: 4518 4519 targetDir //cb_config/collect/collect_dir 4520 collectMode //cb_config/collect/collect_mode 4521 archiveMode //cb_config/collect/archive_mode 4522 ignoreFile //cb_config/collect/ignore_file 4523 4524 We also read groups of the following items, one list element per 4525 item:: 4526 4527 absoluteExcludePaths //cb_config/collect/exclude/abs_path 4528 excludePatterns //cb_config/collect/exclude/pattern 4529 collectFiles //cb_config/collect/file 4530 collectDirs //cb_config/collect/dir 4531 4532 The exclusions are parsed by L{_parseExclusions}, the collect files are 4533 parsed by L{_parseCollectFiles}, and the directories are parsed by 4534 L{_parseCollectDirs}. 4535 4536 @param parentNode: Parent node to search beneath. 4537 4538 @return: C{CollectConfig} object or C{None} if the section does not exist. 4539 @raise ValueError: If some filled-in value is invalid. 4540 """ 4541 collect = None 4542 sectionNode = readFirstChild(parentNode, "collect") 4543 if sectionNode is not None: 4544 collect = CollectConfig() 4545 collect.targetDir = readString(sectionNode, "collect_dir") 4546 collect.collectMode = readString(sectionNode, "collect_mode") 4547 collect.archiveMode = readString(sectionNode, "archive_mode") 4548 collect.ignoreFile = readString(sectionNode, "ignore_file") 4549 (collect.absoluteExcludePaths, unused, collect.excludePatterns) = Config._parseExclusions(sectionNode) 4550 collect.collectFiles = Config._parseCollectFiles(sectionNode) 4551 collect.collectDirs = Config._parseCollectDirs(sectionNode) 4552 return collect
4553 4554 @staticmethod
4555 - def _parseStage(parentNode):
4556 """ 4557 Parses a stage configuration section. 4558 4559 We read the following individual fields:: 4560 4561 targetDir //cb_config/stage/staging_dir 4562 4563 We also read groups of the following items, one list element per 4564 item:: 4565 4566 localPeers //cb_config/stage/peer 4567 remotePeers //cb_config/stage/peer 4568 4569 The individual peer entries are parsed by L{_parsePeerList}. 4570 4571 @param parentNode: Parent node to search beneath. 4572 4573 @return: C{StageConfig} object or C{None} if the section does not exist. 4574 @raise ValueError: If some filled-in value is invalid. 4575 """ 4576 stage = None 4577 sectionNode = readFirstChild(parentNode, "stage") 4578 if sectionNode is not None: 4579 stage = StageConfig() 4580 stage.targetDir = readString(sectionNode, "staging_dir") 4581 (stage.localPeers, stage.remotePeers) = Config._parsePeerList(sectionNode) 4582 return stage
4583 4584 @staticmethod
4585 - def _parseStore(parentNode):
4586 """ 4587 Parses a store configuration section. 4588 4589 We read the following fields:: 4590 4591 sourceDir //cb_config/store/source_dir 4592 mediaType //cb_config/store/media_type 4593 deviceType //cb_config/store/device_type 4594 devicePath //cb_config/store/target_device 4595 deviceScsiId //cb_config/store/target_scsi_id 4596 driveSpeed //cb_config/store/drive_speed 4597 checkData //cb_config/store/check_data 4598 checkMedia //cb_config/store/check_media 4599 warnMidnite //cb_config/store/warn_midnite 4600 noEject //cb_config/store/no_eject 4601 4602 Blanking behavior configuration is parsed by the C{_parseBlankBehavior} 4603 method. 4604 4605 @param parentNode: Parent node to search beneath. 4606 4607 @return: C{StoreConfig} object or C{None} if the section does not exist. 4608 @raise ValueError: If some filled-in value is invalid. 4609 """ 4610 store = None 4611 sectionNode = readFirstChild(parentNode, "store") 4612 if sectionNode is not None: 4613 store = StoreConfig() 4614 store.sourceDir = readString(sectionNode, "source_dir") 4615 store.mediaType = readString(sectionNode, "media_type") 4616 store.deviceType = readString(sectionNode, "device_type") 4617 store.devicePath = readString(sectionNode, "target_device") 4618 store.deviceScsiId = readString(sectionNode, "target_scsi_id") 4619 store.driveSpeed = readInteger(sectionNode, "drive_speed") 4620 store.checkData = readBoolean(sectionNode, "check_data") 4621 store.checkMedia = readBoolean(sectionNode, "check_media") 4622 store.warnMidnite = readBoolean(sectionNode, "warn_midnite") 4623 store.noEject = readBoolean(sectionNode, "no_eject") 4624 store.blankBehavior = Config._parseBlankBehavior(sectionNode) 4625 store.refreshMediaDelay = readInteger(sectionNode, "refresh_media_delay") 4626 store.ejectDelay = readInteger(sectionNode, "eject_delay") 4627 return store
4628 4629 @staticmethod
4630 - def _parsePurge(parentNode):
4631 """ 4632 Parses a purge configuration section. 4633 4634 We read groups of the following items, one list element per 4635 item:: 4636 4637 purgeDirs //cb_config/purge/dir 4638 4639 The individual directory entries are parsed by L{_parsePurgeDirs}. 4640 4641 @param parentNode: Parent node to search beneath. 4642 4643 @return: C{PurgeConfig} object or C{None} if the section does not exist. 4644 @raise ValueError: If some filled-in value is invalid. 4645 """ 4646 purge = None 4647 sectionNode = readFirstChild(parentNode, "purge") 4648 if sectionNode is not None: 4649 purge = PurgeConfig() 4650 purge.purgeDirs = Config._parsePurgeDirs(sectionNode) 4651 return purge
4652 4653 @staticmethod
4654 - def _parseExtendedActions(parentNode):
4655 """ 4656 Reads extended actions data from immediately beneath the parent. 4657 4658 We read the following individual fields from each extended action:: 4659 4660 name name 4661 module module 4662 function function 4663 index index 4664 dependencies depends 4665 4666 Dependency information is parsed by the C{_parseDependencies} method. 4667 4668 @param parentNode: Parent node to search beneath. 4669 4670 @return: List of extended actions. 4671 @raise ValueError: If the data at the location can't be read 4672 """ 4673 lst = [] 4674 for entry in readChildren(parentNode, "action"): 4675 if isElement(entry): 4676 action = ExtendedAction() 4677 action.name = readString(entry, "name") 4678 action.module = readString(entry, "module") 4679 action.function = readString(entry, "function") 4680 action.index = readInteger(entry, "index") 4681 action.dependencies = Config._parseDependencies(entry) 4682 lst.append(action) 4683 if lst == []: 4684 lst = None 4685 return lst
4686 4687 @staticmethod
4688 - def _parseExclusions(parentNode):
4689 """ 4690 Reads exclusions data from immediately beneath the parent. 4691 4692 We read groups of the following items, one list element per item:: 4693 4694 absolute exclude/abs_path 4695 relative exclude/rel_path 4696 patterns exclude/pattern 4697 4698 If there are none of some pattern (i.e. no relative path items) then 4699 C{None} will be returned for that item in the tuple. 4700 4701 This method can be used to parse exclusions on both the collect 4702 configuration level and on the collect directory level within collect 4703 configuration. 4704 4705 @param parentNode: Parent node to search beneath. 4706 4707 @return: Tuple of (absolute, relative, patterns) exclusions. 4708 """ 4709 sectionNode = readFirstChild(parentNode, "exclude") 4710 if sectionNode is None: 4711 return (None, None, None) 4712 else: 4713 absolute = readStringList(sectionNode, "abs_path") 4714 relative = readStringList(sectionNode, "rel_path") 4715 patterns = readStringList(sectionNode, "pattern") 4716 return (absolute, relative, patterns)
4717 4718 @staticmethod
4719 - def _parseOverrides(parentNode):
4720 """ 4721 Reads a list of C{CommandOverride} objects from immediately beneath the parent. 4722 4723 We read the following individual fields:: 4724 4725 command command 4726 absolutePath abs_path 4727 4728 @param parentNode: Parent node to search beneath. 4729 4730 @return: List of C{CommandOverride} objects or C{None} if none are found. 4731 @raise ValueError: If some filled-in value is invalid. 4732 """ 4733 lst = [] 4734 for entry in readChildren(parentNode, "override"): 4735 if isElement(entry): 4736 override = CommandOverride() 4737 override.command = readString(entry, "command") 4738 override.absolutePath = readString(entry, "abs_path") 4739 lst.append(override) 4740 if lst == []: 4741 lst = None 4742 return lst
4743 4744 @staticmethod
4745 - def _parseHooks(parentNode):
4746 """ 4747 Reads a list of C{ActionHook} objects from immediately beneath the parent. 4748 4749 We read the following individual fields:: 4750 4751 action action 4752 command command 4753 4754 @param parentNode: Parent node to search beneath. 4755 4756 @return: List of C{ActionHook} objects or C{None} if none are found. 4757 @raise ValueError: If some filled-in value is invalid. 4758 """ 4759 lst = [] 4760 for entry in readChildren(parentNode, "pre_action_hook"): 4761 if isElement(entry): 4762 hook = PreActionHook() 4763 hook.action = readString(entry, "action") 4764 hook.command = readString(entry, "command") 4765 lst.append(hook) 4766 for entry in readChildren(parentNode, "post_action_hook"): 4767 if isElement(entry): 4768 hook = PostActionHook() 4769 hook.action = readString(entry, "action") 4770 hook.command = readString(entry, "command") 4771 lst.append(hook) 4772 if lst == []: 4773 lst = None 4774 return lst
4775 4776 @staticmethod
4777 - def _parseCollectFiles(parentNode):
4778 """ 4779 Reads a list of C{CollectFile} objects from immediately beneath the parent. 4780 4781 We read the following individual fields:: 4782 4783 absolutePath abs_path 4784 collectMode mode I{or} collect_mode 4785 archiveMode archive_mode 4786 4787 The collect mode is a special case. Just a C{mode} tag is accepted, but 4788 we prefer C{collect_mode} for consistency with the rest of the config 4789 file and to avoid confusion with the archive mode. If both are provided, 4790 only C{mode} will be used. 4791 4792 @param parentNode: Parent node to search beneath. 4793 4794 @return: List of C{CollectFile} objects or C{None} if none are found. 4795 @raise ValueError: If some filled-in value is invalid. 4796 """ 4797 lst = [] 4798 for entry in readChildren(parentNode, "file"): 4799 if isElement(entry): 4800 cfile = CollectFile() 4801 cfile.absolutePath = readString(entry, "abs_path") 4802 cfile.collectMode = readString(entry, "mode") 4803 if cfile.collectMode is None: 4804 cfile.collectMode = readString(entry, "collect_mode") 4805 cfile.archiveMode = readString(entry, "archive_mode") 4806 lst.append(cfile) 4807 if lst == []: 4808 lst = None 4809 return lst
4810 4811 @staticmethod
4812 - def _parseCollectDirs(parentNode):
4813 """ 4814 Reads a list of C{CollectDir} objects from immediately beneath the parent. 4815 4816 We read the following individual fields:: 4817 4818 absolutePath abs_path 4819 collectMode mode I{or} collect_mode 4820 archiveMode archive_mode 4821 ignoreFile ignore_file 4822 linkDepth link_depth 4823 dereference dereference 4824 recursionLevel recursion_level 4825 4826 The collect mode is a special case. Just a C{mode} tag is accepted for 4827 backwards compatibility, but we prefer C{collect_mode} for consistency 4828 with the rest of the config file and to avoid confusion with the archive 4829 mode. If both are provided, only C{mode} will be used. 4830 4831 We also read groups of the following items, one list element per 4832 item:: 4833 4834 absoluteExcludePaths exclude/abs_path 4835 relativeExcludePaths exclude/rel_path 4836 excludePatterns exclude/pattern 4837 4838 The exclusions are parsed by L{_parseExclusions}. 4839 4840 @param parentNode: Parent node to search beneath. 4841 4842 @return: List of C{CollectDir} objects or C{None} if none are found. 4843 @raise ValueError: If some filled-in value is invalid. 4844 """ 4845 lst = [] 4846 for entry in readChildren(parentNode, "dir"): 4847 if isElement(entry): 4848 cdir = CollectDir() 4849 cdir.absolutePath = readString(entry, "abs_path") 4850 cdir.collectMode = readString(entry, "mode") 4851 if cdir.collectMode is None: 4852 cdir.collectMode = readString(entry, "collect_mode") 4853 cdir.archiveMode = readString(entry, "archive_mode") 4854 cdir.ignoreFile = readString(entry, "ignore_file") 4855 cdir.linkDepth = readInteger(entry, "link_depth") 4856 cdir.dereference = readBoolean(entry, "dereference") 4857 cdir.recursionLevel = readInteger(entry, "recursion_level") 4858 (cdir.absoluteExcludePaths, cdir.relativeExcludePaths, cdir.excludePatterns) = Config._parseExclusions(entry) 4859 lst.append(cdir) 4860 if lst == []: 4861 lst = None 4862 return lst
4863 4864 @staticmethod
4865 - def _parsePurgeDirs(parentNode):
4866 """ 4867 Reads a list of C{PurgeDir} objects from immediately beneath the parent. 4868 4869 We read the following individual fields:: 4870 4871 absolutePath <baseExpr>/abs_path 4872 retainDays <baseExpr>/retain_days 4873 4874 @param parentNode: Parent node to search beneath. 4875 4876 @return: List of C{PurgeDir} objects or C{None} if none are found. 4877 @raise ValueError: If the data at the location can't be read 4878 """ 4879 lst = [] 4880 for entry in readChildren(parentNode, "dir"): 4881 if isElement(entry): 4882 cdir = PurgeDir() 4883 cdir.absolutePath = readString(entry, "abs_path") 4884 cdir.retainDays = readInteger(entry, "retain_days") 4885 lst.append(cdir) 4886 if lst == []: 4887 lst = None 4888 return lst
4889 4890 @staticmethod
4891 - def _parsePeerList(parentNode):
4892 """ 4893 Reads remote and local peer data from immediately beneath the parent. 4894 4895 We read the following individual fields for both remote 4896 and local peers:: 4897 4898 name name 4899 collectDir collect_dir 4900 4901 We also read the following individual fields for remote peers 4902 only:: 4903 4904 remoteUser backup_user 4905 rcpCommand rcp_command 4906 rshCommand rsh_command 4907 cbackCommand cback_command 4908 managed managed 4909 managedActions managed_actions 4910 4911 Additionally, the value in the C{type} field is used to determine whether 4912 this entry is a remote peer. If the type is C{"remote"}, it's a remote 4913 peer, and if the type is C{"local"}, it's a remote peer. 4914 4915 If there are none of one type of peer (i.e. no local peers) then C{None} 4916 will be returned for that item in the tuple. 4917 4918 @param parentNode: Parent node to search beneath. 4919 4920 @return: Tuple of (local, remote) peer lists. 4921 @raise ValueError: If the data at the location can't be read 4922 """ 4923 localPeers = [] 4924 remotePeers = [] 4925 for entry in readChildren(parentNode, "peer"): 4926 if isElement(entry): 4927 peerType = readString(entry, "type") 4928 if peerType == "local": 4929 localPeer = LocalPeer() 4930 localPeer.name = readString(entry, "name") 4931 localPeer.collectDir = readString(entry, "collect_dir") 4932 localPeer.ignoreFailureMode = readString(entry, "ignore_failures") 4933 localPeers.append(localPeer) 4934 elif peerType == "remote": 4935 remotePeer = RemotePeer() 4936 remotePeer.name = readString(entry, "name") 4937 remotePeer.collectDir = readString(entry, "collect_dir") 4938 remotePeer.remoteUser = readString(entry, "backup_user") 4939 remotePeer.rcpCommand = readString(entry, "rcp_command") 4940 remotePeer.rshCommand = readString(entry, "rsh_command") 4941 remotePeer.cbackCommand = readString(entry, "cback_command") 4942 remotePeer.ignoreFailureMode = readString(entry, "ignore_failures") 4943 remotePeer.managed = readBoolean(entry, "managed") 4944 managedActions = readString(entry, "managed_actions") 4945 remotePeer.managedActions = parseCommaSeparatedString(managedActions) 4946 remotePeers.append(remotePeer) 4947 if localPeers == []: 4948 localPeers = None 4949 if remotePeers == []: 4950 remotePeers = None 4951 return (localPeers, remotePeers)
4952 4953 @staticmethod
4954 - def _parseDependencies(parentNode):
4955 """ 4956 Reads extended action dependency information from a parent node. 4957 4958 We read the following individual fields:: 4959 4960 runBefore depends/run_before 4961 runAfter depends/run_after 4962 4963 Each of these fields is a comma-separated list of action names. 4964 4965 The result is placed into an C{ActionDependencies} object. 4966 4967 If the dependencies parent node does not exist, C{None} will be returned. 4968 Otherwise, an C{ActionDependencies} object will always be created, even 4969 if it does not contain any actual dependencies in it. 4970 4971 @param parentNode: Parent node to search beneath. 4972 4973 @return: C{ActionDependencies} object or C{None}. 4974 @raise ValueError: If the data at the location can't be read 4975 """ 4976 sectionNode = readFirstChild(parentNode, "depends") 4977 if sectionNode is None: 4978 return None 4979 else: 4980 runBefore = readString(sectionNode, "run_before") 4981 runAfter = readString(sectionNode, "run_after") 4982 beforeList = parseCommaSeparatedString(runBefore) 4983 afterList = parseCommaSeparatedString(runAfter) 4984 return ActionDependencies(beforeList, afterList)
4985 4986 @staticmethod
4987 - def _parseBlankBehavior(parentNode):
4988 """ 4989 Reads a single C{BlankBehavior} object from immediately beneath the parent. 4990 4991 We read the following individual fields:: 4992 4993 blankMode blank_behavior/mode 4994 blankFactor blank_behavior/factor 4995 4996 @param parentNode: Parent node to search beneath. 4997 4998 @return: C{BlankBehavior} object or C{None} if none if the section is not found 4999 @raise ValueError: If some filled-in value is invalid. 5000 """ 5001 blankBehavior = None 5002 sectionNode = readFirstChild(parentNode, "blank_behavior") 5003 if sectionNode is not None: 5004 blankBehavior = BlankBehavior() 5005 blankBehavior.blankMode = readString(sectionNode, "mode") 5006 blankBehavior.blankFactor = readString(sectionNode, "factor") 5007 return blankBehavior
5008 5009 5010 ######################################## 5011 # High-level methods for generating XML 5012 ######################################## 5013
5014 - def _extractXml(self):
5015 """ 5016 Internal method to extract configuration into an XML string. 5017 5018 This method assumes that the internal L{validate} method has been called 5019 prior to extracting the XML, if the caller cares. No validation will be 5020 done internally. 5021 5022 As a general rule, fields that are set to C{None} will be extracted into 5023 the document as empty tags. The same goes for container tags that are 5024 filled based on lists - if the list is empty or C{None}, the container 5025 tag will be empty. 5026 """ 5027 (xmlDom, parentNode) = createOutputDom() 5028 Config._addReference(xmlDom, parentNode, self.reference) 5029 Config._addExtensions(xmlDom, parentNode, self.extensions) 5030 Config._addOptions(xmlDom, parentNode, self.options) 5031 Config._addPeers(xmlDom, parentNode, self.peers) 5032 Config._addCollect(xmlDom, parentNode, self.collect) 5033 Config._addStage(xmlDom, parentNode, self.stage) 5034 Config._addStore(xmlDom, parentNode, self.store) 5035 Config._addPurge(xmlDom, parentNode, self.purge) 5036 xmlData = serializeDom(xmlDom) 5037 xmlDom.unlink() 5038 return xmlData
5039 5040 @staticmethod
5041 - def _addReference(xmlDom, parentNode, referenceConfig):
5042 """ 5043 Adds a <reference> configuration section as the next child of a parent. 5044 5045 We add the following fields to the document:: 5046 5047 author //cb_config/reference/author 5048 revision //cb_config/reference/revision 5049 description //cb_config/reference/description 5050 generator //cb_config/reference/generator 5051 5052 If C{referenceConfig} is C{None}, then no container will be added. 5053 5054 @param xmlDom: DOM tree as from L{createOutputDom}. 5055 @param parentNode: Parent that the section should be appended to. 5056 @param referenceConfig: Reference configuration section to be added to the document. 5057 """ 5058 if referenceConfig is not None: 5059 sectionNode = addContainerNode(xmlDom, parentNode, "reference") 5060 addStringNode(xmlDom, sectionNode, "author", referenceConfig.author) 5061 addStringNode(xmlDom, sectionNode, "revision", referenceConfig.revision) 5062 addStringNode(xmlDom, sectionNode, "description", referenceConfig.description) 5063 addStringNode(xmlDom, sectionNode, "generator", referenceConfig.generator)
5064 5065 @staticmethod
5066 - def _addExtensions(xmlDom, parentNode, extensionsConfig):
5067 """ 5068 Adds an <extensions> configuration section as the next child of a parent. 5069 5070 We add the following fields to the document:: 5071 5072 order_mode //cb_config/extensions/order_mode 5073 5074 We also add groups of the following items, one list element per item:: 5075 5076 actions //cb_config/extensions/action 5077 5078 The extended action entries are added by L{_addExtendedAction}. 5079 5080 If C{extensionsConfig} is C{None}, then no container will be added. 5081 5082 @param xmlDom: DOM tree as from L{createOutputDom}. 5083 @param parentNode: Parent that the section should be appended to. 5084 @param extensionsConfig: Extensions configuration section to be added to the document. 5085 """ 5086 if extensionsConfig is not None: 5087 sectionNode = addContainerNode(xmlDom, parentNode, "extensions") 5088 addStringNode(xmlDom, sectionNode, "order_mode", extensionsConfig.orderMode) 5089 if extensionsConfig.actions is not None: 5090 for action in extensionsConfig.actions: 5091 Config._addExtendedAction(xmlDom, sectionNode, action)
5092 5093 @staticmethod
5094 - def _addOptions(xmlDom, parentNode, optionsConfig):
5095 """ 5096 Adds a <options> configuration section as the next child of a parent. 5097 5098 We add the following fields to the document:: 5099 5100 startingDay //cb_config/options/starting_day 5101 workingDir //cb_config/options/working_dir 5102 backupUser //cb_config/options/backup_user 5103 backupGroup //cb_config/options/backup_group 5104 rcpCommand //cb_config/options/rcp_command 5105 rshCommand //cb_config/options/rsh_command 5106 cbackCommand //cb_config/options/cback_command 5107 managedActions //cb_config/options/managed_actions 5108 5109 We also add groups of the following items, one list element per 5110 item:: 5111 5112 overrides //cb_config/options/override 5113 hooks //cb_config/options/pre_action_hook 5114 hooks //cb_config/options/post_action_hook 5115 5116 The individual override items are added by L{_addOverride}. The 5117 individual hook items are added by L{_addHook}. 5118 5119 If C{optionsConfig} is C{None}, then no container will be added. 5120 5121 @param xmlDom: DOM tree as from L{createOutputDom}. 5122 @param parentNode: Parent that the section should be appended to. 5123 @param optionsConfig: Options configuration section to be added to the document. 5124 """ 5125 if optionsConfig is not None: 5126 sectionNode = addContainerNode(xmlDom, parentNode, "options") 5127 addStringNode(xmlDom, sectionNode, "starting_day", optionsConfig.startingDay) 5128 addStringNode(xmlDom, sectionNode, "working_dir", optionsConfig.workingDir) 5129 addStringNode(xmlDom, sectionNode, "backup_user", optionsConfig.backupUser) 5130 addStringNode(xmlDom, sectionNode, "backup_group", optionsConfig.backupGroup) 5131 addStringNode(xmlDom, sectionNode, "rcp_command", optionsConfig.rcpCommand) 5132 addStringNode(xmlDom, sectionNode, "rsh_command", optionsConfig.rshCommand) 5133 addStringNode(xmlDom, sectionNode, "cback_command", optionsConfig.cbackCommand) 5134 managedActions = Config._buildCommaSeparatedString(optionsConfig.managedActions) 5135 addStringNode(xmlDom, sectionNode, "managed_actions", managedActions) 5136 if optionsConfig.overrides is not None: 5137 for override in optionsConfig.overrides: 5138 Config._addOverride(xmlDom, sectionNode, override) 5139 if optionsConfig.hooks is not None: 5140 for hook in optionsConfig.hooks: 5141 Config._addHook(xmlDom, sectionNode, hook)
5142 5143 @staticmethod
5144 - def _addPeers(xmlDom, parentNode, peersConfig):
5145 """ 5146 Adds a <peers> configuration section as the next child of a parent. 5147 5148 We add groups of the following items, one list element per 5149 item:: 5150 5151 localPeers //cb_config/peers/peer 5152 remotePeers //cb_config/peers/peer 5153 5154 The individual local and remote peer entries are added by 5155 L{_addLocalPeer} and L{_addRemotePeer}, respectively. 5156 5157 If C{peersConfig} is C{None}, then no container will be added. 5158 5159 @param xmlDom: DOM tree as from L{createOutputDom}. 5160 @param parentNode: Parent that the section should be appended to. 5161 @param peersConfig: Peers configuration section to be added to the document. 5162 """ 5163 if peersConfig is not None: 5164 sectionNode = addContainerNode(xmlDom, parentNode, "peers") 5165 if peersConfig.localPeers is not None: 5166 for localPeer in peersConfig.localPeers: 5167 Config._addLocalPeer(xmlDom, sectionNode, localPeer) 5168 if peersConfig.remotePeers is not None: 5169 for remotePeer in peersConfig.remotePeers: 5170 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
5171 5172 @staticmethod
5173 - def _addCollect(xmlDom, parentNode, collectConfig):
5174 """ 5175 Adds a <collect> configuration section as the next child of a parent. 5176 5177 We add the following fields to the document:: 5178 5179 targetDir //cb_config/collect/collect_dir 5180 collectMode //cb_config/collect/collect_mode 5181 archiveMode //cb_config/collect/archive_mode 5182 ignoreFile //cb_config/collect/ignore_file 5183 5184 We also add groups of the following items, one list element per 5185 item:: 5186 5187 absoluteExcludePaths //cb_config/collect/exclude/abs_path 5188 excludePatterns //cb_config/collect/exclude/pattern 5189 collectFiles //cb_config/collect/file 5190 collectDirs //cb_config/collect/dir 5191 5192 The individual collect files are added by L{_addCollectFile} and 5193 individual collect directories are added by L{_addCollectDir}. 5194 5195 If C{collectConfig} is C{None}, then no container will be added. 5196 5197 @param xmlDom: DOM tree as from L{createOutputDom}. 5198 @param parentNode: Parent that the section should be appended to. 5199 @param collectConfig: Collect configuration section to be added to the document. 5200 """ 5201 if collectConfig is not None: 5202 sectionNode = addContainerNode(xmlDom, parentNode, "collect") 5203 addStringNode(xmlDom, sectionNode, "collect_dir", collectConfig.targetDir) 5204 addStringNode(xmlDom, sectionNode, "collect_mode", collectConfig.collectMode) 5205 addStringNode(xmlDom, sectionNode, "archive_mode", collectConfig.archiveMode) 5206 addStringNode(xmlDom, sectionNode, "ignore_file", collectConfig.ignoreFile) 5207 if ((collectConfig.absoluteExcludePaths is not None and collectConfig.absoluteExcludePaths != []) or 5208 (collectConfig.excludePatterns is not None and collectConfig.excludePatterns != [])): 5209 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude") 5210 if collectConfig.absoluteExcludePaths is not None: 5211 for absolutePath in collectConfig.absoluteExcludePaths: 5212 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath) 5213 if collectConfig.excludePatterns is not None: 5214 for pattern in collectConfig.excludePatterns: 5215 addStringNode(xmlDom, excludeNode, "pattern", pattern) 5216 if collectConfig.collectFiles is not None: 5217 for collectFile in collectConfig.collectFiles: 5218 Config._addCollectFile(xmlDom, sectionNode, collectFile) 5219 if collectConfig.collectDirs is not None: 5220 for collectDir in collectConfig.collectDirs: 5221 Config._addCollectDir(xmlDom, sectionNode, collectDir)
5222 5223 @staticmethod
5224 - def _addStage(xmlDom, parentNode, stageConfig):
5225 """ 5226 Adds a <stage> configuration section as the next child of a parent. 5227 5228 We add the following fields to the document:: 5229 5230 targetDir //cb_config/stage/staging_dir 5231 5232 We also add groups of the following items, one list element per 5233 item:: 5234 5235 localPeers //cb_config/stage/peer 5236 remotePeers //cb_config/stage/peer 5237 5238 The individual local and remote peer entries are added by 5239 L{_addLocalPeer} and L{_addRemotePeer}, respectively. 5240 5241 If C{stageConfig} is C{None}, then no container will be added. 5242 5243 @param xmlDom: DOM tree as from L{createOutputDom}. 5244 @param parentNode: Parent that the section should be appended to. 5245 @param stageConfig: Stage configuration section to be added to the document. 5246 """ 5247 if stageConfig is not None: 5248 sectionNode = addContainerNode(xmlDom, parentNode, "stage") 5249 addStringNode(xmlDom, sectionNode, "staging_dir", stageConfig.targetDir) 5250 if stageConfig.localPeers is not None: 5251 for localPeer in stageConfig.localPeers: 5252 Config._addLocalPeer(xmlDom, sectionNode, localPeer) 5253 if stageConfig.remotePeers is not None: 5254 for remotePeer in stageConfig.remotePeers: 5255 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
5256 5257 @staticmethod
5258 - def _addStore(xmlDom, parentNode, storeConfig):
5259 """ 5260 Adds a <store> configuration section as the next child of a parent. 5261 5262 We add the following fields to the document:: 5263 5264 sourceDir //cb_config/store/source_dir 5265 mediaType //cb_config/store/media_type 5266 deviceType //cb_config/store/device_type 5267 devicePath //cb_config/store/target_device 5268 deviceScsiId //cb_config/store/target_scsi_id 5269 driveSpeed //cb_config/store/drive_speed 5270 checkData //cb_config/store/check_data 5271 checkMedia //cb_config/store/check_media 5272 warnMidnite //cb_config/store/warn_midnite 5273 noEject //cb_config/store/no_eject 5274 refreshMediaDelay //cb_config/store/refresh_media_delay 5275 ejectDelay //cb_config/store/eject_delay 5276 5277 Blanking behavior configuration is added by the L{_addBlankBehavior} 5278 method. 5279 5280 If C{storeConfig} is C{None}, then no container will be added. 5281 5282 @param xmlDom: DOM tree as from L{createOutputDom}. 5283 @param parentNode: Parent that the section should be appended to. 5284 @param storeConfig: Store configuration section to be added to the document. 5285 """ 5286 if storeConfig is not None: 5287 sectionNode = addContainerNode(xmlDom, parentNode, "store") 5288 addStringNode(xmlDom, sectionNode, "source_dir", storeConfig.sourceDir) 5289 addStringNode(xmlDom, sectionNode, "media_type", storeConfig.mediaType) 5290 addStringNode(xmlDom, sectionNode, "device_type", storeConfig.deviceType) 5291 addStringNode(xmlDom, sectionNode, "target_device", storeConfig.devicePath) 5292 addStringNode(xmlDom, sectionNode, "target_scsi_id", storeConfig.deviceScsiId) 5293 addIntegerNode(xmlDom, sectionNode, "drive_speed", storeConfig.driveSpeed) 5294 addBooleanNode(xmlDom, sectionNode, "check_data", storeConfig.checkData) 5295 addBooleanNode(xmlDom, sectionNode, "check_media", storeConfig.checkMedia) 5296 addBooleanNode(xmlDom, sectionNode, "warn_midnite", storeConfig.warnMidnite) 5297 addBooleanNode(xmlDom, sectionNode, "no_eject", storeConfig.noEject) 5298 addIntegerNode(xmlDom, sectionNode, "refresh_media_delay", storeConfig.refreshMediaDelay) 5299 addIntegerNode(xmlDom, sectionNode, "eject_delay", storeConfig.ejectDelay) 5300 Config._addBlankBehavior(xmlDom, sectionNode, storeConfig.blankBehavior)
5301 5302 @staticmethod
5303 - def _addPurge(xmlDom, parentNode, purgeConfig):
5304 """ 5305 Adds a <purge> configuration section as the next child of a parent. 5306 5307 We add the following fields to the document:: 5308 5309 purgeDirs //cb_config/purge/dir 5310 5311 The individual directory entries are added by L{_addPurgeDir}. 5312 5313 If C{purgeConfig} is C{None}, then no container will be added. 5314 5315 @param xmlDom: DOM tree as from L{createOutputDom}. 5316 @param parentNode: Parent that the section should be appended to. 5317 @param purgeConfig: Purge configuration section to be added to the document. 5318 """ 5319 if purgeConfig is not None: 5320 sectionNode = addContainerNode(xmlDom, parentNode, "purge") 5321 if purgeConfig.purgeDirs is not None: 5322 for purgeDir in purgeConfig.purgeDirs: 5323 Config._addPurgeDir(xmlDom, sectionNode, purgeDir)
5324 5325 @staticmethod
5326 - def _addExtendedAction(xmlDom, parentNode, action):
5327 """ 5328 Adds an extended action container as the next child of a parent. 5329 5330 We add the following fields to the document:: 5331 5332 name action/name 5333 module action/module 5334 function action/function 5335 index action/index 5336 dependencies action/depends 5337 5338 Dependencies are added by the L{_addDependencies} method. 5339 5340 The <action> node itself is created as the next child of the parent node. 5341 This method only adds one action node. The parent must loop for each action 5342 in the C{ExtensionsConfig} object. 5343 5344 If C{action} is C{None}, this method call will be a no-op. 5345 5346 @param xmlDom: DOM tree as from L{createOutputDom}. 5347 @param parentNode: Parent that the section should be appended to. 5348 @param action: Purge directory to be added to the document. 5349 """ 5350 if action is not None: 5351 sectionNode = addContainerNode(xmlDom, parentNode, "action") 5352 addStringNode(xmlDom, sectionNode, "name", action.name) 5353 addStringNode(xmlDom, sectionNode, "module", action.module) 5354 addStringNode(xmlDom, sectionNode, "function", action.function) 5355 addIntegerNode(xmlDom, sectionNode, "index", action.index) 5356 Config._addDependencies(xmlDom, sectionNode, action.dependencies)
5357 5358 @staticmethod
5359 - def _addOverride(xmlDom, parentNode, override):
5360 """ 5361 Adds a command override container as the next child of a parent. 5362 5363 We add the following fields to the document:: 5364 5365 command override/command 5366 absolutePath override/abs_path 5367 5368 The <override> node itself is created as the next child of the parent 5369 node. This method only adds one override node. The parent must loop for 5370 each override in the C{OptionsConfig} object. 5371 5372 If C{override} is C{None}, this method call will be a no-op. 5373 5374 @param xmlDom: DOM tree as from L{createOutputDom}. 5375 @param parentNode: Parent that the section should be appended to. 5376 @param override: Command override to be added to the document. 5377 """ 5378 if override is not None: 5379 sectionNode = addContainerNode(xmlDom, parentNode, "override") 5380 addStringNode(xmlDom, sectionNode, "command", override.command) 5381 addStringNode(xmlDom, sectionNode, "abs_path", override.absolutePath)
5382 5383 @staticmethod
5384 - def _addHook(xmlDom, parentNode, hook):
5385 """ 5386 Adds an action hook container as the next child of a parent. 5387 5388 The behavior varies depending on the value of the C{before} and C{after} 5389 flags on the hook. If the C{before} flag is set, it's a pre-action hook, 5390 and we'll add the following fields:: 5391 5392 action pre_action_hook/action 5393 command pre_action_hook/command 5394 5395 If the C{after} flag is set, it's a post-action hook, and we'll add the 5396 following fields:: 5397 5398 action post_action_hook/action 5399 command post_action_hook/command 5400 5401 The <pre_action_hook> or <post_action_hook> node itself is created as the 5402 next child of the parent node. This method only adds one hook node. The 5403 parent must loop for each hook in the C{OptionsConfig} object. 5404 5405 If C{hook} is C{None}, this method call will be a no-op. 5406 5407 @param xmlDom: DOM tree as from L{createOutputDom}. 5408 @param parentNode: Parent that the section should be appended to. 5409 @param hook: Command hook to be added to the document. 5410 """ 5411 if hook is not None: 5412 if hook.before: 5413 sectionNode = addContainerNode(xmlDom, parentNode, "pre_action_hook") 5414 else: 5415 sectionNode = addContainerNode(xmlDom, parentNode, "post_action_hook") 5416 addStringNode(xmlDom, sectionNode, "action", hook.action) 5417 addStringNode(xmlDom, sectionNode, "command", hook.command)
5418 5419 @staticmethod
5420 - def _addCollectFile(xmlDom, parentNode, collectFile):
5421 """ 5422 Adds a collect file container as the next child of a parent. 5423 5424 We add the following fields to the document:: 5425 5426 absolutePath dir/abs_path 5427 collectMode dir/collect_mode 5428 archiveMode dir/archive_mode 5429 5430 Note that for consistency with collect directory handling we'll only emit 5431 the preferred C{collect_mode} tag. 5432 5433 The <file> node itself is created as the next child of the parent node. 5434 This method only adds one collect file node. The parent must loop 5435 for each collect file in the C{CollectConfig} object. 5436 5437 If C{collectFile} is C{None}, this method call will be a no-op. 5438 5439 @param xmlDom: DOM tree as from L{createOutputDom}. 5440 @param parentNode: Parent that the section should be appended to. 5441 @param collectFile: Collect file to be added to the document. 5442 """ 5443 if collectFile is not None: 5444 sectionNode = addContainerNode(xmlDom, parentNode, "file") 5445 addStringNode(xmlDom, sectionNode, "abs_path", collectFile.absolutePath) 5446 addStringNode(xmlDom, sectionNode, "collect_mode", collectFile.collectMode) 5447 addStringNode(xmlDom, sectionNode, "archive_mode", collectFile.archiveMode)
5448 5449 @staticmethod
5450 - def _addCollectDir(xmlDom, parentNode, collectDir):
5451 """ 5452 Adds a collect directory container as the next child of a parent. 5453 5454 We add the following fields to the document:: 5455 5456 absolutePath dir/abs_path 5457 collectMode dir/collect_mode 5458 archiveMode dir/archive_mode 5459 ignoreFile dir/ignore_file 5460 linkDepth dir/link_depth 5461 dereference dir/dereference 5462 recursionLevel dir/recursion_level 5463 5464 Note that an original XML document might have listed the collect mode 5465 using the C{mode} tag, since we accept both C{collect_mode} and C{mode}. 5466 However, here we'll only emit the preferred C{collect_mode} tag. 5467 5468 We also add groups of the following items, one list element per item:: 5469 5470 absoluteExcludePaths dir/exclude/abs_path 5471 relativeExcludePaths dir/exclude/rel_path 5472 excludePatterns dir/exclude/pattern 5473 5474 The <dir> node itself is created as the next child of the parent node. 5475 This method only adds one collect directory node. The parent must loop 5476 for each collect directory in the C{CollectConfig} object. 5477 5478 If C{collectDir} is C{None}, this method call will be a no-op. 5479 5480 @param xmlDom: DOM tree as from L{createOutputDom}. 5481 @param parentNode: Parent that the section should be appended to. 5482 @param collectDir: Collect directory to be added to the document. 5483 """ 5484 if collectDir is not None: 5485 sectionNode = addContainerNode(xmlDom, parentNode, "dir") 5486 addStringNode(xmlDom, sectionNode, "abs_path", collectDir.absolutePath) 5487 addStringNode(xmlDom, sectionNode, "collect_mode", collectDir.collectMode) 5488 addStringNode(xmlDom, sectionNode, "archive_mode", collectDir.archiveMode) 5489 addStringNode(xmlDom, sectionNode, "ignore_file", collectDir.ignoreFile) 5490 addIntegerNode(xmlDom, sectionNode, "link_depth", collectDir.linkDepth) 5491 addBooleanNode(xmlDom, sectionNode, "dereference", collectDir.dereference) 5492 addIntegerNode(xmlDom, sectionNode, "recursion_level", collectDir.recursionLevel) 5493 if ((collectDir.absoluteExcludePaths is not None and collectDir.absoluteExcludePaths != []) or 5494 (collectDir.relativeExcludePaths is not None and collectDir.relativeExcludePaths != []) or 5495 (collectDir.excludePatterns is not None and collectDir.excludePatterns != [])): 5496 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude") 5497 if collectDir.absoluteExcludePaths is not None: 5498 for absolutePath in collectDir.absoluteExcludePaths: 5499 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath) 5500 if collectDir.relativeExcludePaths is not None: 5501 for relativePath in collectDir.relativeExcludePaths: 5502 addStringNode(xmlDom, excludeNode, "rel_path", relativePath) 5503 if collectDir.excludePatterns is not None: 5504 for pattern in collectDir.excludePatterns: 5505 addStringNode(xmlDom, excludeNode, "pattern", pattern)
5506 5507 @staticmethod
5508 - def _addLocalPeer(xmlDom, parentNode, localPeer):
5509 """ 5510 Adds a local peer container as the next child of a parent. 5511 5512 We add the following fields to the document:: 5513 5514 name peer/name 5515 collectDir peer/collect_dir 5516 ignoreFailureMode peer/ignore_failures 5517 5518 Additionally, C{peer/type} is filled in with C{"local"}, since this is a 5519 local peer. 5520 5521 The <peer> node itself is created as the next child of the parent node. 5522 This method only adds one peer node. The parent must loop for each peer 5523 in the C{StageConfig} object. 5524 5525 If C{localPeer} is C{None}, this method call will be a no-op. 5526 5527 @param xmlDom: DOM tree as from L{createOutputDom}. 5528 @param parentNode: Parent that the section should be appended to. 5529 @param localPeer: Purge directory to be added to the document. 5530 """ 5531 if localPeer is not None: 5532 sectionNode = addContainerNode(xmlDom, parentNode, "peer") 5533 addStringNode(xmlDom, sectionNode, "name", localPeer.name) 5534 addStringNode(xmlDom, sectionNode, "type", "local") 5535 addStringNode(xmlDom, sectionNode, "collect_dir", localPeer.collectDir) 5536 addStringNode(xmlDom, sectionNode, "ignore_failures", localPeer.ignoreFailureMode)
5537 5538 @staticmethod
5539 - def _addRemotePeer(xmlDom, parentNode, remotePeer):
5540 """ 5541 Adds a remote peer container as the next child of a parent. 5542 5543 We add the following fields to the document:: 5544 5545 name peer/name 5546 collectDir peer/collect_dir 5547 remoteUser peer/backup_user 5548 rcpCommand peer/rcp_command 5549 rcpCommand peer/rcp_command 5550 rshCommand peer/rsh_command 5551 cbackCommand peer/cback_command 5552 ignoreFailureMode peer/ignore_failures 5553 managed peer/managed 5554 managedActions peer/managed_actions 5555 5556 Additionally, C{peer/type} is filled in with C{"remote"}, since this is a 5557 remote peer. 5558 5559 The <peer> node itself is created as the next child of the parent node. 5560 This method only adds one peer node. The parent must loop for each peer 5561 in the C{StageConfig} object. 5562 5563 If C{remotePeer} is C{None}, this method call will be a no-op. 5564 5565 @param xmlDom: DOM tree as from L{createOutputDom}. 5566 @param parentNode: Parent that the section should be appended to. 5567 @param remotePeer: Purge directory to be added to the document. 5568 """ 5569 if remotePeer is not None: 5570 sectionNode = addContainerNode(xmlDom, parentNode, "peer") 5571 addStringNode(xmlDom, sectionNode, "name", remotePeer.name) 5572 addStringNode(xmlDom, sectionNode, "type", "remote") 5573 addStringNode(xmlDom, sectionNode, "collect_dir", remotePeer.collectDir) 5574 addStringNode(xmlDom, sectionNode, "backup_user", remotePeer.remoteUser) 5575 addStringNode(xmlDom, sectionNode, "rcp_command", remotePeer.rcpCommand) 5576 addStringNode(xmlDom, sectionNode, "rsh_command", remotePeer.rshCommand) 5577 addStringNode(xmlDom, sectionNode, "cback_command", remotePeer.cbackCommand) 5578 addStringNode(xmlDom, sectionNode, "ignore_failures", remotePeer.ignoreFailureMode) 5579 addBooleanNode(xmlDom, sectionNode, "managed", remotePeer.managed) 5580 managedActions = Config._buildCommaSeparatedString(remotePeer.managedActions) 5581 addStringNode(xmlDom, sectionNode, "managed_actions", managedActions)
5582 5583 @staticmethod
5584 - def _addPurgeDir(xmlDom, parentNode, purgeDir):
5585 """ 5586 Adds a purge directory container as the next child of a parent. 5587 5588 We add the following fields to the document:: 5589 5590 absolutePath dir/abs_path 5591 retainDays dir/retain_days 5592 5593 The <dir> node itself is created as the next child of the parent node. 5594 This method only adds one purge directory node. The parent must loop for 5595 each purge directory in the C{PurgeConfig} object. 5596 5597 If C{purgeDir} is C{None}, this method call will be a no-op. 5598 5599 @param xmlDom: DOM tree as from L{createOutputDom}. 5600 @param parentNode: Parent that the section should be appended to. 5601 @param purgeDir: Purge directory to be added to the document. 5602 """ 5603 if purgeDir is not None: 5604 sectionNode = addContainerNode(xmlDom, parentNode, "dir") 5605 addStringNode(xmlDom, sectionNode, "abs_path", purgeDir.absolutePath) 5606 addIntegerNode(xmlDom, sectionNode, "retain_days", purgeDir.retainDays)
5607 5608 @staticmethod
5609 - def _addDependencies(xmlDom, parentNode, dependencies):
5610 """ 5611 Adds a extended action dependencies to parent node. 5612 5613 We add the following fields to the document:: 5614 5615 runBefore depends/run_before 5616 runAfter depends/run_after 5617 5618 If C{dependencies} is C{None}, this method call will be a no-op. 5619 5620 @param xmlDom: DOM tree as from L{createOutputDom}. 5621 @param parentNode: Parent that the section should be appended to. 5622 @param dependencies: C{ActionDependencies} object to be added to the document 5623 """ 5624 if dependencies is not None: 5625 sectionNode = addContainerNode(xmlDom, parentNode, "depends") 5626 runBefore = Config._buildCommaSeparatedString(dependencies.beforeList) 5627 runAfter = Config._buildCommaSeparatedString(dependencies.afterList) 5628 addStringNode(xmlDom, sectionNode, "run_before", runBefore) 5629 addStringNode(xmlDom, sectionNode, "run_after", runAfter)
5630 5631 @staticmethod
5632 - def _buildCommaSeparatedString(valueList):
5633 """ 5634 Creates a comma-separated string from a list of values. 5635 5636 As a special case, if C{valueList} is C{None}, then C{None} will be 5637 returned. 5638 5639 @param valueList: List of values to be placed into a string 5640 5641 @return: Values from valueList as a comma-separated string. 5642 """ 5643 if valueList is None: 5644 return None 5645 return ",".join(valueList)
5646 5647 @staticmethod
5648 - def _addBlankBehavior(xmlDom, parentNode, blankBehavior):
5649 """ 5650 Adds a blanking behavior container as the next child of a parent. 5651 5652 We add the following fields to the document:: 5653 5654 blankMode blank_behavior/mode 5655 blankFactor blank_behavior/factor 5656 5657 The <blank_behavior> node itself is created as the next child of the 5658 parent node. 5659 5660 If C{blankBehavior} is C{None}, this method call will be a no-op. 5661 5662 @param xmlDom: DOM tree as from L{createOutputDom}. 5663 @param parentNode: Parent that the section should be appended to. 5664 @param blankBehavior: Blanking behavior to be added to the document. 5665 """ 5666 if blankBehavior is not None: 5667 sectionNode = addContainerNode(xmlDom, parentNode, "blank_behavior") 5668 addStringNode(xmlDom, sectionNode, "mode", blankBehavior.blankMode) 5669 addStringNode(xmlDom, sectionNode, "factor", blankBehavior.blankFactor)
5670 5671 5672 ################################################# 5673 # High-level methods used for validating content 5674 ################################################# 5675
5676 - def _validateContents(self):
5677 """ 5678 Validates configuration contents per rules discussed in module 5679 documentation. 5680 5681 This is the second pass at validation. It ensures that any filled-in 5682 section contains valid data. Any sections which is not set to C{None} is 5683 validated per the rules for that section, laid out in the module 5684 documentation (above). 5685 5686 @raise ValueError: If configuration is invalid. 5687 """ 5688 self._validateReference() 5689 self._validateExtensions() 5690 self._validateOptions() 5691 self._validatePeers() 5692 self._validateCollect() 5693 self._validateStage() 5694 self._validateStore() 5695 self._validatePurge()
5696
5697 - def _validateReference(self):
5698 """ 5699 Validates reference configuration. 5700 There are currently no reference-related validations. 5701 @raise ValueError: If reference configuration is invalid. 5702 """ 5703 pass
5704
5705 - def _validateExtensions(self):
5706 """ 5707 Validates extensions configuration. 5708 5709 The list of actions may be either C{None} or an empty list C{[]} if 5710 desired. Each extended action must include a name, a module, and a 5711 function. 5712 5713 Then, if the order mode is None or "index", an index is required; and if 5714 the order mode is "dependency", dependency information is required. 5715 5716 @raise ValueError: If reference configuration is invalid. 5717 """ 5718 if self.extensions is not None: 5719 if self.extensions.actions is not None: 5720 names = [] 5721 for action in self.extensions.actions: 5722 if action.name is None: 5723 raise ValueError("Each extended action must set a name.") 5724 names.append(action.name) 5725 if action.module is None: 5726 raise ValueError("Each extended action must set a module.") 5727 if action.function is None: 5728 raise ValueError("Each extended action must set a function.") 5729 if self.extensions.orderMode is None or self.extensions.orderMode == "index": 5730 if action.index is None: 5731 raise ValueError("Each extended action must set an index, based on order mode.") 5732 elif self.extensions.orderMode == "dependency": 5733 if action.dependencies is None: 5734 raise ValueError("Each extended action must set dependency information, based on order mode.") 5735 checkUnique("Duplicate extension names exist:", names)
5736
5737 - def _validateOptions(self):
5738 """ 5739 Validates options configuration. 5740 5741 All fields must be filled in except the rsh command. The rcp and rsh 5742 commands are used as default values for all remote peers. Remote peers 5743 can also rely on the backup user as the default remote user name if they 5744 choose. 5745 5746 @raise ValueError: If reference configuration is invalid. 5747 """ 5748 if self.options is not None: 5749 if self.options.startingDay is None: 5750 raise ValueError("Options section starting day must be filled in.") 5751 if self.options.workingDir is None: 5752 raise ValueError("Options section working directory must be filled in.") 5753 if self.options.backupUser is None: 5754 raise ValueError("Options section backup user must be filled in.") 5755 if self.options.backupGroup is None: 5756 raise ValueError("Options section backup group must be filled in.") 5757 if self.options.rcpCommand is None: 5758 raise ValueError("Options section remote copy command must be filled in.")
5759
5760 - def _validatePeers(self):
5761 """ 5762 Validates peers configuration per rules in L{_validatePeerList}. 5763 @raise ValueError: If peers configuration is invalid. 5764 """ 5765 if self.peers is not None: 5766 self._validatePeerList(self.peers.localPeers, self.peers.remotePeers)
5767
5768 - def _validateCollect(self):
5769 """ 5770 Validates collect configuration. 5771 5772 The target directory must be filled in. The collect mode, archive mode, 5773 ignore file, and recursion level are all optional. The list of absolute 5774 paths to exclude and patterns to exclude may be either C{None} or an 5775 empty list C{[]} if desired. 5776 5777 Each collect directory entry must contain an absolute path to collect, 5778 and then must either be able to take collect mode, archive mode and 5779 ignore file configuration from the parent C{CollectConfig} object, or 5780 must set each value on its own. The list of absolute paths to exclude, 5781 relative paths to exclude and patterns to exclude may be either C{None} 5782 or an empty list C{[]} if desired. Any list of absolute paths to exclude 5783 or patterns to exclude will be combined with the same list in the 5784 C{CollectConfig} object to make the complete list for a given directory. 5785 5786 @raise ValueError: If collect configuration is invalid. 5787 """ 5788 if self.collect is not None: 5789 if self.collect.targetDir is None: 5790 raise ValueError("Collect section target directory must be filled in.") 5791 if self.collect.collectFiles is not None: 5792 for collectFile in self.collect.collectFiles: 5793 if collectFile.absolutePath is None: 5794 raise ValueError("Each collect file must set an absolute path.") 5795 if self.collect.collectMode is None and collectFile.collectMode is None: 5796 raise ValueError("Collect mode must either be set in parent collect section or individual collect file.") 5797 if self.collect.archiveMode is None and collectFile.archiveMode is None: 5798 raise ValueError("Archive mode must either be set in parent collect section or individual collect file.") 5799 if self.collect.collectDirs is not None: 5800 for collectDir in self.collect.collectDirs: 5801 if collectDir.absolutePath is None: 5802 raise ValueError("Each collect directory must set an absolute path.") 5803 if self.collect.collectMode is None and collectDir.collectMode is None: 5804 raise ValueError("Collect mode must either be set in parent collect section or individual collect directory.") 5805 if self.collect.archiveMode is None and collectDir.archiveMode is None: 5806 raise ValueError("Archive mode must either be set in parent collect section or individual collect directory.") 5807 if self.collect.ignoreFile is None and collectDir.ignoreFile is None: 5808 raise ValueError("Ignore file must either be set in parent collect section or individual collect directory.") 5809 if (collectDir.linkDepth is None or collectDir.linkDepth < 1) and collectDir.dereference: 5810 raise ValueError("Dereference flag is only valid when a non-zero link depth is in use.")
5811
5812 - def _validateStage(self):
5813 """ 5814 Validates stage configuration. 5815 5816 The target directory must be filled in, and the peers are 5817 also validated. 5818 5819 Peers are only required in this section if the peers configuration 5820 section is not filled in. However, if any peers are filled in 5821 here, they override the peers configuration and must meet the 5822 validation criteria in L{_validatePeerList}. 5823 5824 @raise ValueError: If stage configuration is invalid. 5825 """ 5826 if self.stage is not None: 5827 if self.stage.targetDir is None: 5828 raise ValueError("Stage section target directory must be filled in.") 5829 if self.peers is None: 5830 # In this case, stage configuration is our only configuration and must be valid. 5831 self._validatePeerList(self.stage.localPeers, self.stage.remotePeers) 5832 else: 5833 # In this case, peers configuration is the default and stage configuration overrides. 5834 # Validation is only needed if it's stage configuration is actually filled in. 5835 if self.stage.hasPeers(): 5836 self._validatePeerList(self.stage.localPeers, self.stage.remotePeers)
5837
5838 - def _validateStore(self):
5839 """ 5840 Validates store configuration. 5841 5842 The device type, drive speed, and blanking behavior are optional. All 5843 other values are required. Missing booleans will be set to defaults. 5844 5845 If blanking behavior is provided, then both a blanking mode and a 5846 blanking factor are required. 5847 5848 The image writer functionality in the C{writer} module is supposed to be 5849 able to handle a device speed of C{None}. 5850 5851 Any caller which needs a "real" (non-C{None}) value for the device type 5852 can use C{DEFAULT_DEVICE_TYPE}, which is guaranteed to be sensible. 5853 5854 This is also where we make sure that the media type -- which is already a 5855 valid type -- matches up properly with the device type. 5856 5857 @raise ValueError: If store configuration is invalid. 5858 """ 5859 if self.store is not None: 5860 if self.store.sourceDir is None: 5861 raise ValueError("Store section source directory must be filled in.") 5862 if self.store.mediaType is None: 5863 raise ValueError("Store section media type must be filled in.") 5864 if self.store.devicePath is None: 5865 raise ValueError("Store section device path must be filled in.") 5866 if self.store.deviceType == None or self.store.deviceType == "cdwriter": 5867 if self.store.mediaType not in VALID_CD_MEDIA_TYPES: 5868 raise ValueError("Media type must match device type.") 5869 elif self.store.deviceType == "dvdwriter": 5870 if self.store.mediaType not in VALID_DVD_MEDIA_TYPES: 5871 raise ValueError("Media type must match device type.") 5872 if self.store.blankBehavior is not None: 5873 if self.store.blankBehavior.blankMode is None and self.store.blankBehavior.blankFactor is None: 5874 raise ValueError("If blanking behavior is provided, all values must be filled in.")
5875
5876 - def _validatePurge(self):
5877 """ 5878 Validates purge configuration. 5879 5880 The list of purge directories may be either C{None} or an empty list 5881 C{[]} if desired. All purge directories must contain a path and a retain 5882 days value. 5883 5884 @raise ValueError: If purge configuration is invalid. 5885 """ 5886 if self.purge is not None: 5887 if self.purge.purgeDirs is not None: 5888 for purgeDir in self.purge.purgeDirs: 5889 if purgeDir.absolutePath is None: 5890 raise ValueError("Each purge directory must set an absolute path.") 5891 if purgeDir.retainDays is None: 5892 raise ValueError("Each purge directory must set a retain days value.")
5893
5894 - def _validatePeerList(self, localPeers, remotePeers):
5895 """ 5896 Validates the set of local and remote peers. 5897 5898 Local peers must be completely filled in, including both name and collect 5899 directory. Remote peers must also fill in the name and collect 5900 directory, but can leave the remote user and rcp command unset. In this 5901 case, the remote user is assumed to match the backup user from the 5902 options section and rcp command is taken directly from the options 5903 section. 5904 5905 @param localPeers: List of local peers 5906 @param remotePeers: List of remote peers 5907 5908 @raise ValueError: If stage configuration is invalid. 5909 """ 5910 if localPeers is None and remotePeers is None: 5911 raise ValueError("Peer list must contain at least one backup peer.") 5912 if localPeers is None and remotePeers is not None: 5913 if len(remotePeers) < 1: 5914 raise ValueError("Peer list must contain at least one backup peer.") 5915 elif localPeers is not None and remotePeers is None: 5916 if len(localPeers) < 1: 5917 raise ValueError("Peer list must contain at least one backup peer.") 5918 elif localPeers is not None and remotePeers is not None: 5919 if len(localPeers) + len(remotePeers) < 1: 5920 raise ValueError("Peer list must contain at least one backup peer.") 5921 names = [] 5922 if localPeers is not None: 5923 for localPeer in localPeers: 5924 if localPeer.name is None: 5925 raise ValueError("Local peers must set a name.") 5926 names.append(localPeer.name) 5927 if localPeer.collectDir is None: 5928 raise ValueError("Local peers must set a collect directory.") 5929 if remotePeers is not None: 5930 for remotePeer in remotePeers: 5931 if remotePeer.name is None: 5932 raise ValueError("Remote peers must set a name.") 5933 names.append(remotePeer.name) 5934 if remotePeer.collectDir is None: 5935 raise ValueError("Remote peers must set a collect directory.") 5936 if (self.options is None or self.options.backupUser is None) and remotePeer.remoteUser is None: 5937 raise ValueError("Remote user must either be set in options section or individual remote peer.") 5938 if (self.options is None or self.options.rcpCommand is None) and remotePeer.rcpCommand is None: 5939 raise ValueError("Remote copy command must either be set in options section or individual remote peer.") 5940 if remotePeer.managed: 5941 if (self.options is None or self.options.rshCommand is None) and remotePeer.rshCommand is None: 5942 raise ValueError("Remote shell command must either be set in options section or individual remote peer.") 5943 if (self.options is None or self.options.cbackCommand is None) and remotePeer.cbackCommand is None: 5944 raise ValueError("Remote cback command must either be set in options section or individual remote peer.") 5945 if ((self.options is None or self.options.managedActions is None or len(self.options.managedActions) < 1) 5946 and (remotePeer.managedActions is None or len(remotePeer.managedActions) < 1)): 5947 raise ValueError("Managed actions list must be set in options section or individual remote peer.") 5948 checkUnique("Duplicate peer names exist:", names)
5949
5950 5951 ######################################################################## 5952 # General utility functions 5953 ######################################################################## 5954 5955 -def readByteQuantity(parent, name):
5956 """ 5957 Read a byte size value from an XML document. 5958 5959 A byte size value is an interpreted string value. If the string value 5960 ends with "MB" or "GB", then the string before that is interpreted as 5961 megabytes or gigabytes. Otherwise, it is intepreted as bytes. 5962 5963 @param parent: Parent node to search beneath. 5964 @param name: Name of node to search for. 5965 5966 @return: ByteQuantity parsed from XML document 5967 """ 5968 data = readString(parent, name) 5969 if data is None: 5970 return None 5971 data = data.strip() 5972 if data.endswith("KB"): 5973 quantity = data[0:data.rfind("KB")].strip() 5974 units = UNIT_KBYTES 5975 elif data.endswith("MB"): 5976 quantity = data[0:data.rfind("MB")].strip() 5977 units = UNIT_MBYTES 5978 elif data.endswith("GB"): 5979 quantity = data[0:data.rfind("GB")].strip() 5980 units = UNIT_GBYTES 5981 else: 5982 quantity = data.strip() 5983 units = UNIT_BYTES 5984 return ByteQuantity(quantity, units)
5985
5986 -def addByteQuantityNode(xmlDom, parentNode, nodeName, byteQuantity):
5987 """ 5988 Adds a text node as the next child of a parent, to contain a byte size. 5989 5990 If the C{byteQuantity} is None, then the node will be created, but will 5991 be empty (i.e. will contain no text node child). 5992 5993 The size in bytes will be normalized. If it is larger than 1.0 GB, it will 5994 be shown in GB ("1.0 GB"). If it is larger than 1.0 MB ("1.0 MB"), it will 5995 be shown in MB. Otherwise, it will be shown in bytes ("423413"). 5996 5997 @param xmlDom: DOM tree as from C{impl.createDocument()}. 5998 @param parentNode: Parent node to create child for. 5999 @param nodeName: Name of the new container node. 6000 @param byteQuantity: ByteQuantity object to put into the XML document 6001 6002 @return: Reference to the newly-created node. 6003 """ 6004 if byteQuantity is None: 6005 byteString = None 6006 elif byteQuantity.units == UNIT_KBYTES: 6007 byteString = "%s KB" % byteQuantity.quantity 6008 elif byteQuantity.units == UNIT_MBYTES: 6009 byteString = "%s MB" % byteQuantity.quantity 6010 elif byteQuantity.units == UNIT_GBYTES: 6011 byteString = "%s GB" % byteQuantity.quantity 6012 else: 6013 byteString = byteQuantity.quantity 6014 return addStringNode(xmlDom, parentNode, nodeName, byteString)
6015