import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger('anate.vm') import os import devices class VirtualDisk(devices.DMDevice): _LOOP_DEV_MAJOR = 7 _AVAILABLE_MINORS = [0, 1, 2, 3, 4, 5, 6, 7] def getAvailableMinor(self): return self._AVAILABLE_MINORS[0] def useMinor(self, minor): self._AVAILABLE_MINORS.remove(minor) def freeMinor(self, minor): self._AVAILABLE_MINORS.append(minor) self._AVAILABLE_MINORS.sort() def __init__(self, name, size, usable_size=None): if not usable_size: usable_size = size elif usable_size > size: logger.error('usable_size cannot be greater than size') return self._remove_node = False self._loop_node = self._createLoopNode(name) if not self._loop_node: raise OSError, 'node error' self._loop_dev = self._createLoopDev(name, self._loop_node, usable_size) devices.DMDevice.__init__(self, name, self._loop_dev, size) def _createLoopNode(self, name): loop_node = devices.BlockDeviceNode(os.path.join('/dev/', name), major=None, minor=None) if loop_node.available: logger.info('using existing node %s', loop_node.path) loop_node.major, loop_node.minor = devices.getDeviceNumbers(loop_node.path) if loop_node.major != self._LOOP_DEV_MAJOR: logger.error('not a loop device node') return if loop_node.minor not in self._AVAILABLE_MINORS: logger.error('node not available') return else: logger.info('creating new node %s', loop_node.path) loop_node.major = self._LOOP_DEV_MAJOR loop_node.minor = self.getAvailableMinor() loop_node.create() self._remove_node = True self.useMinor(loop_node.minor) logger.info('using minor %d', loop_node.minor) logger.info('available minors: %s', self._AVAILABLE_MINORS) if not loop_node.available: raise OSError, 'node error' return loop_node def _createLoopDev(self, name, loop_node, size): loop_dev = devices.LoopDevice(name, loop_node, os.path.join('/tmp/', name), size) loop_dev.initialize() if not loop_dev.active: raise OSError, 'loop device error' return loop_dev def create(self): self.initialize() if not self.active: raise OSError, 'dm device error' def remove(self): self.destroy() if self.active: raise OSError, 'dm device error' self._loop_dev.destroy() if self._loop_dev.active: raise OSError, 'loop device error' if self._remove_node: logger.info('removing node %s', self._loop_node.path) self._loop_node.unlink() if self._loop_node.available: raise OSError, 'node error' self.freeMinor(self._loop_node.minor) logger.info('freeing minor %d', self._loop_node.minor) logger.info('available minors: %s', self._AVAILABLE_MINORS) class VM(object): def __init__(self): self._disks = {} def addDisk(self, name, size, usable_size=None): if name in self.disks: logger.error('disk %s already exists', name) return disk = VirtualDisk(name, size=size, usable_size=usable_size) disk.create() self._disks[name] = disk def removeDisk(self, name): if name not in self.disks: logger.error('disk %s does not exist', name) return disk = self.getDisk(name) if disk.active: disk.remove() del self._disks[name] def halt(self): for disk in self.disks.values(): if disk.active: disk.remove() self._disks = {} @property def disks(self): return self._disks def getDisk(self, name): return self.disks.get(name, None)