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