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