ZFS Automatic Snapshot Daemon
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

136 lines
4.9 KiB

# Public API
''' Base filesystem classes and registration facilities '''
class Filesystem:
''' Base filsystem class inherited by each filesystem implementation '''
def __init__(self, name, props, **kwprops):
# Set common properties
self._name = name
# Process arguments to extract all properties
props = _process_args(props, kwprops)
# Delegate further initialisation to the subclass
self.initialise(props)
def initialise(self, props):
''' Perform initialisation. This method is called in the constructor
once the property arguments have been processed and merged into a
single property dictionary. Subclasses typically use this method for
transforming property values and assigning them to private
attributes on the Filesystem object. '''
async def snapshots(self):
''' Retrieve an {ordinal: snapshot} dictionary of the snapshots that are
managed by this Filesystem object. '''
async def mountpoint(self):
''' Retrieve the mountpoint path this Filesystem object is managing. '''
@classmethod
async def filesystems(cls):
''' Retrieve a {name: filesystem} dictionary of the mounted filesystems
that are managed by this Filesystem class. '''
raise NotImplementedError()
@classmethod
async def expose(cls):
''' Retrieve an object to be exposed on the global scope of the
configuration file. The identifier of this object will equal the
registered name of the filesystem. This may be used to expose
variables and methods that the user will need in order to configure
the filesystem. The method is called whenever the configuration
file is reloaded. '''
class Snapshot:
''' Base snapshot class inherited by each filesystem implementation '''
def __init__(self, filesystem, tag, props, **kwprops):
# pylint: disable=unused-argument
# Set common properties
self._filesystem = filesystem
self._tag = tag
# Process arguments to extract all properties
props = _process_args(props, kwprops)
# Delegate further initialisation to the subclass
self.initialise(props)
def initialise(self, props):
''' Perform initialisation. This method is called in the constructor
once the property arguments have been processed and merged into a
single property dictionary. Subclasses typically use this method for
transforming property values and assigning them to private
attributes on the Snapshot object. '''
def filesystem(self):
''' Get parent Filesystem object. This method need not be overridden
in subclasses. '''
return self._filesystem
def tag(self):
''' Get tag name. Each configured schedule in ZAFS has a unique tag
name. The tag name is passed in the constructor of the snapshot. A
tag name paired with an ordinal uniquely identifies a snapshot. This
method need not be overridden in subclasses. '''
return self._tag
def ordinal(self):
''' Get ordinal. Ordinals are sortable, hashable timestamps that are
unique per tag name. They need not be numbers, but they must sort
in a strictly ascending chronological order. The ordinal is
typically derived from the UNIX timestamp the snapshot was taken at.
Before the snapshot is taken, this method returns None. '''
raise NotImplementedError()
async def take(self):
''' Take snapshot and return the ordinal. This method is never called
more than once per snapshot object. '''
def taken(self):
''' This method returns True if the snapshot has been taken. '''
async def delete(self):
''' Delete this snapshot. No further method calls are made on the
snapshot once it has been destroyed. '''
class FilesystemRegistry:
''' Class that keeps a global registry of available Filesystem classes '''
_filesystems = {}
@classmethod
def register(cls, name, klass):
''' Register a filesystem. If a filesystem needs to be configured by the
user, it must retrieve its configuration from a dictionary at
config['filesystems'][name]. '''
cls._filesystems[name] = klass
@classmethod
def all(cls):
''' Retrieve a {name: class} dictionary of all registered
filesystems '''
return dict(cls._filesystems)
#
# Private objects
_filesystems = {}
def _process_args(props, kwprops):
''' Merge 'props' and 'kwprops' into single dictionary '''
if props:
if not isinstance(props, dict):
raise TypeError('Properties argument is not a dictionary')
props = dict(props)
else:
props = {}
# Update properties dictionary with keyword arguments
props.update(kwprops)
return props