<s> """<STR_LIT>""" <EOL> from __future__ import absolute_import <EOL> from errno import ENOENT <EOL> from contextlib import contextmanager <EOL> from tarfile import TarFile <EOL> from io import BytesIO <EOL> from zope . interface import implementer <EOL> from characteristic import with_init , with_cmp , with_repr <EOL> from twisted . internet . defer import succeed , fail <EOL> from twisted . application . service import Service <EOL> from . errors import MaximumSizeTooSmall <EOL> from . interfaces import ( <EOL> IFilesystemSnapshots , IStoragePool , IFilesystem , <EOL> FilesystemAlreadyExists ) <EOL> from . zfs import Snapshot <EOL> from . . _model import VolumeSize <EOL> @ implementer ( IFilesystemSnapshots ) <EOL> class CannedFilesystemSnapshots ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , results ) : <EOL> """<STR_LIT>""" <EOL> self . _results = results <EOL> self . _snapshots = [ ] <EOL> def create ( self , name ) : <EOL> d = self . _results . pop ( <NUM_LIT:0> ) <EOL> d . addCallback ( lambda _ : self . _snapshots . append ( name ) ) <EOL> return d <EOL> def list ( self ) : <EOL> return succeed ( self . _snapshots ) <EOL> @ implementer ( IFilesystem ) <EOL> @ with_cmp ( [ "<STR_LIT:path>" ] ) <EOL> @ with_repr ( [ "<STR_LIT:path>" , "<STR_LIT:size>" ] ) <EOL> @ with_init ( [ "<STR_LIT:path>" , "<STR_LIT:size>" ] , <EOL> defaults = dict ( size = VolumeSize ( maximum_size = None ) ) ) <EOL> class DirectoryFilesystem ( object ) : <EOL> """<STR_LIT>""" <EOL> def get_path ( self ) : <EOL> return self . path <EOL> def _snapshots ( self ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> data = self . get_path ( ) . child ( b"<STR_LIT>" ) . getContent ( ) <EOL> except IOError as e : <EOL> if e . errno != ENOENT : <EOL> raise <EOL> snapshots = [ ] <EOL> else : <EOL> snapshots = [ <EOL> Snapshot ( name = name ) <EOL> for name <EOL> in data . splitlines ( ) <EOL> ] <EOL> return snapshots <EOL> def snapshots ( self ) : <EOL> """<STR_LIT>""" <EOL> return succeed ( self . _snapshots ( ) ) <EOL> def snapshot ( self , name ) : <EOL> """<STR_LIT>""" <EOL> self . get_path ( ) . child ( b"<STR_LIT>" ) . setContent ( <EOL> b"<STR_LIT:\n>" . join ( [ <EOL> snapshot . name for snapshot in self . _snapshots ( ) ] + [ name ] ) <EOL> ) <EOL> @ contextmanager <EOL> def reader ( self , remote_snapshots = None ) : <EOL> """<STR_LIT>""" <EOL> result = BytesIO ( ) <EOL> tarball = TarFile ( fileobj = result , mode = "<STR_LIT:w>" ) <EOL> for child in self . path . children ( ) : <EOL> tarball . add ( child . path , arcname = child . basename ( ) , recursive = True ) <EOL> tarball . close ( ) <EOL> if remote_snapshots : <EOL> result . write ( <EOL> u"<STR_LIT>" . format ( <EOL> u"<STR_LIT:\n>" . join ( snapshot . name for snapshot in remote_snapshots ) <EOL> ) . encode ( "<STR_LIT:ascii>" ) <EOL> ) <EOL> result . seek ( <NUM_LIT:0> , <NUM_LIT:0> ) <EOL> yield result <EOL> @ contextmanager <EOL> def writer ( self ) : <EOL> """<STR_LIT>""" <EOL> result = BytesIO ( ) <EOL> yield result <EOL> result . seek ( <NUM_LIT:0> , <NUM_LIT:0> ) <EOL> try : <EOL> tarball = TarFile ( fileobj = result , mode = "<STR_LIT:r>" ) <EOL> if self . path . exists ( ) : <EOL> self . path . remove ( ) <EOL> self . path . createDirectory ( ) <EOL> tarball . extractall ( self . path . path ) <EOL> except : <EOL> pass <EOL> @ implementer ( IStoragePool ) <EOL> class FilesystemStoragePool ( Service ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , root ) : <EOL> """<STR_LIT>""" <EOL> self . _root = root <EOL> if not self . _root . exists ( ) : <EOL> self . _root . createDirectory ( ) <EOL> def create ( self , volume ) : <EOL> filesystem = self . get ( volume ) <EOL> root = filesystem . get_path ( ) <EOL> root . makedirs ( ) <EOL> if volume . size . maximum_size is not None : <EOL> root . child ( b"<STR_LIT>" ) . setContent ( <EOL> u"<STR_LIT>" . format ( volume . size . maximum_size ) . encode ( "<STR_LIT:ascii>" ) ) <EOL> return succeed ( filesystem ) <EOL> def destroy ( self , volume ) : <EOL> filesystem = self . get ( volume ) <EOL> root = filesystem . get_path ( ) <EOL> root . remove ( ) <EOL> return succeed ( None ) <EOL> def set_maximum_size ( self , volume ) : <EOL> filesystem = self . get ( volume ) <EOL> root = filesystem . get_path ( ) <EOL> def get_size ( ) : <EOL> total_size = <NUM_LIT:0> <EOL> for f in root . walk ( ) : <EOL> if not f . isdir ( ) : <EOL> total_size += f . getsize ( ) <EOL> return total_size <EOL> current_size = get_size ( ) <EOL> size_path = root . child ( b"<STR_LIT>" ) <EOL> if volume . size . maximum_size is not None : <EOL> if volume . size . maximum_size < current_size : <EOL> raise MaximumSizeTooSmall ( ) <EOL> size_path . setContent ( <EOL> u"<STR_LIT>" . format ( volume . size . maximum_size ) . encode ( "<STR_LIT:ascii>" ) ) <EOL> elif size_path . exists ( ) : <EOL> size_path . remove ( ) <EOL> return succeed ( filesystem ) <EOL> def clone_to ( self , parent , volume ) : <EOL> parent = self . get ( parent ) <EOL> child = self . get ( volume ) <EOL> if child . get_path ( ) . exists ( ) : <EOL> return fail ( FilesystemAlreadyExists ( ) ) <EOL> d = self . create ( volume ) <EOL> with parent . reader ( ) as reader : <EOL> with child . writer ( ) as writer : <EOL> writer . write ( reader . read ( ) ) <EOL> return d <EOL> def change_owner ( self , volume , new_volume ) : <EOL> old_filesystem = self . get ( volume ) <EOL> new_filesystem = self . get ( new_volume ) <EOL> if new_filesystem . get_path ( ) . exists ( ) : <EOL> return fail ( FilesystemAlreadyExists ( ) ) <EOL> old_filesystem . get_path ( ) . moveTo ( new_filesystem . get_path ( ) ) <EOL> return succeed ( new_filesystem ) <EOL> def get ( self , volume ) : <EOL> return DirectoryFilesystem ( <EOL> path = self . _root . child ( b"<STR_LIT>" % ( <EOL> volume . node_id . encode ( "<STR_LIT:ascii>" ) , volume . name . to_bytes ( ) ) ) , <EOL> size = volume . size ) <EOL> def enumerate ( self ) : <EOL> filesystems = set ( ) <EOL> if self . _root . isdir ( ) : <EOL> for path in self . _root . children ( ) : <EOL> if path . child ( b"<STR_LIT>" ) . exists ( ) : <EOL> maximum_size = int ( <EOL> path . child ( b"<STR_LIT>" ) . getContent ( ) . decode ( "<STR_LIT:ascii>" ) ) <EOL> else : <EOL> maximum_size = None <EOL> filesystems . add ( <EOL> DirectoryFilesystem ( <EOL> path = path , <EOL> size = VolumeSize ( maximum_size = maximum_size ) , <EOL> ) <EOL> ) <EOL> return succeed ( filesystems ) </s>
