Loading ccnode/exc.py +4 −0 Original line number Diff line number Diff line Loading @@ -11,3 +11,7 @@ class PluginError(CCNodeError): class UndefinedDomain(CCNodeError): pass class PoolStorageError(CCNodeError): pass ccnode/hypervisor/__init__.py +80 −6 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ from ccnode.hypervisor.lib import ( EventLoop as VirEventLoop, ) from ccnode.hypervisor.domains import VirtualMachine from ccnode.exc import UndefinedDomain from ccnode.exc import UndefinedDomain, PoolStorageError logger = logging.getLogger(__name__) Loading Loading @@ -247,6 +247,22 @@ class Handler(HostHandler): logger.error(msg) raise UndefinedDomain(msg) def vol_create(self, pool, name, size): logger.debug('Volume create %s, pool %s, size %s', name, pool, size) try: self.hypervisor.storage.create_volume(pool, name, size) except Exception: logger.exception('Error while creating volume') raise def vol_delete(self, pool, name): logger.debug('Volume delete %s, pool %s', name, pool) try: self.hypervisor.storage.delete_volume(pool, name) except Exception: logger.exception('Error while deleting volume') raise class Hypervisor(object): """Container for all hypervisor related state.""" Loading Loading @@ -415,8 +431,8 @@ class StorageIndex(object): ) self.paths = dict( (v.path, v) for v in chain.from_iterable(map( lambda s: s.volumes, (v.path, v) for v in chain.from_iterable(imap( lambda s: s.volumes.itervalues(), self.storages.itervalues(), )), ) Loading @@ -427,6 +443,62 @@ class StorageIndex(object): def get_storage(self, name): return self.storages.get(name) def create_volume(self, pool_name, volume_name, capacity): """Create a new volume in the storage pool. :param str name: name for the volume :param int capacity: size for the volume """ # get volume logger.debug('asked pool %s', pool_name) logger.debug('Pool state %s', self.storages) try: pool = self.storages[pool_name] except KeyError: raise PoolStorageError('Invalid pool name') if pool is None: raise Exception('Storage pool not found') try: new_volume = pool.lv_storage.createXML("""<volume> <name>%s</name> <capacity>%d</capacity> </volume>""" % (volume_name, capacity), 0) except libvirt.libvirtError: logger.exception('Error while creating volume') raise new_volume = Volume(new_volume) # if success add the volume to the index self.paths[new_volume.path] = new_volume # and also to its storage pool self.storages[new_volume.storage].volumes[new_volume.name] = new_volume def delete_volume(self, pool_name, volume_name): """Delete a volume in the givent storage pool. :param str pool_name: name for the storage pool :param str volume_name: name for the volume """ # get volume try: pool = self.storages[pool_name] except KeyError: raise PoolStorageError('Invalid pool name') try: volume = pool.volumes[volume_name] except KeyError: raise PoolStorageError('Invalid volume name') # delete from index del self.paths[volume.path] del self.storages[pool_name].volumes[volume_name] # delete volume try: volume.lv_volume.delete(0) except libvirt.libvirtError: logger.exception('Error while deleting volume') raise class Storage(object): """Storage abstraction.""" Loading @@ -436,15 +508,16 @@ class Storage(object): """ self.uuid = lv_storage.UUID() self.name = lv_storage.name() self.lv_storage = lv_storage self.state, self.capacity, self.allocation, self.available = lv_storage.info() self.state = STORAGE_STATES[self.state] self.volumes = map( self.volumes = dict((v.name, v) for v in imap( Volume, (lv_storage.storageVolLookupByName(n) for n in lv_storage.listVolumes()), ) )) class Volume(object): Loading @@ -457,3 +530,4 @@ class Volume(object): self.path = lv_volume.path() self.name = lv_volume.name() self.capacity, self.allocation = lv_volume.info()[1:] self.lv_volume = lv_volume Loading
ccnode/exc.py +4 −0 Original line number Diff line number Diff line Loading @@ -11,3 +11,7 @@ class PluginError(CCNodeError): class UndefinedDomain(CCNodeError): pass class PoolStorageError(CCNodeError): pass
ccnode/hypervisor/__init__.py +80 −6 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ from ccnode.hypervisor.lib import ( EventLoop as VirEventLoop, ) from ccnode.hypervisor.domains import VirtualMachine from ccnode.exc import UndefinedDomain from ccnode.exc import UndefinedDomain, PoolStorageError logger = logging.getLogger(__name__) Loading Loading @@ -247,6 +247,22 @@ class Handler(HostHandler): logger.error(msg) raise UndefinedDomain(msg) def vol_create(self, pool, name, size): logger.debug('Volume create %s, pool %s, size %s', name, pool, size) try: self.hypervisor.storage.create_volume(pool, name, size) except Exception: logger.exception('Error while creating volume') raise def vol_delete(self, pool, name): logger.debug('Volume delete %s, pool %s', name, pool) try: self.hypervisor.storage.delete_volume(pool, name) except Exception: logger.exception('Error while deleting volume') raise class Hypervisor(object): """Container for all hypervisor related state.""" Loading Loading @@ -415,8 +431,8 @@ class StorageIndex(object): ) self.paths = dict( (v.path, v) for v in chain.from_iterable(map( lambda s: s.volumes, (v.path, v) for v in chain.from_iterable(imap( lambda s: s.volumes.itervalues(), self.storages.itervalues(), )), ) Loading @@ -427,6 +443,62 @@ class StorageIndex(object): def get_storage(self, name): return self.storages.get(name) def create_volume(self, pool_name, volume_name, capacity): """Create a new volume in the storage pool. :param str name: name for the volume :param int capacity: size for the volume """ # get volume logger.debug('asked pool %s', pool_name) logger.debug('Pool state %s', self.storages) try: pool = self.storages[pool_name] except KeyError: raise PoolStorageError('Invalid pool name') if pool is None: raise Exception('Storage pool not found') try: new_volume = pool.lv_storage.createXML("""<volume> <name>%s</name> <capacity>%d</capacity> </volume>""" % (volume_name, capacity), 0) except libvirt.libvirtError: logger.exception('Error while creating volume') raise new_volume = Volume(new_volume) # if success add the volume to the index self.paths[new_volume.path] = new_volume # and also to its storage pool self.storages[new_volume.storage].volumes[new_volume.name] = new_volume def delete_volume(self, pool_name, volume_name): """Delete a volume in the givent storage pool. :param str pool_name: name for the storage pool :param str volume_name: name for the volume """ # get volume try: pool = self.storages[pool_name] except KeyError: raise PoolStorageError('Invalid pool name') try: volume = pool.volumes[volume_name] except KeyError: raise PoolStorageError('Invalid volume name') # delete from index del self.paths[volume.path] del self.storages[pool_name].volumes[volume_name] # delete volume try: volume.lv_volume.delete(0) except libvirt.libvirtError: logger.exception('Error while deleting volume') raise class Storage(object): """Storage abstraction.""" Loading @@ -436,15 +508,16 @@ class Storage(object): """ self.uuid = lv_storage.UUID() self.name = lv_storage.name() self.lv_storage = lv_storage self.state, self.capacity, self.allocation, self.available = lv_storage.info() self.state = STORAGE_STATES[self.state] self.volumes = map( self.volumes = dict((v.name, v) for v in imap( Volume, (lv_storage.storageVolLookupByName(n) for n in lv_storage.listVolumes()), ) )) class Volume(object): Loading @@ -457,3 +530,4 @@ class Volume(object): self.path = lv_volume.path() self.name = lv_volume.name() self.capacity, self.allocation = lv_volume.info()[1:] self.lv_volume = lv_volume