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

Source Code for Module CedarBackup2.config

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