Package CedarBackup2 :: Module config
[hide private]
[frames] | no frames]

Source Code for Module CedarBackup2.config

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