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