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