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