summaryrefslogtreecommitdiffstats
path: root/anate/vm.py
diff options
context:
space:
mode:
authorMartin Gracik <mgracik@redhat.com>2009-03-24 11:05:40 +0100
committerMartin Gracik <mgracik@redhat.com>2009-03-24 14:41:55 +0100
commitac83df7815ff3db042875db51a43c107e982ee70 (patch)
treea8b67d04cf0b00ea92b6fa1d4c162123dc9fa0e3 /anate/vm.py
downloadanate-ac83df7815ff3db042875db51a43c107e982ee70.tar.gz
anate-ac83df7815ff3db042875db51a43c107e982ee70.tar.xz
anate-ac83df7815ff3db042875db51a43c107e982ee70.zip
Initial commitHEADmaster
Diffstat (limited to 'anate/vm.py')
-rw-r--r--anate/vm.py135
1 files changed, 135 insertions, 0 deletions
diff --git a/anate/vm.py b/anate/vm.py
new file mode 100644
index 0000000..71fcabc
--- /dev/null
+++ b/anate/vm.py
@@ -0,0 +1,135 @@
+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)