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 1041 2013-05-10 02:05:13Z 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 - The eject delay must be an integer >= 0 3414 3415 Note that although the blanking factor must be a positive floating point 3416 number, it is stored as a string. This is done so that we can losslessly go 3417 back and forth between XML and object representations of configuration. 3418 3419 @sort: __init__, __repr__, __str__, __cmp__, sourceDir, 3420 mediaType, deviceType, devicePath, deviceScsiId, 3421 driveSpeed, checkData, checkMedia, warnMidnite, noEject, 3422 blankBehavior, refreshMediaDelay, ejectDelay 3423 """ 3424
3425 - def __init__(self, sourceDir=None, mediaType=None, deviceType=None, 3426 devicePath=None, deviceScsiId=None, driveSpeed=None, 3427 checkData=False, warnMidnite=False, noEject=False, 3428 checkMedia=False, blankBehavior=None, refreshMediaDelay=None, 3429 ejectDelay=None):
3430 """ 3431 Constructor for the C{StoreConfig} class. 3432 3433 @param sourceDir: Directory whose contents should be written to media. 3434 @param mediaType: Type of the media (see notes above). 3435 @param deviceType: Type of the device (optional, see notes above). 3436 @param devicePath: Filesystem device name for writer device, i.e. C{/dev/cdrw}. 3437 @param deviceScsiId: SCSI id for writer device, i.e. C{[<method>:]scsibus,target,lun}. 3438 @param driveSpeed: Speed of the drive, i.e. C{2} for 2x drive, etc. 3439 @param checkData: Whether resulting image should be validated. 3440 @param checkMedia: Whether media should be checked before being written to. 3441 @param warnMidnite: Whether to generate warnings for crossing midnite. 3442 @param noEject: Indicates that the writer device should not be ejected. 3443 @param blankBehavior: Controls optimized blanking behavior. 3444 @param refreshMediaDelay: Delay, in seconds, to add after refreshing media 3445 @param ejectDelay: Delay, in seconds, to add after ejecting media before closing the tray 3446 3447 @raise ValueError: If one of the values is invalid. 3448 """ 3449 self._sourceDir = None 3450 self._mediaType = None 3451 self._deviceType = None 3452 self._devicePath = None 3453 self._deviceScsiId = None 3454 self._driveSpeed = None 3455 self._checkData = None 3456 self._checkMedia = None 3457 self._warnMidnite = None 3458 self._noEject = None 3459 self._blankBehavior = None 3460 self._refreshMediaDelay = None 3461 self._ejectDelay = None 3462 self.sourceDir = sourceDir 3463 self.mediaType = mediaType 3464 self.deviceType = deviceType 3465 self.devicePath = devicePath 3466 self.deviceScsiId = deviceScsiId 3467 self.driveSpeed = driveSpeed 3468 self.checkData = checkData 3469 self.checkMedia = checkMedia 3470 self.warnMidnite = warnMidnite 3471 self.noEject = noEject 3472 self.blankBehavior = blankBehavior 3473 self.refreshMediaDelay = refreshMediaDelay 3474 self.ejectDelay = ejectDelay
3475
3476 - def __repr__(self):
3477 """ 3478 Official string representation for class instance. 3479 """ 3480 return "StoreConfig(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % ( 3481 self.sourceDir, self.mediaType, self.deviceType, 3482 self.devicePath, self.deviceScsiId, self.driveSpeed, 3483 self.checkData, self.warnMidnite, self.noEject, 3484 self.checkMedia, self.blankBehavior, self.refreshMediaDelay, 3485 self.ejectDelay)
3486
3487 - def __str__(self):
3488 """ 3489 Informal string representation for class instance. 3490 """ 3491 return self.__repr__()
3492
3493 - def __cmp__(self, other):
3494 """ 3495 Definition of equals operator for this class. 3496 @param other: Other object to compare to. 3497 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 3498 """ 3499 if other is None: 3500 return 1 3501 if self.sourceDir != other.sourceDir: 3502 if self.sourceDir < other.sourceDir: 3503 return -1 3504 else: 3505 return 1 3506 if self.mediaType != other.mediaType: 3507 if self.mediaType < other.mediaType: 3508 return -1 3509 else: 3510 return 1 3511 if self.deviceType != other.deviceType: 3512 if self.deviceType < other.deviceType: 3513 return -1 3514 else: 3515 return 1 3516 if self.devicePath != other.devicePath: 3517 if self.devicePath < other.devicePath: 3518 return -1 3519 else: 3520 return 1 3521 if self.deviceScsiId != other.deviceScsiId: 3522 if self.deviceScsiId < other.deviceScsiId: 3523 return -1 3524 else: 3525 return 1 3526 if self.driveSpeed != other.driveSpeed: 3527 if self.driveSpeed < other.driveSpeed: 3528 return -1 3529 else: 3530 return 1 3531 if self.checkData != other.checkData: 3532 if self.checkData < other.checkData: 3533 return -1 3534 else: 3535 return 1 3536 if self.checkMedia != other.checkMedia: 3537 if self.checkMedia < other.checkMedia: 3538 return -1 3539 else: 3540 return 1 3541 if self.warnMidnite != other.warnMidnite: 3542 if self.warnMidnite < other.warnMidnite: 3543 return -1 3544 else: 3545 return 1 3546 if self.noEject != other.noEject: 3547 if self.noEject < other.noEject: 3548 return -1 3549 else: 3550 return 1 3551 if self.blankBehavior != other.blankBehavior: 3552 if self.blankBehavior < other.blankBehavior: 3553 return -1 3554 else: 3555 return 1 3556 if self.refreshMediaDelay != other.refreshMediaDelay: 3557 if self.refreshMediaDelay < other.refreshMediaDelay: 3558 return -1 3559 else: 3560 return 1 3561 if self.ejectDelay != other.ejectDelay: 3562 if self.ejectDelay < other.ejectDelay: 3563 return -1 3564 else: 3565 return 1 3566 return 0
3567
3568 - def _setSourceDir(self, value):
3569 """ 3570 Property target used to set the source directory. 3571 The value must be an absolute path if it is not C{None}. 3572 It does not have to exist on disk at the time of assignment. 3573 @raise ValueError: If the value is not an absolute path. 3574 @raise ValueError: If the value cannot be encoded properly. 3575 """ 3576 if value is not None: 3577 if not os.path.isabs(value): 3578 raise ValueError("Source directory must be an absolute path.") 3579 self._sourceDir = encodePath(value)
3580
3581 - def _getSourceDir(self):
3582 """ 3583 Property target used to get the source directory. 3584 """ 3585 return self._sourceDir
3586
3587 - def _setMediaType(self, value):
3588 """ 3589 Property target used to set the media type. 3590 The value must be one of L{VALID_MEDIA_TYPES}. 3591 @raise ValueError: If the value is not valid. 3592 """ 3593 if value is not None: 3594 if value not in VALID_MEDIA_TYPES: 3595 raise ValueError("Media type must be one of %s." % VALID_MEDIA_TYPES) 3596 self._mediaType = value
3597
3598 - def _getMediaType(self):
3599 """ 3600 Property target used to get the media type. 3601 """ 3602 return self._mediaType
3603
3604 - def _setDeviceType(self, value):
3605 """ 3606 Property target used to set the device type. 3607 The value must be one of L{VALID_DEVICE_TYPES}. 3608 @raise ValueError: If the value is not valid. 3609 """ 3610 if value is not None: 3611 if value not in VALID_DEVICE_TYPES: 3612 raise ValueError("Device type must be one of %s." % VALID_DEVICE_TYPES) 3613 self._deviceType = value
3614
3615 - def _getDeviceType(self):
3616 """ 3617 Property target used to get the device type. 3618 """ 3619 return self._deviceType
3620
3621 - def _setDevicePath(self, value):
3622 """ 3623 Property target used to set the device path. 3624 The value must be an absolute path if it is not C{None}. 3625 It does not have to exist on disk at the time of assignment. 3626 @raise ValueError: If the value is not an absolute path. 3627 @raise ValueError: If the value cannot be encoded properly. 3628 """ 3629 if value is not None: 3630 if not os.path.isabs(value): 3631 raise ValueError("Device path must be an absolute path.") 3632 self._devicePath = encodePath(value)
3633
3634 - def _getDevicePath(self):
3635 """ 3636 Property target used to get the device path. 3637 """ 3638 return self._devicePath
3639
3640 - def _setDeviceScsiId(self, value):
3641 """ 3642 Property target used to set the SCSI id 3643 The SCSI id must be valid per L{validateScsiId}. 3644 @raise ValueError: If the value is not valid. 3645 """ 3646 if value is None: 3647 self._deviceScsiId = None 3648 else: 3649 self._deviceScsiId = validateScsiId(value)
3650
3651 - def _getDeviceScsiId(self):
3652 """ 3653 Property target used to get the SCSI id. 3654 """ 3655 return self._deviceScsiId
3656
3657 - def _setDriveSpeed(self, value):
3658 """ 3659 Property target used to set the drive speed. 3660 The drive speed must be valid per L{validateDriveSpeed}. 3661 @raise ValueError: If the value is not valid. 3662 """ 3663 self._driveSpeed = validateDriveSpeed(value)
3664
3665 - def _getDriveSpeed(self):
3666 """ 3667 Property target used to get the drive speed. 3668 """ 3669 return self._driveSpeed
3670
3671 - def _setCheckData(self, value):
3672 """ 3673 Property target used to set the check data flag. 3674 No validations, but we normalize the value to C{True} or C{False}. 3675 """ 3676 if value: 3677 self._checkData = True 3678 else: 3679 self._checkData = False
3680
3681 - def _getCheckData(self):
3682 """ 3683 Property target used to get the check data flag. 3684 """ 3685 return self._checkData
3686
3687 - def _setCheckMedia(self, value):
3688 """ 3689 Property target used to set the check media flag. 3690 No validations, but we normalize the value to C{True} or C{False}. 3691 """ 3692 if value: 3693 self._checkMedia = True 3694 else: 3695 self._checkMedia = False
3696
3697 - def _getCheckMedia(self):
3698 """ 3699 Property target used to get the check media flag. 3700 """ 3701 return self._checkMedia
3702
3703 - def _setWarnMidnite(self, value):
3704 """ 3705 Property target used to set the midnite warning flag. 3706 No validations, but we normalize the value to C{True} or C{False}. 3707 """ 3708 if value: 3709 self._warnMidnite = True 3710 else: 3711 self._warnMidnite = False
3712
3713 - def _getWarnMidnite(self):
3714 """ 3715 Property target used to get the midnite warning flag. 3716 """ 3717 return self._warnMidnite
3718
3719 - def _setNoEject(self, value):
3720 """ 3721 Property target used to set the no-eject flag. 3722 No validations, but we normalize the value to C{True} or C{False}. 3723 """ 3724 if value: 3725 self._noEject = True 3726 else: 3727 self._noEject = False
3728
3729 - def _getNoEject(self):
3730 """ 3731 Property target used to get the no-eject flag. 3732 """ 3733 return self._noEject
3734
3735 - def _setBlankBehavior(self, value):
3736 """ 3737 Property target used to set blanking behavior configuration. 3738 If not C{None}, the value must be a C{BlankBehavior} object. 3739 @raise ValueError: If the value is not a C{BlankBehavior} 3740 """ 3741 if value is None: 3742 self._blankBehavior = None 3743 else: 3744 if not isinstance(value, BlankBehavior): 3745 raise ValueError("Value must be a C{BlankBehavior} object.") 3746 self._blankBehavior = value
3747
3748 - def _getBlankBehavior(self):
3749 """ 3750 Property target used to get the blanking behavior configuration. 3751 """ 3752 return self._blankBehavior
3753
3754 - def _setRefreshMediaDelay(self, value):
3755 """ 3756 Property target used to set the refreshMediaDelay. 3757 The value must be an integer >= 0. 3758 @raise ValueError: If the value is not valid. 3759 """ 3760 if value is None: 3761 self._refreshMediaDelay = None 3762 else: 3763 try: 3764 value = int(value) 3765 except TypeError: 3766 raise ValueError("Action refreshMediaDelay value must be an integer >= 0.") 3767 if value < 0: 3768 raise ValueError("Action refreshMediaDelay value must be an integer >= 0.") 3769 if value == 0: 3770 value = None # normalize this out, since it's the default 3771 self._refreshMediaDelay = value
3772
3773 - def _getRefreshMediaDelay(self):
3774 """ 3775 Property target used to get the action refreshMediaDelay. 3776 """ 3777 return self._refreshMediaDelay
3778
3779 - def _setEjectDelay(self, value):
3780 """ 3781 Property target used to set the ejectDelay. 3782 The value must be an integer >= 0. 3783 @raise ValueError: If the value is not valid. 3784 """ 3785 if value is None: 3786 self._ejectDelay = None 3787 else: 3788 try: 3789 value = int(value) 3790 except TypeError: 3791 raise ValueError("Action ejectDelay value must be an integer >= 0.") 3792 if value < 0: 3793 raise ValueError("Action ejectDelay value must be an integer >= 0.") 3794 if value == 0: 3795 value = None # normalize this out, since it's the default 3796 self._ejectDelay = value
3797
3798 - def _getEjectDelay(self):
3799 """ 3800 Property target used to get the action ejectDelay. 3801 """ 3802 return self._ejectDelay
3803 3804 sourceDir = property(_getSourceDir, _setSourceDir, None, "Directory whose contents should be written to media.") 3805 mediaType = property(_getMediaType, _setMediaType, None, "Type of the media (see notes above).") 3806 deviceType = property(_getDeviceType, _setDeviceType, None, "Type of the device (optional, see notes above).") 3807 devicePath = property(_getDevicePath, _setDevicePath, None, "Filesystem device name for writer device.") 3808 deviceScsiId = property(_getDeviceScsiId, _setDeviceScsiId, None, "SCSI id for writer device (optional, see notes above).") 3809 driveSpeed = property(_getDriveSpeed, _setDriveSpeed, None, "Speed of the drive.") 3810 checkData = property(_getCheckData, _setCheckData, None, "Whether resulting image should be validated.") 3811 checkMedia = property(_getCheckMedia, _setCheckMedia, None, "Whether media should be checked before being written to.") 3812 warnMidnite = property(_getWarnMidnite, _setWarnMidnite, None, "Whether to generate warnings for crossing midnite.") 3813 noEject = property(_getNoEject, _setNoEject, None, "Indicates that the writer device should not be ejected.") 3814 blankBehavior = property(_getBlankBehavior, _setBlankBehavior, None, "Controls optimized blanking behavior.") 3815 refreshMediaDelay = property(_getRefreshMediaDelay, _setRefreshMediaDelay, None, "Delay, in seconds, to add after refreshing media.") 3816 ejectDelay = property(_getEjectDelay, _setEjectDelay, None, "Delay, in seconds, to add after ejecting media before closing the tray")
3817
3818 3819 ######################################################################## 3820 # PurgeConfig class definition 3821 ######################################################################## 3822 3823 -class PurgeConfig(object):
3824 3825 """ 3826 Class representing a Cedar Backup purge configuration. 3827 3828 The following restrictions exist on data in this class: 3829 3830 - The purge directory list must be a list of C{PurgeDir} objects. 3831 3832 For the C{purgeDirs} list, validation is accomplished through the 3833 L{util.ObjectTypeList} list implementation that overrides common list 3834 methods and transparently ensures that each element is a C{PurgeDir}. 3835 3836 @note: Lists within this class are "unordered" for equality comparisons. 3837 3838 @sort: __init__, __repr__, __str__, __cmp__, purgeDirs 3839 """ 3840
3841 - def __init__(self, purgeDirs=None):
3842 """ 3843 Constructor for the C{Purge} class. 3844 @param purgeDirs: List of purge directories. 3845 @raise ValueError: If one of the values is invalid. 3846 """ 3847 self._purgeDirs = None 3848 self.purgeDirs = purgeDirs
3849
3850 - def __repr__(self):
3851 """ 3852 Official string representation for class instance. 3853 """ 3854 return "PurgeConfig(%s)" % self.purgeDirs
3855
3856 - def __str__(self):
3857 """ 3858 Informal string representation for class instance. 3859 """ 3860 return self.__repr__()
3861
3862 - def __cmp__(self, other):
3863 """ 3864 Definition of equals operator for this class. 3865 Lists within this class are "unordered" for equality comparisons. 3866 @param other: Other object to compare to. 3867 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 3868 """ 3869 if other is None: 3870 return 1 3871 if self.purgeDirs != other.purgeDirs: 3872 if self.purgeDirs < other.purgeDirs: 3873 return -1 3874 else: 3875 return 1 3876 return 0
3877
3878 - def _setPurgeDirs(self, value):
3879 """ 3880 Property target used to set the purge dirs list. 3881 Either the value must be C{None} or each element must be a C{PurgeDir}. 3882 @raise ValueError: If the value is not a C{PurgeDir} 3883 """ 3884 if value is None: 3885 self._purgeDirs = None 3886 else: 3887 try: 3888 saved = self._purgeDirs 3889 self._purgeDirs = ObjectTypeList(PurgeDir, "PurgeDir") 3890 self._purgeDirs.extend(value) 3891 except Exception, e: 3892 self._purgeDirs = saved 3893 raise e
3894
3895 - def _getPurgeDirs(self):
3896 """ 3897 Property target used to get the purge dirs list. 3898 """ 3899 return self._purgeDirs
3900 3901 purgeDirs = property(_getPurgeDirs, _setPurgeDirs, None, "List of directories to purge.")
3902
3903 3904 ######################################################################## 3905 # Config class definition 3906 ######################################################################## 3907 3908 -class Config(object):
3909 3910 ###################### 3911 # Class documentation 3912 ###################### 3913 3914 """ 3915 Class representing a Cedar Backup XML configuration document. 3916 3917 The C{Config} class is a Python object representation of a Cedar Backup XML 3918 configuration file. It is intended to be the only Python-language interface 3919 to Cedar Backup configuration on disk for both Cedar Backup itself and for 3920 external applications. 3921 3922 The object representation is two-way: XML data can be used to create a 3923 C{Config} object, and then changes to the object can be propogated back to 3924 disk. A C{Config} object can even be used to create a configuration file 3925 from scratch programmatically. 3926 3927 This class and the classes it is composed from often use Python's 3928 C{property} construct to validate input and limit access to values. Some 3929 validations can only be done once a document is considered "complete" 3930 (see module notes for more details). 3931 3932 Assignments to the various instance variables must match the expected 3933 type, i.e. C{reference} must be a C{ReferenceConfig}. The internal check 3934 uses the built-in C{isinstance} function, so it should be OK to use 3935 subclasses if you want to. 3936 3937 If an instance variable is not set, its value will be C{None}. When an 3938 object is initialized without using an XML document, all of the values 3939 will be C{None}. Even when an object is initialized using XML, some of 3940 the values might be C{None} because not every section is required. 3941 3942 @note: Lists within this class are "unordered" for equality comparisons. 3943 3944 @sort: __init__, __repr__, __str__, __cmp__, extractXml, validate, 3945 reference, extensions, options, collect, stage, store, purge, 3946 _getReference, _setReference, _getExtensions, _setExtensions, 3947 _getOptions, _setOptions, _getPeers, _setPeers, _getCollect, 3948 _setCollect, _getStage, _setStage, _getStore, _setStore, 3949 _getPurge, _setPurge 3950 """ 3951 3952 ############## 3953 # Constructor 3954 ############## 3955
3956 - def __init__(self, xmlData=None, xmlPath=None, validate=True):
3957 """ 3958 Initializes a configuration object. 3959 3960 If you initialize the object without passing either C{xmlData} or 3961 C{xmlPath}, then configuration will be empty and will be invalid until it 3962 is filled in properly. 3963 3964 No reference to the original XML data or original path is saved off by 3965 this class. Once the data has been parsed (successfully or not) this 3966 original information is discarded. 3967 3968 Unless the C{validate} argument is C{False}, the L{Config.validate} 3969 method will be called (with its default arguments) against configuration 3970 after successfully parsing any passed-in XML. Keep in mind that even if 3971 C{validate} is C{False}, it might not be possible to parse the passed-in 3972 XML document if lower-level validations fail. 3973 3974 @note: It is strongly suggested that the C{validate} option always be set 3975 to C{True} (the default) unless there is a specific need to read in 3976 invalid configuration from disk. 3977 3978 @param xmlData: XML data representing configuration. 3979 @type xmlData: String data. 3980 3981 @param xmlPath: Path to an XML file on disk. 3982 @type xmlPath: Absolute path to a file on disk. 3983 3984 @param validate: Validate the document after parsing it. 3985 @type validate: Boolean true/false. 3986 3987 @raise ValueError: If both C{xmlData} and C{xmlPath} are passed-in. 3988 @raise ValueError: If the XML data in C{xmlData} or C{xmlPath} cannot be parsed. 3989 @raise ValueError: If the parsed configuration document is not valid. 3990 """ 3991 self._reference = None 3992 self._extensions = None 3993 self._options = None 3994 self._peers = None 3995 self._collect = None 3996 self._stage = None 3997 self._store = None 3998 self._purge = None 3999 self.reference = None 4000 self.extensions = None 4001 self.options = None 4002 self.peers = None 4003 self.collect = None 4004 self.stage = None 4005 self.store = None 4006 self.purge = None 4007 if xmlData is not None and xmlPath is not None: 4008 raise ValueError("Use either xmlData or xmlPath, but not both.") 4009 if xmlData is not None: 4010 self._parseXmlData(xmlData) 4011 if validate: 4012 self.validate() 4013 elif xmlPath is not None: 4014 xmlData = open(xmlPath).read() 4015 self._parseXmlData(xmlData) 4016 if validate: 4017 self.validate()
4018 4019 4020 ######################### 4021 # String representations 4022 ######################### 4023
4024 - def __repr__(self):
4025 """ 4026 Official string representation for class instance. 4027 """ 4028 return "Config(%s, %s, %s, %s, %s, %s, %s, %s)" % (self.reference, self.extensions, self.options, 4029 self.peers, self.collect, self.stage, self.store, 4030 self.purge)
4031
4032 - def __str__(self):
4033 """ 4034 Informal string representation for class instance. 4035 """ 4036 return self.__repr__()
4037 4038 4039 ############################# 4040 # Standard comparison method 4041 ############################# 4042
4043 - def __cmp__(self, other):
4044 """ 4045 Definition of equals operator for this class. 4046 Lists within this class are "unordered" for equality comparisons. 4047 @param other: Other object to compare to. 4048 @return: -1/0/1 depending on whether self is C{<}, C{=} or C{>} other. 4049 """ 4050 if other is None: 4051 return 1 4052 if self.reference != other.reference: 4053 if self.reference < other.reference: 4054 return -1 4055 else: 4056 return 1 4057 if self.extensions != other.extensions: 4058 if self.extensions < other.extensions: 4059 return -1 4060 else: 4061 return 1 4062 if self.options != other.options: 4063 if self.options < other.options: 4064 return -1 4065 else: 4066 return 1 4067 if self.peers != other.peers: 4068 if self.peers < other.peers: 4069 return -1 4070 else: 4071 return 1 4072 if self.collect != other.collect: 4073 if self.collect < other.collect: 4074 return -1 4075 else: 4076 return 1 4077 if self.stage != other.stage: 4078 if self.stage < other.stage: 4079 return -1 4080 else: 4081 return 1 4082 if self.store != other.store: 4083 if self.store < other.store: 4084 return -1 4085 else: 4086 return 1 4087 if self.purge != other.purge: 4088 if self.purge < other.purge: 4089 return -1 4090 else: 4091 return 1 4092 return 0
4093 4094 4095 ############# 4096 # Properties 4097 ############# 4098
4099 - def _setReference(self, value):
4100 """ 4101 Property target used to set the reference configuration value. 4102 If not C{None}, the value must be a C{ReferenceConfig} object. 4103 @raise ValueError: If the value is not a C{ReferenceConfig} 4104 """ 4105 if value is None: 4106 self._reference = None 4107 else: 4108 if not isinstance(value, ReferenceConfig): 4109 raise ValueError("Value must be a C{ReferenceConfig} object.") 4110 self._reference = value
4111
4112 - def _getReference(self):
4113 """ 4114 Property target used to get the reference configuration value. 4115 """ 4116 return self._reference
4117
4118 - def _setExtensions(self, value):
4119 """ 4120 Property target used to set the extensions configuration value. 4121 If not C{None}, the value must be a C{ExtensionsConfig} object. 4122 @raise ValueError: If the value is not a C{ExtensionsConfig} 4123 """ 4124 if value is None: 4125 self._extensions = None 4126 else: 4127 if not isinstance(value, ExtensionsConfig): 4128 raise ValueError("Value must be a C{ExtensionsConfig} object.") 4129 self._extensions = value
4130
4131 - def _getExtensions(self):
4132 """ 4133 Property target used to get the extensions configuration value. 4134 """ 4135 return self._extensions
4136
4137 - def _setOptions(self, value):
4138 """ 4139 Property target used to set the options configuration value. 4140 If not C{None}, the value must be an C{OptionsConfig} object. 4141 @raise ValueError: If the value is not a C{OptionsConfig} 4142 """ 4143 if value is None: 4144 self._options = None 4145 else: 4146 if not isinstance(value, OptionsConfig): 4147 raise ValueError("Value must be a C{OptionsConfig} object.") 4148 self._options = value
4149
4150 - def _getOptions(self):
4151 """ 4152 Property target used to get the options configuration value. 4153 """ 4154 return self._options
4155
4156 - def _setPeers(self, value):
4157 """ 4158 Property target used to set the peers configuration value. 4159 If not C{None}, the value must be an C{PeersConfig} object. 4160 @raise ValueError: If the value is not a C{PeersConfig} 4161 """ 4162 if value is None: 4163 self._peers = None 4164 else: 4165 if not isinstance(value, PeersConfig): 4166 raise ValueError("Value must be a C{PeersConfig} object.") 4167 self._peers = value
4168
4169 - def _getPeers(self):
4170 """ 4171 Property target used to get the peers configuration value. 4172 """ 4173 return self._peers
4174
4175 - def _setCollect(self, value):
4176 """ 4177 Property target used to set the collect configuration value. 4178 If not C{None}, the value must be a C{CollectConfig} object. 4179 @raise ValueError: If the value is not a C{CollectConfig} 4180 """ 4181 if value is None: 4182 self._collect = None 4183 else: 4184 if not isinstance(value, CollectConfig): 4185 raise ValueError("Value must be a C{CollectConfig} object.") 4186 self._collect = value
4187
4188 - def _getCollect(self):
4189 """ 4190 Property target used to get the collect configuration value. 4191 """ 4192 return self._collect
4193
4194 - def _setStage(self, value):
4195 """ 4196 Property target used to set the stage configuration value. 4197 If not C{None}, the value must be a C{StageConfig} object. 4198 @raise ValueError: If the value is not a C{StageConfig} 4199 """ 4200 if value is None: 4201 self._stage = None 4202 else: 4203 if not isinstance(value, StageConfig): 4204 raise ValueError("Value must be a C{StageConfig} object.") 4205 self._stage = value
4206
4207 - def _getStage(self):
4208 """ 4209 Property target used to get the stage configuration value. 4210 """ 4211 return self._stage
4212
4213 - def _setStore(self, value):
4214 """ 4215 Property target used to set the store configuration value. 4216 If not C{None}, the value must be a C{StoreConfig} object. 4217 @raise ValueError: If the value is not a C{StoreConfig} 4218 """ 4219 if value is None: 4220 self._store = None 4221 else: 4222 if not isinstance(value, StoreConfig): 4223 raise ValueError("Value must be a C{StoreConfig} object.") 4224 self._store = value
4225
4226 - def _getStore(self):
4227 """ 4228 Property target used to get the store configuration value. 4229 """ 4230 return self._store
4231
4232 - def _setPurge(self, value):
4233 """ 4234 Property target used to set the purge configuration value. 4235 If not C{None}, the value must be a C{PurgeConfig} object. 4236 @raise ValueError: If the value is not a C{PurgeConfig} 4237 """ 4238 if value is None: 4239 self._purge = None 4240 else: 4241 if not isinstance(value, PurgeConfig): 4242 raise ValueError("Value must be a C{PurgeConfig} object.") 4243 self._purge = value
4244
4245 - def _getPurge(self):
4246 """ 4247 Property target used to get the purge configuration value. 4248 """ 4249 return self._purge
4250 4251 reference = property(_getReference, _setReference, None, "Reference configuration in terms of a C{ReferenceConfig} object.") 4252 extensions = property(_getExtensions, _setExtensions, None, "Extensions configuration in terms of a C{ExtensionsConfig} object.") 4253 options = property(_getOptions, _setOptions, None, "Options configuration in terms of a C{OptionsConfig} object.") 4254 peers = property(_getPeers, _setPeers, None, "Peers configuration in terms of a C{PeersConfig} object.") 4255 collect = property(_getCollect, _setCollect, None, "Collect configuration in terms of a C{CollectConfig} object.") 4256 stage = property(_getStage, _setStage, None, "Stage configuration in terms of a C{StageConfig} object.") 4257 store = property(_getStore, _setStore, None, "Store configuration in terms of a C{StoreConfig} object.") 4258 purge = property(_getPurge, _setPurge, None, "Purge configuration in terms of a C{PurgeConfig} object.") 4259 4260 4261 ################# 4262 # Public methods 4263 ################# 4264
4265 - def extractXml(self, xmlPath=None, validate=True):
4266 """ 4267 Extracts configuration into an XML document. 4268 4269 If C{xmlPath} is not provided, then the XML document will be returned as 4270 a string. If C{xmlPath} is provided, then the XML document will be written 4271 to the file and C{None} will be returned. 4272 4273 Unless the C{validate} parameter is C{False}, the L{Config.validate} 4274 method will be called (with its default arguments) against the 4275 configuration before extracting the XML. If configuration is not valid, 4276 then an XML document will not be extracted. 4277 4278 @note: It is strongly suggested that the C{validate} option always be set 4279 to C{True} (the default) unless there is a specific need to write an 4280 invalid configuration file to disk. 4281 4282 @param xmlPath: Path to an XML file to create on disk. 4283 @type xmlPath: Absolute path to a file. 4284 4285 @param validate: Validate the document before extracting it. 4286 @type validate: Boolean true/false. 4287 4288 @return: XML string data or C{None} as described above. 4289 4290 @raise ValueError: If configuration within the object is not valid. 4291 @raise IOError: If there is an error writing to the file. 4292 @raise OSError: If there is an error writing to the file. 4293 """ 4294 if validate: 4295 self.validate() 4296 xmlData = self._extractXml() 4297 if xmlPath is not None: 4298 open(xmlPath, "w").write(xmlData) 4299 return None 4300 else: 4301 return xmlData
4302
4303 - def validate(self, requireOneAction=True, requireReference=False, requireExtensions=False, requireOptions=True, 4304 requireCollect=False, requireStage=False, requireStore=False, requirePurge=False, requirePeers=False):
4305 """ 4306 Validates configuration represented by the object. 4307 4308 This method encapsulates all of the validations that should apply to a 4309 fully "complete" document but are not already taken care of by earlier 4310 validations. It also provides some extra convenience functionality which 4311 might be useful to some people. The process of validation is laid out in 4312 the I{Validation} section in the class notes (above). 4313 4314 @param requireOneAction: Require at least one of the collect, stage, store or purge sections. 4315 @param requireReference: Require the reference section. 4316 @param requireExtensions: Require the extensions section. 4317 @param requireOptions: Require the options section. 4318 @param requirePeers: Require the peers section. 4319 @param requireCollect: Require the collect section. 4320 @param requireStage: Require the stage section. 4321 @param requireStore: Require the store section. 4322 @param requirePurge: Require the purge section. 4323 4324 @raise ValueError: If one of the validations fails. 4325 """ 4326 if requireOneAction and (self.collect, self.stage, self.store, self.purge) == (None, None, None, None): 4327 raise ValueError("At least one of the collect, stage, store and purge sections is required.") 4328 if requireReference and self.reference is None: 4329 raise ValueError("The reference is section is required.") 4330 if requireExtensions and self.extensions is None: 4331 raise ValueError("The extensions is section is required.") 4332 if requireOptions and self.options is None: 4333 raise ValueError("The options is section is required.") 4334 if requirePeers and self.peers is None: 4335 raise ValueError("The peers is section is required.") 4336 if requireCollect and self.collect is None: 4337 raise ValueError("The collect is section is required.") 4338 if requireStage and self.stage is None: 4339 raise ValueError("The stage is section is required.") 4340 if requireStore and self.store is None: 4341 raise ValueError("The store is section is required.") 4342 if requirePurge and self.purge is None: 4343 raise ValueError("The purge is section is required.") 4344 self._validateContents()
4345 4346 4347 ##################################### 4348 # High-level methods for parsing XML 4349 ##################################### 4350
4351 - def _parseXmlData(self, xmlData):
4352 """ 4353 Internal method to parse an XML string into the object. 4354 4355 This method parses the XML document into a DOM tree (C{xmlDom}) and then 4356 calls individual static methods to parse each of the individual 4357 configuration sections. 4358 4359 Most of the validation we do here has to do with whether the document can 4360 be parsed and whether any values which exist are valid. We don't do much 4361 validation as to whether required elements actually exist unless we have 4362 to to make sense of the document (instead, that's the job of the 4363 L{validate} method). 4364 4365 @param xmlData: XML data to be parsed 4366 @type xmlData: String data 4367 4368 @raise ValueError: If the XML cannot be successfully parsed. 4369 """ 4370 (xmlDom, parentNode) = createInputDom(xmlData) 4371 self._reference = Config._parseReference(parentNode) 4372 self._extensions = Config._parseExtensions(parentNode) 4373 self._options = Config._parseOptions(parentNode) 4374 self._peers = Config._parsePeers(parentNode) 4375 self._collect = Config._parseCollect(parentNode) 4376 self._stage = Config._parseStage(parentNode) 4377 self._store = Config._parseStore(parentNode) 4378 self._purge = Config._parsePurge(parentNode)
4379 4380 @staticmethod
4381 - def _parseReference(parentNode):
4382 """ 4383 Parses a reference configuration section. 4384 4385 We read the following fields:: 4386 4387 author //cb_config/reference/author 4388 revision //cb_config/reference/revision 4389 description //cb_config/reference/description 4390 generator //cb_config/reference/generator 4391 4392 @param parentNode: Parent node to search beneath. 4393 4394 @return: C{ReferenceConfig} object or C{None} if the section does not exist. 4395 @raise ValueError: If some filled-in value is invalid. 4396 """ 4397 reference = None 4398 sectionNode = readFirstChild(parentNode, "reference") 4399 if sectionNode is not None: 4400 reference = ReferenceConfig() 4401 reference.author = readString(sectionNode, "author") 4402 reference.revision = readString(sectionNode, "revision") 4403 reference.description = readString(sectionNode, "description") 4404 reference.generator = readString(sectionNode, "generator") 4405 return reference
4406 4407 @staticmethod
4408 - def _parseExtensions(parentNode):
4409 """ 4410 Parses an extensions configuration section. 4411 4412 We read the following fields:: 4413 4414 orderMode //cb_config/extensions/order_mode 4415 4416 We also read groups of the following items, one list element per item:: 4417 4418 name //cb_config/extensions/action/name 4419 module //cb_config/extensions/action/module 4420 function //cb_config/extensions/action/function 4421 index //cb_config/extensions/action/index 4422 dependencies //cb_config/extensions/action/depends 4423 4424 The extended actions are parsed by L{_parseExtendedActions}. 4425 4426 @param parentNode: Parent node to search beneath. 4427 4428 @return: C{ExtensionsConfig} object or C{None} if the section does not exist. 4429 @raise ValueError: If some filled-in value is invalid. 4430 """ 4431 extensions = None 4432 sectionNode = readFirstChild(parentNode, "extensions") 4433 if sectionNode is not None: 4434 extensions = ExtensionsConfig() 4435 extensions.orderMode = readString(sectionNode, "order_mode") 4436 extensions.actions = Config._parseExtendedActions(sectionNode) 4437 return extensions
4438 4439 @staticmethod
4440 - def _parseOptions(parentNode):
4441 """ 4442 Parses a options configuration section. 4443 4444 We read the following fields:: 4445 4446 startingDay //cb_config/options/starting_day 4447 workingDir //cb_config/options/working_dir 4448 backupUser //cb_config/options/backup_user 4449 backupGroup //cb_config/options/backup_group 4450 rcpCommand //cb_config/options/rcp_command 4451 rshCommand //cb_config/options/rsh_command 4452 cbackCommand //cb_config/options/cback_command 4453 managedActions //cb_config/options/managed_actions 4454 4455 The list of managed actions is a comma-separated list of action names. 4456 4457 We also read groups of the following items, one list element per 4458 item:: 4459 4460 overrides //cb_config/options/override 4461 hooks //cb_config/options/hook 4462 4463 The overrides are parsed by L{_parseOverrides} and the hooks are parsed 4464 by L{_parseHooks}. 4465 4466 @param parentNode: Parent node to search beneath. 4467 4468 @return: C{OptionsConfig} object or C{None} if the section does not exist. 4469 @raise ValueError: If some filled-in value is invalid. 4470 """ 4471 options = None 4472 sectionNode = readFirstChild(parentNode, "options") 4473 if sectionNode is not None: 4474 options = OptionsConfig() 4475 options.startingDay = readString(sectionNode, "starting_day") 4476 options.workingDir = readString(sectionNode, "working_dir") 4477 options.backupUser = readString(sectionNode, "backup_user") 4478 options.backupGroup = readString(sectionNode, "backup_group") 4479 options.rcpCommand = readString(sectionNode, "rcp_command") 4480 options.rshCommand = readString(sectionNode, "rsh_command") 4481 options.cbackCommand = readString(sectionNode, "cback_command") 4482 options.overrides = Config._parseOverrides(sectionNode) 4483 options.hooks = Config._parseHooks(sectionNode) 4484 managedActions = readString(sectionNode, "managed_actions") 4485 options.managedActions = parseCommaSeparatedString(managedActions) 4486 return options
4487 4488 @staticmethod
4489 - def _parsePeers(parentNode):
4490 """ 4491 Parses a peers configuration section. 4492 4493 We read groups of the following items, one list element per 4494 item:: 4495 4496 localPeers //cb_config/stage/peer 4497 remotePeers //cb_config/stage/peer 4498 4499 The individual peer entries are parsed by L{_parsePeerList}. 4500 4501 @param parentNode: Parent node to search beneath. 4502 4503 @return: C{StageConfig} object or C{None} if the section does not exist. 4504 @raise ValueError: If some filled-in value is invalid. 4505 """ 4506 peers = None 4507 sectionNode = readFirstChild(parentNode, "peers") 4508 if sectionNode is not None: 4509 peers = PeersConfig() 4510 (peers.localPeers, peers.remotePeers) = Config._parsePeerList(sectionNode) 4511 return peers
4512 4513 @staticmethod
4514 - def _parseCollect(parentNode):
4515 """ 4516 Parses a collect configuration section. 4517 4518 We read the following individual fields:: 4519 4520 targetDir //cb_config/collect/collect_dir 4521 collectMode //cb_config/collect/collect_mode 4522 archiveMode //cb_config/collect/archive_mode 4523 ignoreFile //cb_config/collect/ignore_file 4524 4525 We also read groups of the following items, one list element per 4526 item:: 4527 4528 absoluteExcludePaths //cb_config/collect/exclude/abs_path 4529 excludePatterns //cb_config/collect/exclude/pattern 4530 collectFiles //cb_config/collect/file 4531 collectDirs //cb_config/collect/dir 4532 4533 The exclusions are parsed by L{_parseExclusions}, the collect files are 4534 parsed by L{_parseCollectFiles}, and the directories are parsed by 4535 L{_parseCollectDirs}. 4536 4537 @param parentNode: Parent node to search beneath. 4538 4539 @return: C{CollectConfig} object or C{None} if the section does not exist. 4540 @raise ValueError: If some filled-in value is invalid. 4541 """ 4542 collect = None 4543 sectionNode = readFirstChild(parentNode, "collect") 4544 if sectionNode is not None: 4545 collect = CollectConfig() 4546 collect.targetDir = readString(sectionNode, "collect_dir") 4547 collect.collectMode = readString(sectionNode, "collect_mode") 4548 collect.archiveMode = readString(sectionNode, "archive_mode") 4549 collect.ignoreFile = readString(sectionNode, "ignore_file") 4550 (collect.absoluteExcludePaths, unused, collect.excludePatterns) = Config._parseExclusions(sectionNode) 4551 collect.collectFiles = Config._parseCollectFiles(sectionNode) 4552 collect.collectDirs = Config._parseCollectDirs(sectionNode) 4553 return collect
4554 4555 @staticmethod
4556 - def _parseStage(parentNode):
4557 """ 4558 Parses a stage configuration section. 4559 4560 We read the following individual fields:: 4561 4562 targetDir //cb_config/stage/staging_dir 4563 4564 We also read groups of the following items, one list element per 4565 item:: 4566 4567 localPeers //cb_config/stage/peer 4568 remotePeers //cb_config/stage/peer 4569 4570 The individual peer entries are parsed by L{_parsePeerList}. 4571 4572 @param parentNode: Parent node to search beneath. 4573 4574 @return: C{StageConfig} object or C{None} if the section does not exist. 4575 @raise ValueError: If some filled-in value is invalid. 4576 """ 4577 stage = None 4578 sectionNode = readFirstChild(parentNode, "stage") 4579 if sectionNode is not None: 4580 stage = StageConfig() 4581 stage.targetDir = readString(sectionNode, "staging_dir") 4582 (stage.localPeers, stage.remotePeers) = Config._parsePeerList(sectionNode) 4583 return stage
4584 4585 @staticmethod
4586 - def _parseStore(parentNode):
4587 """ 4588 Parses a store configuration section. 4589 4590 We read the following fields:: 4591 4592 sourceDir //cb_config/store/source_dir 4593 mediaType //cb_config/store/media_type 4594 deviceType //cb_config/store/device_type 4595 devicePath //cb_config/store/target_device 4596 deviceScsiId //cb_config/store/target_scsi_id 4597 driveSpeed //cb_config/store/drive_speed 4598 checkData //cb_config/store/check_data 4599 checkMedia //cb_config/store/check_media 4600 warnMidnite //cb_config/store/warn_midnite 4601 noEject //cb_config/store/no_eject 4602 4603 Blanking behavior configuration is parsed by the C{_parseBlankBehavior} 4604 method. 4605 4606 @param parentNode: Parent node to search beneath. 4607 4608 @return: C{StoreConfig} object or C{None} if the section does not exist. 4609 @raise ValueError: If some filled-in value is invalid. 4610 """ 4611 store = None 4612 sectionNode = readFirstChild(parentNode, "store") 4613 if sectionNode is not None: 4614 store = StoreConfig() 4615 store.sourceDir = readString(sectionNode, "source_dir") 4616 store.mediaType = readString(sectionNode, "media_type") 4617 store.deviceType = readString(sectionNode, "device_type") 4618 store.devicePath = readString(sectionNode, "target_device") 4619 store.deviceScsiId = readString(sectionNode, "target_scsi_id") 4620 store.driveSpeed = readInteger(sectionNode, "drive_speed") 4621 store.checkData = readBoolean(sectionNode, "check_data") 4622 store.checkMedia = readBoolean(sectionNode, "check_media") 4623 store.warnMidnite = readBoolean(sectionNode, "warn_midnite") 4624 store.noEject = readBoolean(sectionNode, "no_eject") 4625 store.blankBehavior = Config._parseBlankBehavior(sectionNode) 4626 store.refreshMediaDelay = readInteger(sectionNode, "refresh_media_delay") 4627 store.ejectDelay = readInteger(sectionNode, "eject_delay") 4628 return store
4629 4630 @staticmethod
4631 - def _parsePurge(parentNode):
4632 """ 4633 Parses a purge configuration section. 4634 4635 We read groups of the following items, one list element per 4636 item:: 4637 4638 purgeDirs //cb_config/purge/dir 4639 4640 The individual directory entries are parsed by L{_parsePurgeDirs}. 4641 4642 @param parentNode: Parent node to search beneath. 4643 4644 @return: C{PurgeConfig} object or C{None} if the section does not exist. 4645 @raise ValueError: If some filled-in value is invalid. 4646 """ 4647 purge = None 4648 sectionNode = readFirstChild(parentNode, "purge") 4649 if sectionNode is not None: 4650 purge = PurgeConfig() 4651 purge.purgeDirs = Config._parsePurgeDirs(sectionNode) 4652 return purge
4653 4654 @staticmethod
4655 - def _parseExtendedActions(parentNode):
4656 """ 4657 Reads extended actions data from immediately beneath the parent. 4658 4659 We read the following individual fields from each extended action:: 4660 4661 name name 4662 module module 4663 function function 4664 index index 4665 dependencies depends 4666 4667 Dependency information is parsed by the C{_parseDependencies} method. 4668 4669 @param parentNode: Parent node to search beneath. 4670 4671 @return: List of extended actions. 4672 @raise ValueError: If the data at the location can't be read 4673 """ 4674 lst = [] 4675 for entry in readChildren(parentNode, "action"): 4676 if isElement(entry): 4677 action = ExtendedAction() 4678 action.name = readString(entry, "name") 4679 action.module = readString(entry, "module") 4680 action.function = readString(entry, "function") 4681 action.index = readInteger(entry, "index") 4682 action.dependencies = Config._parseDependencies(entry) 4683 lst.append(action) 4684 if lst == []: 4685 lst = None 4686 return lst
4687 4688 @staticmethod
4689 - def _parseExclusions(parentNode):
4690 """ 4691 Reads exclusions data from immediately beneath the parent. 4692 4693 We read groups of the following items, one list element per item:: 4694 4695 absolute exclude/abs_path 4696 relative exclude/rel_path 4697 patterns exclude/pattern 4698 4699 If there are none of some pattern (i.e. no relative path items) then 4700 C{None} will be returned for that item in the tuple. 4701 4702 This method can be used to parse exclusions on both the collect 4703 configuration level and on the collect directory level within collect 4704 configuration. 4705 4706 @param parentNode: Parent node to search beneath. 4707 4708 @return: Tuple of (absolute, relative, patterns) exclusions. 4709 """ 4710 sectionNode = readFirstChild(parentNode, "exclude") 4711 if sectionNode is None: 4712 return (None, None, None) 4713 else: 4714 absolute = readStringList(sectionNode, "abs_path") 4715 relative = readStringList(sectionNode, "rel_path") 4716 patterns = readStringList(sectionNode, "pattern") 4717 return (absolute, relative, patterns)
4718 4719 @staticmethod
4720 - def _parseOverrides(parentNode):
4721 """ 4722 Reads a list of C{CommandOverride} objects from immediately beneath the parent. 4723 4724 We read the following individual fields:: 4725 4726 command command 4727 absolutePath abs_path 4728 4729 @param parentNode: Parent node to search beneath. 4730 4731 @return: List of C{CommandOverride} objects or C{None} if none are found. 4732 @raise ValueError: If some filled-in value is invalid. 4733 """ 4734 lst = [] 4735 for entry in readChildren(parentNode, "override"): 4736 if isElement(entry): 4737 override = CommandOverride() 4738 override.command = readString(entry, "command") 4739 override.absolutePath = readString(entry, "abs_path") 4740 lst.append(override) 4741 if lst == []: 4742 lst = None 4743 return lst
4744 4745 @staticmethod
4746 - def _parseHooks(parentNode):
4747 """ 4748 Reads a list of C{ActionHook} objects from immediately beneath the parent. 4749 4750 We read the following individual fields:: 4751 4752 action action 4753 command command 4754 4755 @param parentNode: Parent node to search beneath. 4756 4757 @return: List of C{ActionHook} 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, "pre_action_hook"): 4762 if isElement(entry): 4763 hook = PreActionHook() 4764 hook.action = readString(entry, "action") 4765 hook.command = readString(entry, "command") 4766 lst.append(hook) 4767 for entry in readChildren(parentNode, "post_action_hook"): 4768 if isElement(entry): 4769 hook = PostActionHook() 4770 hook.action = readString(entry, "action") 4771 hook.command = readString(entry, "command") 4772 lst.append(hook) 4773 if lst == []: 4774 lst = None 4775 return lst
4776 4777 @staticmethod
4778 - def _parseCollectFiles(parentNode):
4779 """ 4780 Reads a list of C{CollectFile} objects from immediately beneath the parent. 4781 4782 We read the following individual fields:: 4783 4784 absolutePath abs_path 4785 collectMode mode I{or} collect_mode 4786 archiveMode archive_mode 4787 4788 The collect mode is a special case. Just a C{mode} tag is accepted, but 4789 we prefer C{collect_mode} for consistency with the rest of the config 4790 file and to avoid confusion with the archive mode. If both are provided, 4791 only C{mode} will be used. 4792 4793 @param parentNode: Parent node to search beneath. 4794 4795 @return: List of C{CollectFile} objects or C{None} if none are found. 4796 @raise ValueError: If some filled-in value is invalid. 4797 """ 4798 lst = [] 4799 for entry in readChildren(parentNode, "file"): 4800 if isElement(entry): 4801 cfile = CollectFile() 4802 cfile.absolutePath = readString(entry, "abs_path") 4803 cfile.collectMode = readString(entry, "mode") 4804 if cfile.collectMode is None: 4805 cfile.collectMode = readString(entry, "collect_mode") 4806 cfile.archiveMode = readString(entry, "archive_mode") 4807 lst.append(cfile) 4808 if lst == []: 4809 lst = None 4810 return lst
4811 4812 @staticmethod
4813 - def _parseCollectDirs(parentNode):
4814 """ 4815 Reads a list of C{CollectDir} objects from immediately beneath the parent. 4816 4817 We read the following individual fields:: 4818 4819 absolutePath abs_path 4820 collectMode mode I{or} collect_mode 4821 archiveMode archive_mode 4822 ignoreFile ignore_file 4823 linkDepth link_depth 4824 dereference dereference 4825 recursionLevel recursion_level 4826 4827 The collect mode is a special case. Just a C{mode} tag is accepted for 4828 backwards compatibility, but we prefer C{collect_mode} for consistency 4829 with the rest of the config file and to avoid confusion with the archive 4830 mode. If both are provided, only C{mode} will be used. 4831 4832 We also read groups of the following items, one list element per 4833 item:: 4834 4835 absoluteExcludePaths exclude/abs_path 4836 relativeExcludePaths exclude/rel_path 4837 excludePatterns exclude/pattern 4838 4839 The exclusions are parsed by L{_parseExclusions}. 4840 4841 @param parentNode: Parent node to search beneath. 4842 4843 @return: List of C{CollectDir} objects or C{None} if none are found. 4844 @raise ValueError: If some filled-in value is invalid. 4845 """ 4846 lst = [] 4847 for entry in readChildren(parentNode, "dir"): 4848 if isElement(entry): 4849 cdir = CollectDir() 4850 cdir.absolutePath = readString(entry, "abs_path") 4851 cdir.collectMode = readString(entry, "mode") 4852 if cdir.collectMode is None: 4853 cdir.collectMode = readString(entry, "collect_mode") 4854 cdir.archiveMode = readString(entry, "archive_mode") 4855 cdir.ignoreFile = readString(entry, "ignore_file") 4856 cdir.linkDepth = readInteger(entry, "link_depth") 4857 cdir.dereference = readBoolean(entry, "dereference") 4858 cdir.recursionLevel = readInteger(entry, "recursion_level") 4859 (cdir.absoluteExcludePaths, cdir.relativeExcludePaths, cdir.excludePatterns) = Config._parseExclusions(entry) 4860 lst.append(cdir) 4861 if lst == []: 4862 lst = None 4863 return lst
4864 4865 @staticmethod
4866 - def _parsePurgeDirs(parentNode):
4867 """ 4868 Reads a list of C{PurgeDir} objects from immediately beneath the parent. 4869 4870 We read the following individual fields:: 4871 4872 absolutePath <baseExpr>/abs_path 4873 retainDays <baseExpr>/retain_days 4874 4875 @param parentNode: Parent node to search beneath. 4876 4877 @return: List of C{PurgeDir} objects or C{None} if none are found. 4878 @raise ValueError: If the data at the location can't be read 4879 """ 4880 lst = [] 4881 for entry in readChildren(parentNode, "dir"): 4882 if isElement(entry): 4883 cdir = PurgeDir() 4884 cdir.absolutePath = readString(entry, "abs_path") 4885 cdir.retainDays = readInteger(entry, "retain_days") 4886 lst.append(cdir) 4887 if lst == []: 4888 lst = None 4889 return lst
4890 4891 @staticmethod
4892 - def _parsePeerList(parentNode):
4893 """ 4894 Reads remote and local peer data from immediately beneath the parent. 4895 4896 We read the following individual fields for both remote 4897 and local peers:: 4898 4899 name name 4900 collectDir collect_dir 4901 4902 We also read the following individual fields for remote peers 4903 only:: 4904 4905 remoteUser backup_user 4906 rcpCommand rcp_command 4907 rshCommand rsh_command 4908 cbackCommand cback_command 4909 managed managed 4910 managedActions managed_actions 4911 4912 Additionally, the value in the C{type} field is used to determine whether 4913 this entry is a remote peer. If the type is C{"remote"}, it's a remote 4914 peer, and if the type is C{"local"}, it's a remote peer. 4915 4916 If there are none of one type of peer (i.e. no local peers) then C{None} 4917 will be returned for that item in the tuple. 4918 4919 @param parentNode: Parent node to search beneath. 4920 4921 @return: Tuple of (local, remote) peer lists. 4922 @raise ValueError: If the data at the location can't be read 4923 """ 4924 localPeers = [] 4925 remotePeers = [] 4926 for entry in readChildren(parentNode, "peer"): 4927 if isElement(entry): 4928 peerType = readString(entry, "type") 4929 if peerType == "local": 4930 localPeer = LocalPeer() 4931 localPeer.name = readString(entry, "name") 4932 localPeer.collectDir = readString(entry, "collect_dir") 4933 localPeer.ignoreFailureMode = readString(entry, "ignore_failures") 4934 localPeers.append(localPeer) 4935 elif peerType == "remote": 4936 remotePeer = RemotePeer() 4937 remotePeer.name = readString(entry, "name") 4938 remotePeer.collectDir = readString(entry, "collect_dir") 4939 remotePeer.remoteUser = readString(entry, "backup_user") 4940 remotePeer.rcpCommand = readString(entry, "rcp_command") 4941 remotePeer.rshCommand = readString(entry, "rsh_command") 4942 remotePeer.cbackCommand = readString(entry, "cback_command") 4943 remotePeer.ignoreFailureMode = readString(entry, "ignore_failures") 4944 remotePeer.managed = readBoolean(entry, "managed") 4945 managedActions = readString(entry, "managed_actions") 4946 remotePeer.managedActions = parseCommaSeparatedString(managedActions) 4947 remotePeers.append(remotePeer) 4948 if localPeers == []: 4949 localPeers = None 4950 if remotePeers == []: 4951 remotePeers = None 4952 return (localPeers, remotePeers)
4953 4954 @staticmethod
4955 - def _parseDependencies(parentNode):
4956 """ 4957 Reads extended action dependency information from a parent node. 4958 4959 We read the following individual fields:: 4960 4961 runBefore depends/run_before 4962 runAfter depends/run_after 4963 4964 Each of these fields is a comma-separated list of action names. 4965 4966 The result is placed into an C{ActionDependencies} object. 4967 4968 If the dependencies parent node does not exist, C{None} will be returned. 4969 Otherwise, an C{ActionDependencies} object will always be created, even 4970 if it does not contain any actual dependencies in it. 4971 4972 @param parentNode: Parent node to search beneath. 4973 4974 @return: C{ActionDependencies} object or C{None}. 4975 @raise ValueError: If the data at the location can't be read 4976 """ 4977 sectionNode = readFirstChild(parentNode, "depends") 4978 if sectionNode is None: 4979 return None 4980 else: 4981 runBefore = readString(sectionNode, "run_before") 4982 runAfter = readString(sectionNode, "run_after") 4983 beforeList = parseCommaSeparatedString(runBefore) 4984 afterList = parseCommaSeparatedString(runAfter) 4985 return ActionDependencies(beforeList, afterList)
4986 4987 @staticmethod
4988 - def _parseBlankBehavior(parentNode):
4989 """ 4990 Reads a single C{BlankBehavior} object from immediately beneath the parent. 4991 4992 We read the following individual fields:: 4993 4994 blankMode blank_behavior/mode 4995 blankFactor blank_behavior/factor 4996 4997 @param parentNode: Parent node to search beneath. 4998 4999 @return: C{BlankBehavior} object or C{None} if none if the section is not found 5000 @raise ValueError: If some filled-in value is invalid. 5001 """ 5002 blankBehavior = None 5003 sectionNode = readFirstChild(parentNode, "blank_behavior") 5004 if sectionNode is not None: 5005 blankBehavior = BlankBehavior() 5006 blankBehavior.blankMode = readString(sectionNode, "mode") 5007 blankBehavior.blankFactor = readString(sectionNode, "factor") 5008 return blankBehavior
5009 5010 5011 ######################################## 5012 # High-level methods for generating XML 5013 ######################################## 5014
5015 - def _extractXml(self):
5016 """ 5017 Internal method to extract configuration into an XML string. 5018 5019 This method assumes that the internal L{validate} method has been called 5020 prior to extracting the XML, if the caller cares. No validation will be 5021 done internally. 5022 5023 As a general rule, fields that are set to C{None} will be extracted into 5024 the document as empty tags. The same goes for container tags that are 5025 filled based on lists - if the list is empty or C{None}, the container 5026 tag will be empty. 5027 """ 5028 (xmlDom, parentNode) = createOutputDom() 5029 Config._addReference(xmlDom, parentNode, self.reference) 5030 Config._addExtensions(xmlDom, parentNode, self.extensions) 5031 Config._addOptions(xmlDom, parentNode, self.options) 5032 Config._addPeers(xmlDom, parentNode, self.peers) 5033 Config._addCollect(xmlDom, parentNode, self.collect) 5034 Config._addStage(xmlDom, parentNode, self.stage) 5035 Config._addStore(xmlDom, parentNode, self.store) 5036 Config._addPurge(xmlDom, parentNode, self.purge) 5037 xmlData = serializeDom(xmlDom) 5038 xmlDom.unlink() 5039 return xmlData
5040 5041 @staticmethod
5042 - def _addReference(xmlDom, parentNode, referenceConfig):
5043 """ 5044 Adds a <reference> configuration section as the next child of a parent. 5045 5046 We add the following fields to the document:: 5047 5048 author //cb_config/reference/author 5049 revision //cb_config/reference/revision 5050 description //cb_config/reference/description 5051 generator //cb_config/reference/generator 5052 5053 If C{referenceConfig} is C{None}, then no container will be added. 5054 5055 @param xmlDom: DOM tree as from L{createOutputDom}. 5056 @param parentNode: Parent that the section should be appended to. 5057 @param referenceConfig: Reference configuration section to be added to the document. 5058 """ 5059 if referenceConfig is not None: 5060 sectionNode = addContainerNode(xmlDom, parentNode, "reference") 5061 addStringNode(xmlDom, sectionNode, "author", referenceConfig.author) 5062 addStringNode(xmlDom, sectionNode, "revision", referenceConfig.revision) 5063 addStringNode(xmlDom, sectionNode, "description", referenceConfig.description) 5064 addStringNode(xmlDom, sectionNode, "generator", referenceConfig.generator)
5065 5066 @staticmethod
5067 - def _addExtensions(xmlDom, parentNode, extensionsConfig):
5068 """ 5069 Adds an <extensions> configuration section as the next child of a parent. 5070 5071 We add the following fields to the document:: 5072 5073 order_mode //cb_config/extensions/order_mode 5074 5075 We also add groups of the following items, one list element per item:: 5076 5077 actions //cb_config/extensions/action 5078 5079 The extended action entries are added by L{_addExtendedAction}. 5080 5081 If C{extensionsConfig} is C{None}, then no container will be added. 5082 5083 @param xmlDom: DOM tree as from L{createOutputDom}. 5084 @param parentNode: Parent that the section should be appended to. 5085 @param extensionsConfig: Extensions configuration section to be added to the document. 5086 """ 5087 if extensionsConfig is not None: 5088 sectionNode = addContainerNode(xmlDom, parentNode, "extensions") 5089 addStringNode(xmlDom, sectionNode, "order_mode", extensionsConfig.orderMode) 5090 if extensionsConfig.actions is not None: 5091 for action in extensionsConfig.actions: 5092 Config._addExtendedAction(xmlDom, sectionNode, action)
5093 5094 @staticmethod
5095 - def _addOptions(xmlDom, parentNode, optionsConfig):
5096 """ 5097 Adds a <options> configuration section as the next child of a parent. 5098 5099 We add the following fields to the document:: 5100 5101 startingDay //cb_config/options/starting_day 5102 workingDir //cb_config/options/working_dir 5103 backupUser //cb_config/options/backup_user 5104 backupGroup //cb_config/options/backup_group 5105 rcpCommand //cb_config/options/rcp_command 5106 rshCommand //cb_config/options/rsh_command 5107 cbackCommand //cb_config/options/cback_command 5108 managedActions //cb_config/options/managed_actions 5109 5110 We also add groups of the following items, one list element per 5111 item:: 5112 5113 overrides //cb_config/options/override 5114 hooks //cb_config/options/pre_action_hook 5115 hooks //cb_config/options/post_action_hook 5116 5117 The individual override items are added by L{_addOverride}. The 5118 individual hook items are added by L{_addHook}. 5119 5120 If C{optionsConfig} 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 optionsConfig: Options configuration section to be added to the document. 5125 """ 5126 if optionsConfig is not None: 5127 sectionNode = addContainerNode(xmlDom, parentNode, "options") 5128 addStringNode(xmlDom, sectionNode, "starting_day", optionsConfig.startingDay) 5129 addStringNode(xmlDom, sectionNode, "working_dir", optionsConfig.workingDir) 5130 addStringNode(xmlDom, sectionNode, "backup_user", optionsConfig.backupUser) 5131 addStringNode(xmlDom, sectionNode, "backup_group", optionsConfig.backupGroup) 5132 addStringNode(xmlDom, sectionNode, "rcp_command", optionsConfig.rcpCommand) 5133 addStringNode(xmlDom, sectionNode, "rsh_command", optionsConfig.rshCommand) 5134 addStringNode(xmlDom, sectionNode, "cback_command", optionsConfig.cbackCommand) 5135 managedActions = Config._buildCommaSeparatedString(optionsConfig.managedActions) 5136 addStringNode(xmlDom, sectionNode, "managed_actions", managedActions) 5137 if optionsConfig.overrides is not None: 5138 for override in optionsConfig.overrides: 5139 Config._addOverride(xmlDom, sectionNode, override) 5140 if optionsConfig.hooks is not None: 5141 for hook in optionsConfig.hooks: 5142 Config._addHook(xmlDom, sectionNode, hook)
5143 5144 @staticmethod
5145 - def _addPeers(xmlDom, parentNode, peersConfig):
5146 """ 5147 Adds a <peers> configuration section as the next child of a parent. 5148 5149 We add groups of the following items, one list element per 5150 item:: 5151 5152 localPeers //cb_config/peers/peer 5153 remotePeers //cb_config/peers/peer 5154 5155 The individual local and remote peer entries are added by 5156 L{_addLocalPeer} and L{_addRemotePeer}, respectively. 5157 5158 If C{peersConfig} 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 peersConfig: Peers configuration section to be added to the document. 5163 """ 5164 if peersConfig is not None: 5165 sectionNode = addContainerNode(xmlDom, parentNode, "peers") 5166 if peersConfig.localPeers is not None: 5167 for localPeer in peersConfig.localPeers: 5168 Config._addLocalPeer(xmlDom, sectionNode, localPeer) 5169 if peersConfig.remotePeers is not None: 5170 for remotePeer in peersConfig.remotePeers: 5171 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
5172 5173 @staticmethod
5174 - def _addCollect(xmlDom, parentNode, collectConfig):
5175 """ 5176 Adds a <collect> configuration section as the next child of a parent. 5177 5178 We add the following fields to the document:: 5179 5180 targetDir //cb_config/collect/collect_dir 5181 collectMode //cb_config/collect/collect_mode 5182 archiveMode //cb_config/collect/archive_mode 5183 ignoreFile //cb_config/collect/ignore_file 5184 5185 We also add groups of the following items, one list element per 5186 item:: 5187 5188 absoluteExcludePaths //cb_config/collect/exclude/abs_path 5189 excludePatterns //cb_config/collect/exclude/pattern 5190 collectFiles //cb_config/collect/file 5191 collectDirs //cb_config/collect/dir 5192 5193 The individual collect files are added by L{_addCollectFile} and 5194 individual collect directories are added by L{_addCollectDir}. 5195 5196 If C{collectConfig} is C{None}, then no container will be added. 5197 5198 @param xmlDom: DOM tree as from L{createOutputDom}. 5199 @param parentNode: Parent that the section should be appended to. 5200 @param collectConfig: Collect configuration section to be added to the document. 5201 """ 5202 if collectConfig is not None: 5203 sectionNode = addContainerNode(xmlDom, parentNode, "collect") 5204 addStringNode(xmlDom, sectionNode, "collect_dir", collectConfig.targetDir) 5205 addStringNode(xmlDom, sectionNode, "collect_mode", collectConfig.collectMode) 5206 addStringNode(xmlDom, sectionNode, "archive_mode", collectConfig.archiveMode) 5207 addStringNode(xmlDom, sectionNode, "ignore_file", collectConfig.ignoreFile) 5208 if ((collectConfig.absoluteExcludePaths is not None and collectConfig.absoluteExcludePaths != []) or 5209 (collectConfig.excludePatterns is not None and collectConfig.excludePatterns != [])): 5210 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude") 5211 if collectConfig.absoluteExcludePaths is not None: 5212 for absolutePath in collectConfig.absoluteExcludePaths: 5213 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath) 5214 if collectConfig.excludePatterns is not None: 5215 for pattern in collectConfig.excludePatterns: 5216 addStringNode(xmlDom, excludeNode, "pattern", pattern) 5217 if collectConfig.collectFiles is not None: 5218 for collectFile in collectConfig.collectFiles: 5219 Config._addCollectFile(xmlDom, sectionNode, collectFile) 5220 if collectConfig.collectDirs is not None: 5221 for collectDir in collectConfig.collectDirs: 5222 Config._addCollectDir(xmlDom, sectionNode, collectDir)
5223 5224 @staticmethod
5225 - def _addStage(xmlDom, parentNode, stageConfig):
5226 """ 5227 Adds a <stage> configuration section as the next child of a parent. 5228 5229 We add the following fields to the document:: 5230 5231 targetDir //cb_config/stage/staging_dir 5232 5233 We also add groups of the following items, one list element per 5234 item:: 5235 5236 localPeers //cb_config/stage/peer 5237 remotePeers //cb_config/stage/peer 5238 5239 The individual local and remote peer entries are added by 5240 L{_addLocalPeer} and L{_addRemotePeer}, respectively. 5241 5242 If C{stageConfig} is C{None}, then no container will be added. 5243 5244 @param xmlDom: DOM tree as from L{createOutputDom}. 5245 @param parentNode: Parent that the section should be appended to. 5246 @param stageConfig: Stage configuration section to be added to the document. 5247 """ 5248 if stageConfig is not None: 5249 sectionNode = addContainerNode(xmlDom, parentNode, "stage") 5250 addStringNode(xmlDom, sectionNode, "staging_dir", stageConfig.targetDir) 5251 if stageConfig.localPeers is not None: 5252 for localPeer in stageConfig.localPeers: 5253 Config._addLocalPeer(xmlDom, sectionNode, localPeer) 5254 if stageConfig.remotePeers is not None: 5255 for remotePeer in stageConfig.remotePeers: 5256 Config._addRemotePeer(xmlDom, sectionNode, remotePeer)
5257 5258 @staticmethod
5259 - def _addStore(xmlDom, parentNode, storeConfig):
5260 """ 5261 Adds a <store> configuration section as the next child of a parent. 5262 5263 We add the following fields to the document:: 5264 5265 sourceDir //cb_config/store/source_dir 5266 mediaType //cb_config/store/media_type 5267 deviceType //cb_config/store/device_type 5268 devicePath //cb_config/store/target_device 5269 deviceScsiId //cb_config/store/target_scsi_id 5270 driveSpeed //cb_config/store/drive_speed 5271 checkData //cb_config/store/check_data 5272 checkMedia //cb_config/store/check_media 5273 warnMidnite //cb_config/store/warn_midnite 5274 noEject //cb_config/store/no_eject 5275 refreshMediaDelay //cb_config/store/refresh_media_delay 5276 ejectDelay //cb_config/store/eject_delay 5277 5278 Blanking behavior configuration is added by the L{_addBlankBehavior} 5279 method. 5280 5281 If C{storeConfig} is C{None}, then no container will be added. 5282 5283 @param xmlDom: DOM tree as from L{createOutputDom}. 5284 @param parentNode: Parent that the section should be appended to. 5285 @param storeConfig: Store configuration section to be added to the document. 5286 """ 5287 if storeConfig is not None: 5288 sectionNode = addContainerNode(xmlDom, parentNode, "store") 5289 addStringNode(xmlDom, sectionNode, "source_dir", storeConfig.sourceDir) 5290 addStringNode(xmlDom, sectionNode, "media_type", storeConfig.mediaType) 5291 addStringNode(xmlDom, sectionNode, "device_type", storeConfig.deviceType) 5292 addStringNode(xmlDom, sectionNode, "target_device", storeConfig.devicePath) 5293 addStringNode(xmlDom, sectionNode, "target_scsi_id", storeConfig.deviceScsiId) 5294 addIntegerNode(xmlDom, sectionNode, "drive_speed", storeConfig.driveSpeed) 5295 addBooleanNode(xmlDom, sectionNode, "check_data", storeConfig.checkData) 5296 addBooleanNode(xmlDom, sectionNode, "check_media", storeConfig.checkMedia) 5297 addBooleanNode(xmlDom, sectionNode, "warn_midnite", storeConfig.warnMidnite) 5298 addBooleanNode(xmlDom, sectionNode, "no_eject", storeConfig.noEject) 5299 addIntegerNode(xmlDom, sectionNode, "refresh_media_delay", storeConfig.refreshMediaDelay) 5300 addIntegerNode(xmlDom, sectionNode, "eject_delay", storeConfig.ejectDelay) 5301 Config._addBlankBehavior(xmlDom, sectionNode, storeConfig.blankBehavior)
5302 5303 @staticmethod
5304 - def _addPurge(xmlDom, parentNode, purgeConfig):
5305 """ 5306 Adds a <purge> configuration section as the next child of a parent. 5307 5308 We add the following fields to the document:: 5309 5310 purgeDirs //cb_config/purge/dir 5311 5312 The individual directory entries are added by L{_addPurgeDir}. 5313 5314 If C{purgeConfig} is C{None}, then no container will be added. 5315 5316 @param xmlDom: DOM tree as from L{createOutputDom}. 5317 @param parentNode: Parent that the section should be appended to. 5318 @param purgeConfig: Purge configuration section to be added to the document. 5319 """ 5320 if purgeConfig is not None: 5321 sectionNode = addContainerNode(xmlDom, parentNode, "purge") 5322 if purgeConfig.purgeDirs is not None: 5323 for purgeDir in purgeConfig.purgeDirs: 5324 Config._addPurgeDir(xmlDom, sectionNode, purgeDir)
5325 5326 @staticmethod
5327 - def _addExtendedAction(xmlDom, parentNode, action):
5328 """ 5329 Adds an extended action container as the next child of a parent. 5330 5331 We add the following fields to the document:: 5332 5333 name action/name 5334 module action/module 5335 function action/function 5336 index action/index 5337 dependencies action/depends 5338 5339 Dependencies are added by the L{_addDependencies} method. 5340 5341 The <action> node itself is created as the next child of the parent node. 5342 This method only adds one action node. The parent must loop for each action 5343 in the C{ExtensionsConfig} object. 5344 5345 If C{action} is C{None}, this method call will be a no-op. 5346 5347 @param xmlDom: DOM tree as from L{createOutputDom}. 5348 @param parentNode: Parent that the section should be appended to. 5349 @param action: Purge directory to be added to the document. 5350 """ 5351 if action is not None: 5352 sectionNode = addContainerNode(xmlDom, parentNode, "action") 5353 addStringNode(xmlDom, sectionNode, "name", action.name) 5354 addStringNode(xmlDom, sectionNode, "module", action.module) 5355 addStringNode(xmlDom, sectionNode, "function", action.function) 5356 addIntegerNode(xmlDom, sectionNode, "index", action.index) 5357 Config._addDependencies(xmlDom, sectionNode, action.dependencies)
5358 5359 @staticmethod
5360 - def _addOverride(xmlDom, parentNode, override):
5361 """ 5362 Adds a command override container as the next child of a parent. 5363 5364 We add the following fields to the document:: 5365 5366 command override/command 5367 absolutePath override/abs_path 5368 5369 The <override> node itself is created as the next child of the parent 5370 node. This method only adds one override node. The parent must loop for 5371 each override in the C{OptionsConfig} object. 5372 5373 If C{override} is C{None}, this method call will be a no-op. 5374 5375 @param xmlDom: DOM tree as from L{createOutputDom}. 5376 @param parentNode: Parent that the section should be appended to. 5377 @param override: Command override to be added to the document. 5378 """ 5379 if override is not None: 5380 sectionNode = addContainerNode(xmlDom, parentNode, "override") 5381 addStringNode(xmlDom, sectionNode, "command", override.command) 5382 addStringNode(xmlDom, sectionNode, "abs_path", override.absolutePath)
5383 5384 @staticmethod
5385 - def _addHook(xmlDom, parentNode, hook):
5386 """ 5387 Adds an action hook container as the next child of a parent. 5388 5389 The behavior varies depending on the value of the C{before} and C{after} 5390 flags on the hook. If the C{before} flag is set, it's a pre-action hook, 5391 and we'll add the following fields:: 5392 5393 action pre_action_hook/action 5394 command pre_action_hook/command 5395 5396 If the C{after} flag is set, it's a post-action hook, and we'll add the 5397 following fields:: 5398 5399 action post_action_hook/action 5400 command post_action_hook/command 5401 5402 The <pre_action_hook> or <post_action_hook> node itself is created as the 5403 next child of the parent node. This method only adds one hook node. The 5404 parent must loop for each hook in the C{OptionsConfig} object. 5405 5406 If C{hook} is C{None}, this method call will be a no-op. 5407 5408 @param xmlDom: DOM tree as from L{createOutputDom}. 5409 @param parentNode: Parent that the section should be appended to. 5410 @param hook: Command hook to be added to the document. 5411 """ 5412 if hook is not None: 5413 if hook.before: 5414 sectionNode = addContainerNode(xmlDom, parentNode, "pre_action_hook") 5415 else: 5416 sectionNode = addContainerNode(xmlDom, parentNode, "post_action_hook") 5417 addStringNode(xmlDom, sectionNode, "action", hook.action) 5418 addStringNode(xmlDom, sectionNode, "command", hook.command)
5419 5420 @staticmethod
5421 - def _addCollectFile(xmlDom, parentNode, collectFile):
5422 """ 5423 Adds a collect file container as the next child of a parent. 5424 5425 We add the following fields to the document:: 5426 5427 absolutePath dir/abs_path 5428 collectMode dir/collect_mode 5429 archiveMode dir/archive_mode 5430 5431 Note that for consistency with collect directory handling we'll only emit 5432 the preferred C{collect_mode} tag. 5433 5434 The <file> node itself is created as the next child of the parent node. 5435 This method only adds one collect file node. The parent must loop 5436 for each collect file in the C{CollectConfig} object. 5437 5438 If C{collectFile} 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 collectFile: Collect file to be added to the document. 5443 """ 5444 if collectFile is not None: 5445 sectionNode = addContainerNode(xmlDom, parentNode, "file") 5446 addStringNode(xmlDom, sectionNode, "abs_path", collectFile.absolutePath) 5447 addStringNode(xmlDom, sectionNode, "collect_mode", collectFile.collectMode) 5448 addStringNode(xmlDom, sectionNode, "archive_mode", collectFile.archiveMode)
5449 5450 @staticmethod
5451 - def _addCollectDir(xmlDom, parentNode, collectDir):
5452 """ 5453 Adds a collect directory container as the next child of a parent. 5454 5455 We add the following fields to the document:: 5456 5457 absolutePath dir/abs_path 5458 collectMode dir/collect_mode 5459 archiveMode dir/archive_mode 5460 ignoreFile dir/ignore_file 5461 linkDepth dir/link_depth 5462 dereference dir/dereference 5463 recursionLevel dir/recursion_level 5464 5465 Note that an original XML document might have listed the collect mode 5466 using the C{mode} tag, since we accept both C{collect_mode} and C{mode}. 5467 However, here we'll only emit the preferred C{collect_mode} tag. 5468 5469 We also add groups of the following items, one list element per item:: 5470 5471 absoluteExcludePaths dir/exclude/abs_path 5472 relativeExcludePaths dir/exclude/rel_path 5473 excludePatterns dir/exclude/pattern 5474 5475 The <dir> node itself is created as the next child of the parent node. 5476 This method only adds one collect directory node. The parent must loop 5477 for each collect directory in the C{CollectConfig} object. 5478 5479 If C{collectDir} is C{None}, this method call will be a no-op. 5480 5481 @param xmlDom: DOM tree as from L{createOutputDom}. 5482 @param parentNode: Parent that the section should be appended to. 5483 @param collectDir: Collect directory to be added to the document. 5484 """ 5485 if collectDir is not None: 5486 sectionNode = addContainerNode(xmlDom, parentNode, "dir") 5487 addStringNode(xmlDom, sectionNode, "abs_path", collectDir.absolutePath) 5488 addStringNode(xmlDom, sectionNode, "collect_mode", collectDir.collectMode) 5489 addStringNode(xmlDom, sectionNode, "archive_mode", collectDir.archiveMode) 5490 addStringNode(xmlDom, sectionNode, "ignore_file", collectDir.ignoreFile) 5491 addIntegerNode(xmlDom, sectionNode, "link_depth", collectDir.linkDepth) 5492 addBooleanNode(xmlDom, sectionNode, "dereference", collectDir.dereference) 5493 addIntegerNode(xmlDom, sectionNode, "recursion_level", collectDir.recursionLevel) 5494 if ((collectDir.absoluteExcludePaths is not None and collectDir.absoluteExcludePaths != []) or 5495 (collectDir.relativeExcludePaths is not None and collectDir.relativeExcludePaths != []) or 5496 (collectDir.excludePatterns is not None and collectDir.excludePatterns != [])): 5497 excludeNode = addContainerNode(xmlDom, sectionNode, "exclude") 5498 if collectDir.absoluteExcludePaths is not None: 5499 for absolutePath in collectDir.absoluteExcludePaths: 5500 addStringNode(xmlDom, excludeNode, "abs_path", absolutePath) 5501 if collectDir.relativeExcludePaths is not None: 5502 for relativePath in collectDir.relativeExcludePaths: 5503 addStringNode(xmlDom, excludeNode, "rel_path", relativePath) 5504 if collectDir.excludePatterns is not None: 5505 for pattern in collectDir.excludePatterns: 5506 addStringNode(xmlDom, excludeNode, "pattern", pattern)
5507 5508 @staticmethod
5509 - def _addLocalPeer(xmlDom, parentNode, localPeer):
5510 """ 5511 Adds a local peer container as the next child of a parent. 5512 5513 We add the following fields to the document:: 5514 5515 name peer/name 5516 collectDir peer/collect_dir 5517 ignoreFailureMode peer/ignore_failures 5518 5519 Additionally, C{peer/type} is filled in with C{"local"}, since this is a 5520 local peer. 5521 5522 The <peer> node itself is created as the next child of the parent node. 5523 This method only adds one peer node. The parent must loop for each peer 5524 in the C{StageConfig} object. 5525 5526 If C{localPeer} is C{None}, this method call will be a no-op. 5527 5528 @param xmlDom: DOM tree as from L{createOutputDom}. 5529 @param parentNode: Parent that the section should be appended to. 5530 @param localPeer: Purge directory to be added to the document. 5531 """ 5532 if localPeer is not None: 5533 sectionNode = addContainerNode(xmlDom, parentNode, "peer") 5534 addStringNode(xmlDom, sectionNode, "name", localPeer.name) 5535 addStringNode(xmlDom, sectionNode, "type", "local") 5536 addStringNode(xmlDom, sectionNode, "collect_dir", localPeer.collectDir) 5537 addStringNode(xmlDom, sectionNode, "ignore_failures", localPeer.ignoreFailureMode)
5538 5539 @staticmethod
5540 - def _addRemotePeer(xmlDom, parentNode, remotePeer):
5541 """ 5542 Adds a remote peer container as the next child of a parent. 5543 5544 We add the following fields to the document:: 5545 5546 name peer/name 5547 collectDir peer/collect_dir 5548 remoteUser peer/backup_user 5549 rcpCommand peer/rcp_command 5550 rcpCommand peer/rcp_command 5551 rshCommand peer/rsh_command 5552 cbackCommand peer/cback_command 5553 ignoreFailureMode peer/ignore_failures 5554 managed peer/managed 5555 managedActions peer/managed_actions 5556 5557 Additionally, C{peer/type} is filled in with C{"remote"}, since this is a 5558 remote peer. 5559 5560 The <peer> node itself is created as the next child of the parent node. 5561 This method only adds one peer node. The parent must loop for each peer 5562 in the C{StageConfig} object. 5563 5564 If C{remotePeer} is C{None}, this method call will be a no-op. 5565 5566 @param xmlDom: DOM tree as from L{createOutputDom}. 5567 @param parentNode: Parent that the section should be appended to. 5568 @param remotePeer: Purge directory to be added to the document. 5569 """ 5570 if remotePeer is not None: 5571 sectionNode = addContainerNode(xmlDom, parentNode, "peer") 5572 addStringNode(xmlDom, sectionNode, "name", remotePeer.name) 5573 addStringNode(xmlDom, sectionNode, "type", "remote") 5574 addStringNode(xmlDom, sectionNode, "collect_dir", remotePeer.collectDir) 5575 addStringNode(xmlDom, sectionNode, "backup_user", remotePeer.remoteUser) 5576 addStringNode(xmlDom, sectionNode, "rcp_command", remotePeer.rcpCommand) 5577 addStringNode(xmlDom, sectionNode, "rsh_command", remotePeer.rshCommand) 5578 addStringNode(xmlDom, sectionNode, "cback_command", remotePeer.cbackCommand) 5579 addStringNode(xmlDom, sectionNode, "ignore_failures", remotePeer.ignoreFailureMode) 5580 addBooleanNode(xmlDom, sectionNode, "managed", remotePeer.managed) 5581 managedActions = Config._buildCommaSeparatedString(remotePeer.managedActions) 5582 addStringNode(xmlDom, sectionNode, "managed_actions", managedActions)
5583 5584 @staticmethod
5585 - def _addPurgeDir(xmlDom, parentNode, purgeDir):
5586 """ 5587 Adds a purge directory container as the next child of a parent. 5588 5589 We add the following fields to the document:: 5590 5591 absolutePath dir/abs_path 5592 retainDays dir/retain_days 5593 5594 The <dir> node itself is created as the next child of the parent node. 5595 This method only adds one purge directory node. The parent must loop for 5596 each purge directory in the C{PurgeConfig} object. 5597 5598 If C{purgeDir} is C{None}, this method call will be a no-op. 5599 5600 @param xmlDom: DOM tree as from L{createOutputDom}. 5601 @param parentNode: Parent that the section should be appended to. 5602 @param purgeDir: Purge directory to be added to the document. 5603 """ 5604 if purgeDir is not None: 5605 sectionNode = addContainerNode(xmlDom, parentNode, "dir") 5606 addStringNode(xmlDom, sectionNode, "abs_path", purgeDir.absolutePath) 5607 addIntegerNode(xmlDom, sectionNode, "retain_days", purgeDir.retainDays)
5608 5609 @staticmethod
5610 - def _addDependencies(xmlDom, parentNode, dependencies):
5611 """ 5612 Adds a extended action dependencies to parent node. 5613 5614 We add the following fields to the document:: 5615 5616 runBefore depends/run_before 5617 runAfter depends/run_after 5618 5619 If C{dependencies} is C{None}, this method call will be a no-op. 5620 5621 @param xmlDom: DOM tree as from L{createOutputDom}. 5622 @param parentNode: Parent that the section should be appended to. 5623 @param dependencies: C{ActionDependencies} object to be added to the document 5624 """ 5625 if dependencies is not None: 5626 sectionNode = addContainerNode(xmlDom, parentNode, "depends") 5627 runBefore = Config._buildCommaSeparatedString(dependencies.beforeList) 5628 runAfter = Config._buildCommaSeparatedString(dependencies.afterList) 5629 addStringNode(xmlDom, sectionNode, "run_before", runBefore) 5630 addStringNode(xmlDom, sectionNode, "run_after", runAfter)
5631 5632 @staticmethod
5633 - def _buildCommaSeparatedString(valueList):
5634 """ 5635 Creates a comma-separated string from a list of values. 5636 5637 As a special case, if C{valueList} is C{None}, then C{None} will be 5638 returned. 5639 5640 @param valueList: List of values to be placed into a string 5641 5642 @return: Values from valueList as a comma-separated string. 5643 """ 5644 if valueList is None: 5645 return None 5646 return ",".join(valueList)
5647 5648 @staticmethod
5649 - def _addBlankBehavior(xmlDom, parentNode, blankBehavior):
5650 """ 5651 Adds a blanking behavior container as the next child of a parent. 5652 5653 We add the following fields to the document:: 5654 5655 blankMode blank_behavior/mode 5656 blankFactor blank_behavior/factor 5657 5658 The <blank_behavior> node itself is created as the next child of the 5659 parent node. 5660 5661 If C{blankBehavior} is C{None}, this method call will be a no-op. 5662 5663 @param xmlDom: DOM tree as from L{createOutputDom}. 5664 @param parentNode: Parent that the section should be appended to. 5665 @param blankBehavior: Blanking behavior to be added to the document. 5666 """ 5667 if blankBehavior is not None: 5668 sectionNode = addContainerNode(xmlDom, parentNode, "blank_behavior") 5669 addStringNode(xmlDom, sectionNode, "mode", blankBehavior.blankMode) 5670 addStringNode(xmlDom, sectionNode, "factor", blankBehavior.blankFactor)
5671 5672 5673 ################################################# 5674 # High-level methods used for validating content 5675 ################################################# 5676
5677 - def _validateContents(self):
5678 """ 5679 Validates configuration contents per rules discussed in module 5680 documentation. 5681 5682 This is the second pass at validation. It ensures that any filled-in 5683 section contains valid data. Any sections which is not set to C{None} is 5684 validated per the rules for that section, laid out in the module 5685 documentation (above). 5686 5687 @raise ValueError: If configuration is invalid. 5688 """ 5689 self._validateReference() 5690 self._validateExtensions() 5691 self._validateOptions() 5692 self._validatePeers() 5693 self._validateCollect() 5694 self._validateStage() 5695 self._validateStore() 5696 self._validatePurge()
5697
5698 - def _validateReference(self):
5699 """ 5700 Validates reference configuration. 5701 There are currently no reference-related validations. 5702 @raise ValueError: If reference configuration is invalid. 5703 """ 5704 pass
5705
5706 - def _validateExtensions(self):
5707 """ 5708 Validates extensions configuration. 5709 5710 The list of actions may be either C{None} or an empty list C{[]} if 5711 desired. Each extended action must include a name, a module, and a 5712 function. 5713 5714 Then, if the order mode is None or "index", an index is required; and if 5715 the order mode is "dependency", dependency information is required. 5716 5717 @raise ValueError: If reference configuration is invalid. 5718 """ 5719 if self.extensions is not None: 5720 if self.extensions.actions is not None: 5721 names = [] 5722 for action in self.extensions.actions: 5723 if action.name is None: 5724 raise ValueError("Each extended action must set a name.") 5725 names.append(action.name) 5726 if action.module is None: 5727 raise ValueError("Each extended action must set a module.") 5728 if action.function is None: 5729 raise ValueError("Each extended action must set a function.") 5730 if self.extensions.orderMode is None or self.extensions.orderMode == "index": 5731 if action.index is None: 5732 raise ValueError("Each extended action must set an index, based on order mode.") 5733 elif self.extensions.orderMode == "dependency": 5734 if action.dependencies is None: 5735 raise ValueError("Each extended action must set dependency information, based on order mode.") 5736 checkUnique("Duplicate extension names exist:", names)
5737
5738 - def _validateOptions(self):
5739 """ 5740 Validates options configuration. 5741 5742 All fields must be filled in except the rsh command. The rcp and rsh 5743 commands are used as default values for all remote peers. Remote peers 5744 can also rely on the backup user as the default remote user name if they 5745 choose. 5746 5747 @raise ValueError: If reference configuration is invalid. 5748 """ 5749 if self.options is not None: 5750 if self.options.startingDay is None: 5751 raise ValueError("Options section starting day must be filled in.") 5752 if self.options.workingDir is None: 5753 raise ValueError("Options section working directory must be filled in.") 5754 if self.options.backupUser is None: 5755 raise ValueError("Options section backup user must be filled in.") 5756 if self.options.backupGroup is None: 5757 raise ValueError("Options section backup group must be filled in.") 5758 if self.options.rcpCommand is None: 5759 raise ValueError("Options section remote copy command must be filled in.")
5760
5761 - def _validatePeers(self):
5762 """ 5763 Validates peers configuration per rules in L{_validatePeerList}. 5764 @raise ValueError: If peers configuration is invalid. 5765 """ 5766 if self.peers is not None: 5767 self._validatePeerList(self.peers.localPeers, self.peers.remotePeers)
5768
5769 - def _validateCollect(self):
5770 """ 5771 Validates collect configuration. 5772 5773 The target directory must be filled in. The collect mode, archive mode, 5774 ignore file, and recursion level are all optional. The list of absolute 5775 paths to exclude and patterns to exclude may be either C{None} or an 5776 empty list C{[]} if desired. 5777 5778 Each collect directory entry must contain an absolute path to collect, 5779 and then must either be able to take collect mode, archive mode and 5780 ignore file configuration from the parent C{CollectConfig} object, or 5781 must set each value on its own. The list of absolute paths to exclude, 5782 relative paths to exclude and patterns to exclude may be either C{None} 5783 or an empty list C{[]} if desired. Any list of absolute paths to exclude 5784 or patterns to exclude will be combined with the same list in the 5785 C{CollectConfig} object to make the complete list for a given directory. 5786 5787 @raise ValueError: If collect configuration is invalid. 5788 """ 5789 if self.collect is not None: 5790 if self.collect.targetDir is None: 5791 raise ValueError("Collect section target directory must be filled in.") 5792 if self.collect.collectFiles is not None: 5793 for collectFile in self.collect.collectFiles: 5794 if collectFile.absolutePath is None: 5795 raise ValueError("Each collect file must set an absolute path.") 5796 if self.collect.collectMode is None and collectFile.collectMode is None: 5797 raise ValueError("Collect mode must either be set in parent collect section or individual collect file.") 5798 if self.collect.archiveMode is None and collectFile.archiveMode is None: 5799 raise ValueError("Archive mode must either be set in parent collect section or individual collect file.") 5800 if self.collect.collectDirs is not None: 5801 for collectDir in self.collect.collectDirs: 5802 if collectDir.absolutePath is None: 5803 raise ValueError("Each collect directory must set an absolute path.") 5804 if self.collect.collectMode is None and collectDir.collectMode is None: 5805 raise ValueError("Collect mode must either be set in parent collect section or individual collect directory.") 5806 if self.collect.archiveMode is None and collectDir.archiveMode is None: 5807 raise ValueError("Archive mode must either be set in parent collect section or individual collect directory.") 5808 if self.collect.ignoreFile is None and collectDir.ignoreFile is None: 5809 raise ValueError("Ignore file must either be set in parent collect section or individual collect directory.") 5810 if (collectDir.linkDepth is None or collectDir.linkDepth < 1) and collectDir.dereference: 5811 raise ValueError("Dereference flag is only valid when a non-zero link depth is in use.")
5812
5813 - def _validateStage(self):
5814 """ 5815 Validates stage configuration. 5816 5817 The target directory must be filled in, and the peers are 5818 also validated. 5819 5820 Peers are only required in this section if the peers configuration 5821 section is not filled in. However, if any peers are filled in 5822 here, they override the peers configuration and must meet the 5823 validation criteria in L{_validatePeerList}. 5824 5825 @raise ValueError: If stage configuration is invalid. 5826 """ 5827 if self.stage is not None: 5828 if self.stage.targetDir is None: 5829 raise ValueError("Stage section target directory must be filled in.") 5830 if self.peers is None: 5831 # In this case, stage configuration is our only configuration and must be valid. 5832 self._validatePeerList(self.stage.localPeers, self.stage.remotePeers) 5833 else: 5834 # In this case, peers configuration is the default and stage configuration overrides. 5835 # Validation is only needed if it's stage configuration is actually filled in. 5836 if self.stage.hasPeers(): 5837 self._validatePeerList(self.stage.localPeers, self.stage.remotePeers)
5838
5839 - def _validateStore(self):
5840 """ 5841 Validates store configuration. 5842 5843 The device type, drive speed, and blanking behavior are optional. All 5844 other values are required. Missing booleans will be set to defaults. 5845 5846 If blanking behavior is provided, then both a blanking mode and a 5847 blanking factor are required. 5848 5849 The image writer functionality in the C{writer} module is supposed to be 5850 able to handle a device speed of C{None}. 5851 5852 Any caller which needs a "real" (non-C{None}) value for the device type 5853 can use C{DEFAULT_DEVICE_TYPE}, which is guaranteed to be sensible. 5854 5855 This is also where we make sure that the media type -- which is already a 5856 valid type -- matches up properly with the device type. 5857 5858 @raise ValueError: If store configuration is invalid. 5859 """ 5860 if self.store is not None: 5861 if self.store.sourceDir is None: 5862 raise ValueError("Store section source directory must be filled in.") 5863 if self.store.mediaType is None: 5864 raise ValueError("Store section media type must be filled in.") 5865 if self.store.devicePath is None: 5866 raise ValueError("Store section device path must be filled in.") 5867 if self.store.deviceType == None or self.store.deviceType == "cdwriter": 5868 if self.store.mediaType not in VALID_CD_MEDIA_TYPES: 5869 raise ValueError("Media type must match device type.") 5870 elif self.store.deviceType == "dvdwriter": 5871 if self.store.mediaType not in VALID_DVD_MEDIA_TYPES: 5872 raise ValueError("Media type must match device type.") 5873 if self.store.blankBehavior is not None: 5874 if self.store.blankBehavior.blankMode is None and self.store.blankBehavior.blankFactor is None: 5875 raise ValueError("If blanking behavior is provided, all values must be filled in.")
5876
5877 - def _validatePurge(self):
5878 """ 5879 Validates purge configuration. 5880 5881 The list of purge directories may be either C{None} or an empty list 5882 C{[]} if desired. All purge directories must contain a path and a retain 5883 days value. 5884 5885 @raise ValueError: If purge configuration is invalid. 5886 """ 5887 if self.purge is not None: 5888 if self.purge.purgeDirs is not None: 5889 for purgeDir in self.purge.purgeDirs: 5890 if purgeDir.absolutePath is None: 5891 raise ValueError("Each purge directory must set an absolute path.") 5892 if purgeDir.retainDays is None: 5893 raise ValueError("Each purge directory must set a retain days value.")
5894
5895 - def _validatePeerList(self, localPeers, remotePeers):
5896 """ 5897 Validates the set of local and remote peers. 5898 5899 Local peers must be completely filled in, including both name and collect 5900 directory. Remote peers must also fill in the name and collect 5901 directory, but can leave the remote user and rcp command unset. In this 5902 case, the remote user is assumed to match the backup user from the 5903 options section and rcp command is taken directly from the options 5904 section. 5905 5906 @param localPeers: List of local peers 5907 @param remotePeers: List of remote peers 5908 5909 @raise ValueError: If stage configuration is invalid. 5910 """ 5911 if localPeers is None and remotePeers is None: 5912 raise ValueError("Peer list must contain at least one backup peer.") 5913 if localPeers is None and remotePeers is not None: 5914 if len(remotePeers) < 1: 5915 raise ValueError("Peer list must contain at least one backup peer.") 5916 elif localPeers is not None and remotePeers is None: 5917 if len(localPeers) < 1: 5918 raise ValueError("Peer list must contain at least one backup peer.") 5919 elif localPeers is not None and remotePeers is not None: 5920 if len(localPeers) + len(remotePeers) < 1: 5921 raise ValueError("Peer list must contain at least one backup peer.") 5922 names = [] 5923 if localPeers is not None: 5924 for localPeer in localPeers: 5925 if localPeer.name is None: 5926 raise ValueError("Local peers must set a name.") 5927 names.append(localPeer.name) 5928 if localPeer.collectDir is None: 5929 raise ValueError("Local peers must set a collect directory.") 5930 if remotePeers is not None: 5931 for remotePeer in remotePeers: 5932 if remotePeer.name is None: 5933 raise ValueError("Remote peers must set a name.") 5934 names.append(remotePeer.name) 5935 if remotePeer.collectDir is None: 5936 raise ValueError("Remote peers must set a collect directory.") 5937 if (self.options is None or self.options.backupUser is None) and remotePeer.remoteUser is None: 5938 raise ValueError("Remote user must either be set in options section or individual remote peer.") 5939 if (self.options is None or self.options.rcpCommand is None) and remotePeer.rcpCommand is None: 5940 raise ValueError("Remote copy command must either be set in options section or individual remote peer.") 5941 if remotePeer.managed: 5942 if (self.options is None or self.options.rshCommand is None) and remotePeer.rshCommand is None: 5943 raise ValueError("Remote shell command must either be set in options section or individual remote peer.") 5944 if (self.options is None or self.options.cbackCommand is None) and remotePeer.cbackCommand is None: 5945 raise ValueError("Remote cback command must either be set in options section or individual remote peer.") 5946 if ((self.options is None or self.options.managedActions is None or len(self.options.managedActions) < 1) 5947 and (remotePeer.managedActions is None or len(remotePeer.managedActions) < 1)): 5948 raise ValueError("Managed actions list must be set in options section or individual remote peer.") 5949 checkUnique("Duplicate peer names exist:", names)
5950
5951 5952 ######################################################################## 5953 # General utility functions 5954 ######################################################################## 5955 5956 -def readByteQuantity(parent, name):
5957 """ 5958 Read a byte size value from an XML document. 5959 5960 A byte size value is an interpreted string value. If the string value 5961 ends with "MB" or "GB", then the string before that is interpreted as 5962 megabytes or gigabytes. Otherwise, it is intepreted as bytes. 5963 5964 @param parent: Parent node to search beneath. 5965 @param name: Name of node to search for. 5966 5967 @return: ByteQuantity parsed from XML document 5968 """ 5969 data = readString(parent, name) 5970 if data is None: 5971 return None 5972 data = data.strip() 5973 if data.endswith("KB"): 5974 quantity = data[0:data.rfind("KB")].strip() 5975 units = UNIT_KBYTES 5976 elif data.endswith("MB"): 5977 quantity = data[0:data.rfind("MB")].strip() 5978 units = UNIT_MBYTES 5979 elif data.endswith("GB"): 5980 quantity = data[0:data.rfind("GB")].strip() 5981 units = UNIT_GBYTES 5982 else: 5983 quantity = data.strip() 5984 units = UNIT_BYTES 5985 return ByteQuantity(quantity, units)
5986
5987 -def addByteQuantityNode(xmlDom, parentNode, nodeName, byteQuantity):
5988 """ 5989 Adds a text node as the next child of a parent, to contain a byte size. 5990 5991 If the C{byteQuantity} is None, then the node will be created, but will 5992 be empty (i.e. will contain no text node child). 5993 5994 The size in bytes will be normalized. If it is larger than 1.0 GB, it will 5995 be shown in GB ("1.0 GB"). If it is larger than 1.0 MB ("1.0 MB"), it will 5996 be shown in MB. Otherwise, it will be shown in bytes ("423413"). 5997 5998 @param xmlDom: DOM tree as from C{impl.createDocument()}. 5999 @param parentNode: Parent node to create child for. 6000 @param nodeName: Name of the new container node. 6001 @param byteQuantity: ByteQuantity object to put into the XML document 6002 6003 @return: Reference to the newly-created node. 6004 """ 6005 if byteQuantity is None: 6006 byteString = None 6007 elif byteQuantity.units == UNIT_KBYTES: 6008 byteString = "%s KB" % byteQuantity.quantity 6009 elif byteQuantity.units == UNIT_MBYTES: 6010 byteString = "%s MB" % byteQuantity.quantity 6011 elif byteQuantity.units == UNIT_GBYTES: 6012 byteString = "%s GB" % byteQuantity.quantity 6013 else: 6014 byteString = byteQuantity.quantity 6015 return addStringNode(xmlDom, parentNode, nodeName, byteString)
6016