# HG changeset patch
# User Alastair Tse <atse@xxxxxxxxxxxxx>
# Date 1169653651 0
# Node ID 665be23d7fe9d7ab1380df4630e0c85169786ba5
# Parent bea3d48576c66663e559fbba1bcd9f840a3d1b25
[XEND] Add support for multiple storage repositories.
Splits XendStorageRepository into a helper class and
XendQCowStorageRepo as the QCoW File backed repository. This gives us
the opportunity to introduce a pseudo storage repository to represent
the old way of specifying block devices. This is the
XendLocalStorageRepo.
Note that this still introduces a non-Xen API 'uri' attribute to VDIs
in order to support querying VDIs for their actual location relative
to the Xen host.
The QCoW backed repository is now named QCoW, and the pseudo-SR is
named Local.
This removes the 'image' attribute backwards-compat hack in VBDs in
the Xen API.
Signed-off-by: Alastair Tse <atse@xxxxxxxxxxxxx>
---
tools/python/xen/xend/XendAPI.py | 117 +++----
tools/python/xen/xend/XendConfig.py | 14
tools/python/xen/xend/XendDomainInfo.py | 39 +-
tools/python/xen/xend/XendLocalStorageRepo.py | 94 ++++++
tools/python/xen/xend/XendNode.py | 90 ++++--
tools/python/xen/xend/XendOptions.py | 10
tools/python/xen/xend/XendQCoWStorageRepo.py | 366 +++++++++++++++++++++++++
tools/python/xen/xend/XendStorageRepository.py | 353 ++----------------------
tools/python/xen/xend/XendVDI.py | 33 +-
9 files changed, 681 insertions(+), 435 deletions(-)
diff -r bea3d48576c6 -r 665be23d7fe9 tools/python/xen/xend/XendAPI.py
--- a/tools/python/xen/xend/XendAPI.py Wed Jan 24 14:25:21 2007 +0000
+++ b/tools/python/xen/xend/XendAPI.py Wed Jan 24 15:47:31 2007 +0000
@@ -214,7 +214,7 @@ def valid_vdi(func):
@rtype: callable object
"""
return lambda *args, **kwargs: \
- _check_ref(XendNode.instance().get_sr().is_valid_vdi,
+ _check_ref(XendNode.instance().is_valid_vdi,
'VDI_HANDLE_INVALID', func, *args, **kwargs)
def valid_vtpm(func):
@@ -234,7 +234,7 @@ def valid_sr(func):
@rtype: callable object
"""
return lambda *args, **kwargs: \
- _check_ref(lambda r: XendNode.instance().get_sr().uuid == r,
+ _check_ref(lambda r: XendNode.instance().is_valid_sr,
'SR_HANDLE_INVALID', func, *args, **kwargs)
def valid_pif(func):
@@ -1203,8 +1203,7 @@ class XendAPI:
# Xen API: Class VBD
# ----------------------------------------------------------------
- VBD_attr_ro = ['image',
- 'io_read_kbs',
+ VBD_attr_ro = ['io_read_kbs',
'io_write_kbs']
VBD_attr_rw = ['VM',
'VDI',
@@ -1213,7 +1212,7 @@ class XendAPI:
'type',
'driver']
- VBD_attr_inst = VBD_attr_rw + ['image']
+ VBD_attr_inst = VBD_attr_rw
VBD_methods = [('media_change', None)]
VBD_funcs = [('create', 'VBD')]
@@ -1250,18 +1249,15 @@ class XendAPI:
dom = xendom.get_vm_by_uuid(vbd_struct['VM'])
vbd_ref = ''
try:
- if not vbd_struct.get('VDI', None):
- # this is a traditional VBD without VDI and SR
- vbd_ref = dom.create_vbd(vbd_struct)
- else:
- # new VBD via VDI/SR
- vdi_ref = vbd_struct.get('VDI')
- sr = XendNode.instance().get_sr()
- vdi_image = sr.xen_api_get_by_uuid(vdi_ref)
- if not vdi_image:
- return xen_api_error(['VDI_HANDLE_INVALID', vdi_ref])
- vdi_image = vdi_image.qcow_path
- vbd_ref = dom.create_vbd_with_vdi(vbd_struct, vdi_image)
+ # new VBD via VDI/SR
+ vdi_ref = vbd_struct.get('VDI')
+ vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
+ if not vdi:
+ return xen_api_error(['VDI_HANDLE_INVALID', vdi_ref])
+ vdi_image = vdi.get_image_uri()
+ vbd_ref = XendTask.log_progress(0, 100,
+ dom.create_vbd,
+ vbd_struct, vdi_image)
except XendError:
return xen_api_todo()
@@ -1275,7 +1271,7 @@ class XendAPI:
if not vm:
return xen_api_error(['VBD_HANDLE_INVALID', vbd_ref])
- vm.destroy_vbd(vbd_ref)
+ XendTask.log_progress(0, 100, vm.destroy_vbd, vbd_ref)
return xen_api_success_void()
# attributes (rw)
@@ -1446,7 +1442,7 @@ class XendAPI:
('get_by_name_label', 'Set(VDI)')]
def _get_VDI(self, ref):
- return XendNode.instance().get_sr().xen_api_get_by_uuid(ref)
+ return XendNode.instance().get_vdi_by_uuid(ref)
def VDI_get_VBDs(self, session, vdi_ref):
return xen_api_todo()
@@ -1474,8 +1470,7 @@ class XendAPI:
return xen_api_success(self._get_VDI(vdi_ref).name_description)
def VDI_get_SR(self, session, vdi_ref):
- sr = XendNode.instance().get_sr()
- return xen_api_success(sr.uuid)
+ return xen_api_success(self._get_VDI(vdi_ref).sr_uuid)
def VDI_get_virtual_size(self, session, vdi_ref):
return xen_api_success(self._get_VDI(vdi_ref).virtual_size)
@@ -1513,18 +1508,17 @@ class XendAPI:
return xen_api_todo()
def VDI_destroy(self, session, vdi_ref):
- sr = XendNode.instance().get_sr()
- sr.destroy_image(vdi_ref)
+ sr = XendNode.instance().get_sr_containing_vdi(vdi_ref)
+ sr.destroy_vdi(vdi_ref)
return xen_api_success_void()
def VDI_get_record(self, session, vdi_ref):
- sr = XendNode.instance().get_sr()
- image = sr.xen_api_get_by_uuid(vdi_ref)
+ image = XendNode.instance().get_vdi_by_uuid(vdi_ref)
return xen_api_success({
'uuid': vdi_ref,
'name_label': image.name_label,
'name_description': image.name_description,
- 'SR': sr.uuid,
+ 'SR': image.sr_uuid,
'VBDs': [], # TODO
'virtual_size': image.virtual_size,
'physical_utilisation': image.physical_utilisation,
@@ -1538,25 +1532,22 @@ class XendAPI:
# Class Functions
def VDI_create(self, session, vdi_struct):
- sr = XendNode.instance().get_sr()
sr_ref = vdi_struct.get('SR')
-
- if sr.uuid != sr_ref:
- return xen_api_error(['SR_HANDLE_INVALID', vdi_struct.get('SR')])
-
- vdi_uuid = sr.create_image(vdi_struct)
+ xennode = XendNode.instance()
+ if not xennode.is_valid_sr(sr_ref):
+ return xen_api_error(['SR_HANDLE_INVALID', sr_ref])
+
+ vdi_uuid = xennode.srs[sr_ref].create_vdi(vdi_struct)
return xen_api_success(vdi_uuid)
def VDI_get_all(self, session):
- sr = XendNode.instance().get_sr()
- return xen_api_success(sr.list_images())
+ xennode = XendNode.instance()
+ vdis = [sr.get_vdis() for sr in xennode.srs.values()]
+ return xen_api_success(reduce(lambda x, y: x + y, vdis))
def VDI_get_by_name_label(self, session, name):
- sr = XendNode.instance().get_sr()
- image_uuid = sr.xen_api_get_by_name_label(name)
- if image_uuid:
- return xen_api_success([image_uuid])
- return xen_api_success([])
+ xennode = XendNode.instance()
+ return xen_api_success(xennode.get_vdi_by_name_label(name))
# Xen API: Class VTPM
@@ -1691,15 +1682,11 @@ class XendAPI:
# Class Functions
def SR_get_all(self, session):
- sr = XendNode.instance().get_sr()
- return xen_api_success([sr.uuid])
-
+ return xen_api_success(XendNode.instance().get_all_sr_uuid())
+
def SR_get_by_name_label(self, session, label):
- sr = XendNode.instance().get_sr()
- if sr.name_label != label:
- return xen_api_success([])
- return xen_api_success([sr.uuid])
-
+ return xen_api_success(XendNode.instance().get_sr_by_name(label))
+
def SR_create(self, session):
return xen_api_error(XEND_ERROR_UNSUPPORTED)
@@ -1711,16 +1698,20 @@ class XendAPI:
return xen_api_error(XEND_ERROR_UNSUPPORTED)
def SR_get_record(self, session, sr_ref):
- sr = XendNode.instance().get_sr()
- return xen_api_success(sr.get_record())
+ sr = XendNode.instance().get_sr(sr_ref)
+ if sr:
+ return xen_api_success(sr.get_record())
+ return xen_api_error(['SR_HANDLE_INVALID', sr_ref])
# Attribute acceess
- def _get_SR_func(self, _, func):
- return xen_api_success(getattr(XendNode.instance().get_sr(), func)())
-
- def _get_SR_attr(self, _, attr):
- return xen_api_success(getattr(XendNode.instance().get_sr(), attr))
+ def _get_SR_func(self, sr_ref, func):
+ return xen_api_success(getattr(XendNode.instance().get_sr(sr_ref),
+ func)())
+
+ def _get_SR_attr(self, sr_ref, attr):
+ return xen_api_success(getattr(XendNode.instance().get_sr(sr_ref),
+ attr))
def SR_get_VDIs(self, _, ref):
return self._get_SR_func(ref, 'list_images')
@@ -1729,10 +1720,10 @@ class XendAPI:
return self._get_SR_func(ref, 'virtual_allocation')
def SR_get_physical_utilisation(self, _, ref):
- return self._get_SR_func(ref, 'used_space_bytes')
+ return self._get_SR_func(ref, 'physical_utilisation')
def SR_get_physical_size(self, _, ref):
- return self._get_SR_func(ref, 'total_space_bytes')
+ return self._get_SR_func(ref, 'physical_size')
def SR_get_type(self, _, ref):
return self._get_SR_attr(ref, 'type')
@@ -1747,15 +1738,17 @@ class XendAPI:
return self._get_SR_attr(ref, 'name_description')
def SR_set_name_label(self, session, sr_ref, value):
- sr = XendNode.instance().get_sr()
- sr.name_label = value
- XendNode.instance().save()
+ sr = XendNode.instance.get_sr(sr_ref)
+ if sr:
+ sr.name_label = value
+ XendNode.instance().save()
return xen_api_success_void()
def SR_set_name_description(self, session, sr_ref, value):
- sr = XendNode.instance().get_sr()
- sr.name_description = value
- XendNode.instance().save()
+ sr = XendNode.instance.get_sr(sr_ref)
+ if sr:
+ sr.name_description = value
+ XendNode.instance().save()
return xen_api_success_void()
diff -r bea3d48576c6 -r 665be23d7fe9 tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py Wed Jan 24 14:25:21 2007 +0000
+++ b/tools/python/xen/xend/XendConfig.py Wed Jan 24 15:47:31 2007 +0000
@@ -994,13 +994,15 @@ class XendConfig(dict):
return dev_uuid
elif dev_type in ('vbd', 'tap'):
- if dev_type == 'vbd':
- dev_info['uname'] = cfg_xenapi.get('image', '')
- dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
- elif dev_type == 'tap':
- dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
- dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
+ dev_info['type'] = cfg_xenapi.get('type', 'Disk')
+ if dev_info['type'] == 'CD':
+ old_vbd_type = 'cdrom'
+ else:
+ old_vbd_type = 'disk'
+ dev_info['uname'] = cfg_xenapi.get('image', '')
+ dev_info['dev'] = '%s:%s' % (cfg_xenapi.get('device'),
+ old_vbd_type)
dev_info['driver'] = cfg_xenapi.get('driver')
dev_info['VDI'] = cfg_xenapi.get('VDI', '')
diff -r bea3d48576c6 -r 665be23d7fe9 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Wed Jan 24 14:25:21 2007 +0000
+++ b/tools/python/xen/xend/XendDomainInfo.py Wed Jan 24 15:47:31 2007 +0000
@@ -1656,7 +1656,7 @@ class XendDomainInfo:
from xen.xend import XendDomain
dom0 = XendDomain.instance().privilegedDomain()
- dom0._waitForDeviceUUID(dom0.create_vbd_with_vdi(vbd, fn))
+ dom0._waitForDeviceUUID(dom0.create_vbd(vbd, fn))
fn = BOOTLOADER_LOOPBACK_DEVICE
try:
@@ -2133,24 +2133,7 @@ class XendDomainInfo:
def get_vtpms(self):
return self.info.get('vtpm_refs', [])
- def create_vbd(self, xenapi_vbd):
- """Create a VBD device from the passed struct in Xen API format.
-
- @return: uuid of the device
- @rtype: string
- """
-
- dev_uuid = self.info.device_add('vbd', cfg_xenapi = xenapi_vbd)
- if not dev_uuid:
- raise XendError('Failed to create device')
-
- if self.state == XEN_API_VM_POWER_STATE_RUNNING:
- _, config = self.info['devices'][dev_uuid]
- config['devid'] =
self.getDeviceController('vbd').createDevice(config)
-
- return dev_uuid
-
- def create_vbd_with_vdi(self, xenapi_vbd, vdi_image_path):
+ def create_vbd(self, xenapi_vbd, vdi_image_path):
"""Create a VBD using a VDI from XendStorageRepository.
@param xenapi_vbd: vbd struct from the Xen API
@@ -2159,14 +2142,26 @@ class XendDomainInfo:
@return: uuid of the device
"""
xenapi_vbd['image'] = vdi_image_path
- log.debug('create_vbd_with_vdi: %s' % xenapi_vbd)
- dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
+ log.debug('create_vbd: %s' % xenapi_vbd)
+ dev_uuid = ''
+ if vdi_image_path.startswith('tap'):
+ dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
+ else:
+ dev_uuid = self.info.device_add('vbd', cfg_xenapi = xenapi_vbd)
+
if not dev_uuid:
raise XendError('Failed to create device')
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
_, config = self.info['devices'][dev_uuid]
- config['devid'] =
self.getDeviceController('tap').createDevice(config)
+ dev_control = None
+
+ if vdi_image_path.startswith('tap'):
+ dev_control = self.getDeviceController('tap')
+ else:
+ dev_control = self.getDeviceController('vbd')
+
+ config['devid'] = dev_control.createDevice(config)
return dev_uuid
diff -r bea3d48576c6 -r 665be23d7fe9
tools/python/xen/xend/XendLocalStorageRepo.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/XendLocalStorageRepo.py Wed Jan 24 15:47:31
2007 +0000
@@ -0,0 +1,94 @@
+#!/usr/bin/python
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2007 XenSource Ltd.
+#============================================================================
+#
+# A pseudo-StorageRepository to provide a representation for the images
+# that can be specified by xm.
+#
+
+import commands
+import logging
+import os
+import stat
+import threading
+import re
+import sys
+import struct
+
+from xen.util import mkdir
+from xen.xend import uuid
+from xen.xend.XendError import XendError
+from xen.xend.XendVDI import *
+from xen.xend.XendTask import XendTask
+from xen.xend.XendStorageRepository import XendStorageRepository
+from xen.xend.XendStateStore import XendStateStore
+from xen.xend.XendOptions import instance as xendoptions
+
+MB = 1024 * 1024
+
+log = logging.getLogger("xend.XendLocalStorageRepo")
+
+class XendLocalStorageRepo(XendStorageRepository):
+ """A backwards compatibility storage repository so that
+ traditional file:/dir/file.img and phy:/dev/hdxx images can
+ still be represented in terms of the Xen API.
+ """
+
+ def __init__(self, sr_uuid, sr_type = 'local',
+ name_label = 'Local',
+ name_description = 'Traditional Local Storage Repo'):
+ """
+ @ivar images: mapping of all the images.
+ @type images: dictionary by image uuid.
+ @ivar lock: lock to provide thread safety.
+ """
+
+ XendStorageRepository.__init__(self, sr_uuid, sr_type,
+ name_label, name_description,
+ '/')
+
+ self.state = XendStateStore(xendoptions().get_xend_state_path()
+ + '/local_sr')
+
+ stored_images = self.state.load_state('vdi')
+ if stored_images:
+ for image_uuid, image in stored_images.items():
+ self.images[image_uuid] = XendLocalVDI(image)
+
+ def create_vdi(self, vdi_struct):
+ """ Creates a fake VDI image for a traditional image string.
+
+ The image uri is stored in the attribute 'uri'
+ """
+ vdi_struct['uuid'] = uuid.createString()
+ vdi_struct['SR'] = self.uuid
+ new_image = XendLocalVDI(vdi_struct)
+ self.images[new_image.uuid] = new_image
+ self.save_state()
+ return new_image.uuid
+
+ def save_state(self):
+ vdi_records = dict([(k, v.get_record(transient = False))
+ for k, v in self.images.items()])
+ self.state.save_state('vdi', vdi_records)
+
+ def destroy_vdi(self, vdi_uuid):
+ if vdi_uuid in self.images:
+ del self.images[vdi_uuid]
+
+ self.save_state()
+
diff -r bea3d48576c6 -r 665be23d7fe9 tools/python/xen/xend/XendNode.py
--- a/tools/python/xen/xend/XendNode.py Wed Jan 24 14:25:21 2007 +0000
+++ b/tools/python/xen/xend/XendNode.py Wed Jan 24 15:47:31 2007 +0000
@@ -25,7 +25,8 @@ from xen.xend import uuid
from xen.xend import uuid
from xen.xend.XendError import XendError, NetworkAlreadyConnected
from xen.xend.XendOptions import instance as xendoptions
-from xen.xend.XendStorageRepository import XendStorageRepository
+from xen.xend.XendQCoWStorageRepo import XendQCoWStorageRepo
+from xen.xend.XendLocalStorageRepo import XendLocalStorageRepo
from xen.xend.XendLogging import log
from xen.xend.XendPIF import *
from xen.xend.XendNetwork import *
@@ -88,7 +89,8 @@ class XendNode:
self.pifs = {}
self.networks = {}
-
+ self.srs = {}
+
# initialise networks
saved_networks = self.state_store.load_state('network')
if saved_networks:
@@ -121,13 +123,23 @@ class XendNode:
self.PIF_create(name, mtu, '', mac, network, False)
# initialise storage
- saved_sr = self.state_store.load_state('sr')
- if saved_sr and len(saved_sr) == 1:
- sr_uuid = saved_sr.keys()[0]
- self.sr = XendStorageRepository(sr_uuid)
- else:
- sr_uuid = uuid.createString()
- self.sr = XendStorageRepository(sr_uuid)
+ saved_srs = self.state_store.load_state('sr')
+ if saved_srs:
+ for sr_uuid, sr_cfg in saved_srs.items():
+ if sr_cfg['type'] == 'qcow_file':
+ self.srs[sr_uuid] = XendQCoWStorageRepo(sr_uuid)
+ elif sr_cfg['type'] == 'local_image':
+ self.srs[sr_uuid] = XendLocalStorageRepo(sr_uuid)
+
+ # Create missing SRs if they don't exist
+ if not self.get_sr_by_type('local_image'):
+ image_sr_uuid = uuid.createString()
+ self.srs[image_sr_uuid] = XendLocalStorageRepo(image_sr_uuid)
+
+ if not self.get_sr_by_type('qcow_file'):
+ qcow_sr_uuid = uuid.createString()
+ self.srs[qcow_sr_uuid] = XendQCowStorageRepo(qcow_sr_uuid)
+
def network_create(self, name_label, name_description,
@@ -184,9 +196,7 @@ class XendNode:
self.state_store.save_state('cpu', self.cpus)
self.save_PIFs()
self.save_networks()
-
- sr_record = {self.sr.uuid: self.sr.get_record()}
- self.state_store.save_state('sr', sr_record)
+ self.save_SRs()
def save_PIFs(self):
pif_records = dict([(k, v.get_record(transient = False))
@@ -198,6 +208,11 @@ class XendNode:
for k, v in self.networks.items()])
self.state_store.save_state('network', net_records)
+ def save_SRs(self):
+ sr_records = dict([(k, v.get_record(transient = False))
+ for k, v in self.srs.items()])
+ self.state_store.save_state('sr', sr_records)
+
def shutdown(self):
return 0
@@ -206,7 +221,6 @@ class XendNode:
def notify(self, _):
return 0
-
#
# Ref validation
@@ -221,12 +235,50 @@ class XendNode:
def is_valid_network(self, network_ref):
return (network_ref in self.networks)
- #
- # Storage Repo
- #
-
- def get_sr(self):
- return self.sr
+ def is_valid_sr(self, sr_ref):
+ return (sr_ref in self.srs)
+
+ def is_valid_vdi(self, vdi_ref):
+ for sr in self.srs.values():
+ if sr.is_valid_vdi(vdi_ref):
+ return True
+ return False
+
+ #
+ # Storage Repositories
+ #
+
+ def get_sr(self, sr_uuid):
+ return self.srs.get(sr_uuid)
+
+ def get_sr_by_type(self, sr_type):
+ return [sr.uuid for sr in self.srs.values() if sr.type == sr_type]
+
+ def get_sr_by_name(self, name):
+ return [sr.uuid for sr in self.srs.values() if sr.name_label == name]
+
+ def get_all_sr_uuid(self):
+ return self.srs.keys()
+
+ def get_vdi_by_uuid(self, vdi_uuid):
+ for sr in self.srs.values():
+ if sr.is_valid_vdi(vdi_uuid):
+ return sr.get_vdi_by_uuid(vdi_uuid)
+ return None
+
+ def get_vdi_by_name_label(self, name):
+ for sr in self.srs.values():
+ vdi = sr.get_vdi_by_name_label(name)
+ if vdi:
+ return vdi
+ return None
+
+ def get_sr_containing_vdi(self, vdi_uuid):
+ for sr in self.srs.values():
+ if sr.is_valid_vdi(vdi_uuid):
+ return sr
+ return None
+
#
# Host Functions
diff -r bea3d48576c6 -r 665be23d7fe9 tools/python/xen/xend/XendOptions.py
--- a/tools/python/xen/xend/XendOptions.py Wed Jan 24 14:25:21 2007 +0000
+++ b/tools/python/xen/xend/XendOptions.py Wed Jan 24 15:47:31 2007 +0000
@@ -104,6 +104,9 @@ class XendOptions:
"""Default xend management state storage."""
xend_state_path_default = '/var/lib/xend/state'
+ """Default xend QCoW storage repository location."""
+ xend_storage_path_default = '/var/lib/xend/storage'
+
"""Default type of backend network interfaces"""
netback_type = osdep.netback_type
@@ -211,7 +214,12 @@ class XendOptions:
def get_xend_state_path(self):
""" Get the path for persistent domain configuration storage
"""
- return self.get_config_string("xend-state-path",
self.xend_state_path_default)
+ return self.get_config_string("xend-state-path",
self.xend_state_path_default)
+
+ def get_xend_storage_path(self):
+ """ Get the path for persistent domain configuration storage
+ """
+ return self.get_config_string("xend-storage-path",
self.xend_storage_path_default)
def get_network_script(self):
"""@return the script used to alter the network configuration when
diff -r bea3d48576c6 -r 665be23d7fe9
tools/python/xen/xend/XendQCoWStorageRepo.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/XendQCoWStorageRepo.py Wed Jan 24 15:47:31
2007 +0000
@@ -0,0 +1,366 @@
+#!/usr/bin/python
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006,2007 XenSource Ltd.
+#============================================================================
+#
+# The default QCOW Xen API Storage Repository
+#
+
+import commands
+import logging
+import os
+import stat
+import threading
+import re
+import sys
+import struct
+
+from xen.util import mkdir
+from xen.xend import uuid
+from xen.xend.XendError import XendError
+from xen.xend.XendVDI import *
+from xen.xend.XendTask import XendTask
+from xen.xend.XendStorageRepository import XendStorageRepository
+from xen.xend.XendOptions import instance as xendoptions
+
+XEND_STORAGE_NO_MAXIMUM = sys.maxint
+XEND_STORAGE_QCOW_FILENAME = "%s.qcow"
+XEND_STORAGE_VDICFG_FILENAME = "%s.vdi.xml"
+QCOW_CREATE_COMMAND = "/usr/sbin/qcow-create -r %d %s"
+
+MB = 1024 * 1024
+
+log = logging.getLogger("xend.XendQCowStorageRepo")
+
+
+def qcow_virtual_size(qcow_file):
+ """Read the first 32 bytes of the QCoW header to determine its size.
+
+ See: http://www.gnome.org/~markmc/qcow-image-format.html.
+ """
+ try:
+ qcow_header = open(qcow_file, 'rb').read(32)
+ parts = struct.unpack('>IIQIIQ', qcow_header)
+ return parts[-1]
+ except IOError:
+ return -1
+
+class XendQCoWStorageRepo(XendStorageRepository):
+ """A simple file backed QCOW Storage Repository.
+
+ This class exposes the interface to create VDI's via the
+ Xen API. The backend is a file-backed QCOW format that is stored
+ in XEND_STORAGE_DIR or any that is specified in the constructor.
+
+ The actual images are created in the format <uuid>.img and <uuid>.qcow.
+ """
+
+ def __init__(self, sr_uuid,
+ sr_type = "qcow_file",
+ name_label = "QCoW",
+ name_description = "Xend QCoW Storage Repository",
+ location = xendoptions().get_xend_storage_path(),
+ storage_max = XEND_STORAGE_NO_MAXIMUM):
+ """
+ @keyword storage_max: Maximum disk space to use in bytes.
+ @type storage_max: int
+
+ @ivar storage_free: storage space free for this repository
+ @ivar images: mapping of all the images.
+ @type images: dictionary by image uuid.
+ @ivar lock: lock to provide thread safety.
+ """
+
+ XendStorageRepository.__init__(self, sr_uuid, sr_type, name_label,
+ name_description, location,
+ storage_max)
+ self.storage_free = 0
+ self._refresh()
+
+ def get_record(self, transient = True):
+ retval = {'uuid': self.uuid,
+ 'name_label': self.name_label,
+ 'name_description': self.name_description,
+ 'virtual_allocation': self.virtual_allocation,
+ 'physical_utilisation': self.physical_utilisation,
+ 'physical_size': self.physical_size,
+ 'type': self.type,
+ 'location': self.location,
+ 'VDIs': self.images.keys()}
+
+ if self.physical_size == XEND_STORAGE_NO_MAXIMUM:
+ stfs = os.statvfs(self.location)
+ retval['physical_size'] = stfs.f_blocks * stfs.f_frsize
+
+ return retval
+
+ def _refresh(self):
+ """Internal function that refreshes the state of the disk and
+ updates the list of images available.
+ """
+ self.lock.acquire()
+ try:
+ mkdir.parents(self.location, stat.S_IRWXU)
+
+ # scan the directory and populate self.images
+ virtual_alloc = 0
+ physical_used = 0
+ seen_images = []
+ for filename in os.listdir(self.location):
+ if filename[-5:] == XEND_STORAGE_QCOW_FILENAME[-5:]:
+ image_uuid = filename[:-5]
+ seen_images.append(image_uuid)
+
+ qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
+ cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
+ qcow_path = os.path.join(self.location, qcow_file)
+ cfg_path = os.path.join(self.location, cfg_file)
+
+ phys_size = os.stat(qcow_path).st_size
+ virt_size = qcow_virtual_size(qcow_path)
+
+ # add this image if we haven't seen it before
+ if image_uuid not in self.images:
+ vdi = XendQCoWVDI(image_uuid, self.uuid,
+ qcow_path, cfg_path,
+ virt_size, phys_size)
+
+ if cfg_path and os.path.exists(cfg_path):
+ try:
+ vdi.load_config(cfg_path)
+ except:
+ log.error('Corrupt VDI configuration file %s' %
+ cfg_path)
+
+ self.images[image_uuid] = vdi
+
+ physical_used += phys_size
+ virtual_alloc += virt_size
+
+ # remove images that aren't valid
+ for image_uuid in self.images.keys():
+ if image_uuid not in seen_images:
+ try:
+ os.unlink(self.images[image_uuid].qcow_path)
+ except OSError:
+ pass
+ del self.images[image_uuid]
+
+ self.virtual_allocation = virtual_alloc
+ self.physical_utilisation = physical_used
+
+ # update free storage if we have to track that
+ if self.physical_size == XEND_STORAGE_NO_MAXIMUM:
+ self.storage_free = self._get_free_space()
+ else:
+ self.storage_free = self.physical_size -
self.virtual_allocation
+
+ finally:
+ self.lock.release()
+
+ def _get_free_space(self):
+ """Returns the amount of free space in bytes available in the storage
+ partition. Note that this may not be used if the storage repository
+ is initialised with a maximum size in storage_max.
+
+ @rtype: int
+ """
+ stfs = os.statvfs(self.location)
+ return stfs.f_bavail * stfs.f_frsize
+
+ def _has_space_available_for(self, size_bytes):
+ """Returns whether there is enough space for an image in the
+ partition which the storage_dir resides on.
+
+ @rtype: bool
+ """
+ if self.physical_size != XEND_STORAGE_NO_MAXIMUM:
+ return self.storage_free > size_bytes
+
+ bytes_free = self._get_free_space()
+ if size_bytes < bytes_free:
+ return True
+ return False
+
+ def _create_image_files(self, desired_size_bytes):
+ """Create an image and return its assigned UUID.
+
+ @param desired_size_bytes: Desired image size in bytes
+ @type desired_size_bytes: int
+ @rtype: string
+ @return: uuid
+
+ @raises XendError: If an error occurs.
+ """
+ self.lock.acquire()
+ try:
+ if not self._has_space_available_for(desired_size_bytes):
+ raise XendError("Not enough space")
+
+ image_uuid = uuid.createString()
+ qcow_path = os.path.join(self.location,
+ XEND_STORAGE_QCOW_FILENAME % image_uuid)
+
+ if qcow_path and os.path.exists(qcow_path):
+ raise XendError("Image with same UUID alreaady exists:" %
+ image_uuid)
+
+ cmd = QCOW_CREATE_COMMAND % (desired_size_bytes/MB, qcow_path)
+ rc, output = commands.getstatusoutput(cmd)
+
+ if rc != 0:
+ # cleanup the image file
+ os.unlink(qcow_path)
+ raise XendError("Failed to create QCOW Image: %s" % output)
+
+ self._refresh()
+ return image_uuid
+ finally:
+ self.lock.release()
+
+ def destroy_vdi(self, image_uuid):
+ """Destroy an image that is managed by this storage repository.
+
+ @param image_uuid: Image UUID
+ @type image_uuid: String
+ @rtype: String
+ """
+ self.lock.acquire()
+ try:
+ if image_uuid in self.images:
+ # TODO: check if it is being used?
+ qcow_path = self.images[image_uuid].qcow_path
+ cfg_path = self.images[image_uuid].cfg_path
+ try:
+ os.unlink(qcow_path)
+ if cfg_path and os.path.exists(cfg_path):
+ os.unlink(cfg_path)
+ except OSError:
+ log.exception("Failed to destroy image")
+ del self.images[image_uuid]
+ return True
+ finally:
+ self.lock.release()
+
+ return False
+
+ def list_images(self):
+ """ List all the available images by UUID.
+
+ @rtype: list of strings.
+ @return: list of UUIDs
+ """
+ self.lock.acquire()
+ try:
+ return self.images.keys()
+ finally:
+ self.lock.release()
+
+ def free_space_bytes(self):
+ """Returns the amount of available space in KB.
+ @rtype: int
+ """
+ self.lock.acquire()
+ try:
+ return self.storage_free
+ finally:
+ self.lock.release()
+
+ def total_space_bytes(self):
+ """Returns the total usable space of the storage repo in KB.
+ @rtype: int
+ """
+ self.lock.acquire()
+ try:
+ if self.physical_size == XEND_STORAGE_NO_MAXIMUM:
+ stfs = os.statvfs(self.location)
+ return stfs.f_blocks * stfs.f_frsize
+ else:
+ return self.physical_size
+ finally:
+ self.lock.release()
+
+ def used_space_bytes(self):
+ """Returns the total amount of space used by this storage repository.
+ @rtype: int
+ """
+ self.lock.acquire()
+ try:
+ return self.physical_utilisation
+ finally:
+ self.lock.release()
+
+ def virtual_allocation(self):
+ """Returns the total virtual space allocated within the storage repo.
+ @rtype: int
+ """
+ self.lock.acquire()
+ try:
+ return self.virtual_allocation
+ finally:
+ self.lock.release()
+
+
+ def create_vdi(self, vdi_struct):
+ image_uuid = None
+ try:
+ sector_count = int(vdi_struct.get('virtual_size', 0))
+ sector_size = int(vdi_struct.get('sector_size', 1024))
+ size_bytes = (sector_count * sector_size)
+
+ image_uuid = self._create_image_files(size_bytes)
+
+ image = self.images[image_uuid]
+ image_cfg = {
+ 'sector_size': sector_size,
+ 'virtual_size': sector_count,
+ 'type': vdi_struct.get('type', 'system'),
+ 'name_label': vdi_struct.get('name_label', ''),
+ 'name_description': vdi_struct.get('name_description', ''),
+ 'sharable': bool(vdi_struct.get('sharable', False)),
+ 'read_only': bool(vdi_struct.get('read_only', False)),
+ }
+
+ # load in configuration from vdi_struct
+ image.load_config_dict(image_cfg)
+
+ # save configuration to file
+ cfg_filename = XEND_STORAGE_VDICFG_FILENAME % image_uuid
+ cfg_path = os.path.join(self.location, cfg_filename)
+ image.save_config(cfg_path)
+
+ except Exception, e:
+ # cleanup before raising exception
+ if image_uuid:
+ self.destroy_vdi(image_uuid)
+
+ raise
+
+ return image_uuid
+
+
+# remove everything below this line!! for testing only
+if __name__ == "__main__":
+ xsr = XendStorageRepository()
+ print 'Free Space: %d MB' % (xsr.free_space_bytes()/MB)
+ print "Create Image:",
+ print xsr._create_image_files(10 * MB)
+ print 'Delete all images:'
+ for image_uuid in xsr.list_images():
+ print image_uuid,
+ xsr._destroy_image_files(image_uuid)
+
+ print
diff -r bea3d48576c6 -r 665be23d7fe9
tools/python/xen/xend/XendStorageRepository.py
--- a/tools/python/xen/xend/XendStorageRepository.py Wed Jan 24 14:25:21
2007 +0000
+++ b/tools/python/xen/xend/XendStorageRepository.py Wed Jan 24 15:47:31
2007 +0000
@@ -13,65 +13,28 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
-# Copyright (C) 2006 XenSource Ltd.
+# Copyright (C) 2006, 2007 XenSource Ltd.
#============================================================================
#
-# The default QCOW Xen API Storage Repository
+# Abstract class for XendStorageRepositories
#
-import commands
-import logging
-import os
-import stat
import threading
-import re
import sys
-import struct
-from xen.util import mkdir
-from xen.xend import uuid
from xen.xend.XendError import XendError
from xen.xend.XendVDI import *
-
XEND_STORAGE_NO_MAXIMUM = sys.maxint
-XEND_STORAGE_DIR = "/var/lib/xend/storage/"
-XEND_STORAGE_QCOW_FILENAME = "%s.qcow"
-XEND_STORAGE_VDICFG_FILENAME = "%s.vdi.xml"
-QCOW_CREATE_COMMAND = "/usr/sbin/qcow-create -r %d %s"
-
-MB = 1024 * 1024
-
-log = logging.getLogger("xend.XendStorageRepository")
-
-
-def qcow_virtual_size(qcow_file):
- """Read the first 32 bytes of the QCoW header to determine its size.
-
- See: http://www.gnome.org/~markmc/qcow-image-format.html.
- """
- try:
- qcow_header = open(qcow_file, 'rb').read(32)
- parts = struct.unpack('>IIQIIQ', qcow_header)
- return parts[-1]
- except IOError:
- return -1
class XendStorageRepository:
- """A simple file backed QCOW Storage Repository.
+ """ Base class for Storage Repos. """
- This class exposes the interface to create VDI's via the
- Xen API. The backend is a file-backed QCOW format that is stored
- in XEND_STORAGE_DIR or any that is specified in the constructor.
-
- The actual images are created in the format <uuid>.img and <uuid>.qcow.
- """
-
def __init__(self, uuid,
- sr_type = "qcow_file",
- name_label = "Local",
- name_description = "Xend Storage Repository",
- location = XEND_STORAGE_DIR,
+ sr_type = "unknown",
+ name_label = 'Unknown',
+ name_description = 'Not Implemented',
+ location = '',
storage_max = XEND_STORAGE_NO_MAXIMUM):
"""
@keyword storage_max: Maximum disk space to use in bytes.
@@ -91,303 +54,51 @@ class XendStorageRepository:
self.name_description = name_description
self.images = {}
- self.storage_max = storage_max
- self.storage_free = 0
- self.storage_used = 0
- self.storage_alloc = 0
+ self.physical_size = storage_max
+ self.physical_utilisation = 0
+ self.virtual_allocation = 0
+
+ self.lock = threading.RLock()
- self.lock = threading.RLock()
- self._refresh()
-
- def get_record(self):
+ def get_record(self, transient = True):
retval = {'uuid': self.uuid,
'name_label': self.name_label,
'name_description': self.name_description,
- 'virtual_allocation': self.storage_alloc,
- 'physical_utilisation': self.storage_used,
- 'physical_size': self.storage_max,
+ 'virtual_allocation': self.virtual_allocation,
+ 'physical_utilisation': self.physical_utilisation,
+ 'physical_size': self.physical_size,
'type': self.type,
'location': self.location,
'VDIs': self.images.keys()}
-
- if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
- stfs = os.statvfs(self.location)
- retval['physical_size'] = stfs.f_blocks * stfs.f_frsize
return retval
-
- def _refresh(self):
- """Internal function that refreshes the state of the disk and
- updates the list of images available.
- """
- self.lock.acquire()
- try:
- mkdir.parents(self.location, stat.S_IRWXU)
- # scan the directory and populate self.images
- virtual_alloc = 0
- physical_used = 0
- seen_images = []
- for filename in os.listdir(self.location):
- if filename[-5:] == XEND_STORAGE_QCOW_FILENAME[-5:]:
- image_uuid = filename[:-5]
- seen_images.append(image_uuid)
-
- qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
- cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
- qcow_path = os.path.join(self.location, qcow_file)
- cfg_path = os.path.join(self.location, cfg_file)
-
- phys_size = os.stat(qcow_path).st_size
- virt_size = qcow_virtual_size(qcow_path)
-
- # add this image if we haven't seen it before
- if image_uuid not in self.images:
- vdi = XendQCOWVDI(image_uuid, self.uuid,
- qcow_path, cfg_path,
- virt_size, phys_size)
-
- if cfg_path and os.path.exists(cfg_path):
- try:
- vdi.load_config(cfg_path)
- except:
- log.error('Corrupt VDI configuration file %s' %
- cfg_path)
-
- self.images[image_uuid] = vdi
-
- physical_used += phys_size
- virtual_alloc += virt_size
-
- # remove images that aren't valid
- for image_uuid in self.images.keys():
- if image_uuid not in seen_images:
- try:
- os.unlink(self.images[image_uuid].qcow_path)
- except OSError:
- pass
- del self.images[image_uuid]
-
- self.storage_alloc = virtual_alloc
- self.storage_used = physical_used
-
- # update free storage if we have to track that
- if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
- self.storage_free = self._get_free_space()
- else:
- self.storage_free = self.storage_max - self.storage_alloc
-
- finally:
- self.lock.release()
-
- def _get_free_space(self):
- """Returns the amount of free space in bytes available in the storage
- partition. Note that this may not be used if the storage repository
- is initialised with a maximum size in storage_max.
-
- @rtype: int
- """
- stfs = os.statvfs(self.location)
- return stfs.f_bavail * stfs.f_frsize
-
- def _has_space_available_for(self, size_bytes):
- """Returns whether there is enough space for an image in the
- partition which the storage_dir resides on.
-
- @rtype: bool
- """
- if self.storage_max != XEND_STORAGE_NO_MAXIMUM:
- return self.storage_free > size_bytes
-
- bytes_free = self._get_free_space()
- if size_bytes < bytes_free:
- return True
- return False
-
- def _create_image_files(self, desired_size_bytes):
- """Create an image and return its assigned UUID.
-
- @param desired_size_bytes: Desired image size in bytes
- @type desired_size_bytes: int
- @rtype: string
- @return: uuid
-
- @raises XendError: If an error occurs.
- """
- self.lock.acquire()
- try:
- if not self._has_space_available_for(desired_size_bytes):
- raise XendError("Not enough space")
-
- image_uuid = uuid.createString()
- qcow_path = os.path.join(self.location,
- XEND_STORAGE_QCOW_FILENAME % image_uuid)
-
- if qcow_path and os.path.exists(qcow_path):
- raise XendError("Image with same UUID alreaady exists:" %
- image_uuid)
-
- cmd = QCOW_CREATE_COMMAND % (desired_size_bytes/MB, qcow_path)
- rc, output = commands.getstatusoutput(cmd)
-
- if rc != 0:
- # cleanup the image file
- os.unlink(qcow_path)
- raise XendError("Failed to create QCOW Image: %s" % output)
-
- self._refresh()
- return image_uuid
- finally:
- self.lock.release()
-
- def destroy_image(self, image_uuid):
- """Destroy an image that is managed by this storage repository.
-
- @param image_uuid: Image UUID
- @type image_uuid: String
- @rtype: String
- """
- self.lock.acquire()
- try:
- if image_uuid in self.images:
- # TODO: check if it is being used?
- qcow_path = self.images[image_uuid].qcow_path
- cfg_path = self.images[image_uuid].cfg_path
- try:
- os.unlink(qcow_path)
- if cfg_path and os.path.exists(cfg_path):
- os.unlink(cfg_path)
- except OSError:
- log.exception("Failed to destroy image")
- del self.images[image_uuid]
- return True
- finally:
- self.lock.release()
-
- return False
-
- def list_images(self):
- """ List all the available images by UUID.
-
- @rtype: list of strings.
- @return: list of UUIDs
- """
- self.lock.acquire()
- try:
- return self.images.keys()
- finally:
- self.lock.release()
-
- def free_space_bytes(self):
- """Returns the amount of available space in KB.
- @rtype: int
- """
- self.lock.acquire()
- try:
- return self.storage_free
- finally:
- self.lock.release()
-
- def total_space_bytes(self):
- """Returns the total usable space of the storage repo in KB.
- @rtype: int
- """
- self.lock.acquire()
- try:
- if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
- stfs = os.statvfs(self.location)
- return stfs.f_blocks * stfs.f_frsize
- else:
- return self.storage_max
- finally:
- self.lock.release()
-
- def used_space_bytes(self):
- """Returns the total amount of space used by this storage repository.
- @rtype: int
- """
- self.lock.acquire()
- try:
- return self.storage_used
- finally:
- self.lock.release()
-
- def virtual_allocation(self):
- """Returns the total virtual space allocated within the storage repo.
- @rtype: int
- """
- self.lock.acquire()
- try:
- return self.storage_alloc
- finally:
- self.lock.release()
def is_valid_vdi(self, vdi_uuid):
return (vdi_uuid in self.images)
- def create_image(self, vdi_struct):
- image_uuid = None
- try:
- sector_count = int(vdi_struct.get('virtual_size', 0))
- sector_size = int(vdi_struct.get('sector_size', 1024))
- size_bytes = (sector_count * sector_size)
-
- image_uuid = self._create_image_files(size_bytes)
- image = self.images[image_uuid]
- image_cfg = {
- 'sector_size': sector_size,
- 'virtual_size': sector_count,
- 'type': vdi_struct.get('type', 'system'),
- 'name_label': vdi_struct.get('name_label', ''),
- 'name_description': vdi_struct.get('name_description', ''),
- 'sharable': bool(vdi_struct.get('sharable', False)),
- 'read_only': bool(vdi_struct.get('read_only', False)),
- }
-
- # load in configuration from vdi_struct
- image.load_config_dict(image_cfg)
-
- # save configuration to file
- cfg_filename = XEND_STORAGE_VDICFG_FILENAME % image_uuid
- cfg_path = os.path.join(self.location, cfg_filename)
- image.save_config(cfg_path)
-
- except Exception, e:
- # cleanup before raising exception
- if image_uuid:
- self.destroy_image(image_uuid)
-
- raise
-
- return image_uuid
-
- def xen_api_get_by_name_label(self, label):
+ def get_vdi_by_uuid(self, image_uuid):
self.lock.acquire()
try:
- for image_uuid, val in self.images.items():
- if val.name_label == label:
+ return self.images.get(image_uuid)
+ finally:
+ self.lock.release()
+
+ def get_vdi_by_name_label(self, label):
+ self.lock.acquire()
+ try:
+ for image_uuid, image in self.images.items():
+ if image.name_label == label:
return image_uuid
return None
finally:
self.lock.release()
- def xen_api_get_by_uuid(self, image_uuid):
- self.lock.acquire()
- try:
- return self.images.get(image_uuid)
- finally:
- self.lock.release()
-
+ def get_vdis(self):
+ return self.images.keys()
-# remove everything below this line!!
-if __name__ == "__main__":
- xsr = XendStorageRepository()
- print 'Free Space: %d MB' % (xsr.free_space_bytes()/MB)
- print "Create Image:",
- print xsr._create_image_files(10 * MB)
- print 'Delete all images:'
- for image_uuid in xsr.list_images():
- print image_uuid,
- xsr._destroy_image_files(image_uuid)
+ def create_vdi(self, vdi_struct):
+ raise NotImplementedError()
- print
+ def destroy_vdi(self, vdi_struct):
+ raise NotImplementedError()
diff -r bea3d48576c6 -r 665be23d7fe9 tools/python/xen/xend/XendVDI.py
--- a/tools/python/xen/xend/XendVDI.py Wed Jan 24 14:25:21 2007 +0000
+++ b/tools/python/xen/xend/XendVDI.py Wed Jan 24 15:47:31 2007 +0000
@@ -141,7 +141,7 @@ class XendVDI(AutoSaveObject):
return True
- def get_record(self):
+ def get_record(self, transient = True):
return {'uuid': self.uuid,
'name_label': self.name_label,
'name_description': self.name_description,
@@ -152,12 +152,14 @@ class XendVDI(AutoSaveObject):
'children': [],
'sharable': False,
'readonly': False,
- 'SR': self.sr.get_uuid(),
+ 'SR': self.sr_uuid,
'VBDs': []}
+
+ def get_image_uri(self):
+ raise NotImplementedError()
-class XendQCOWVDI(XendVDI):
-
+class XendQCoWVDI(XendVDI):
def __init__(self, uuid, sr_uuid, qcow_path, cfg_path, vsize, psize):
XendVDI.__init__(self, uuid, sr_uuid)
self.auto_save = False
@@ -168,3 +170,26 @@ class XendQCOWVDI(XendVDI):
self.sector_size = 512
self.auto_save = True
+ def get_image_uri(self):
+ return 'tap:qcow:%s' % self.qcow_path
+
+class XendLocalVDI(XendVDI):
+ def __init__(self, vdi_struct):
+ vdi_uuid = vdi_struct['uuid']
+ sr_uuid = vdi_struct['SR']
+ XendVDI.__init__(self, vdi_uuid, sr_uuid)
+
+ self.auto_save = False
+ self.cfg_path = None
+ self.name_label = vdi_struct.get('name_label','')
+ self.name_description = vdi_struct.get('name_description', '')
+ self.physical_utilisation = 0
+ self.virtual_size = 0
+ self.sector_size = 0
+ self.type = vdi_struct.get('type', '')
+ self.sharable = vdi_struct.get('sharable', False)
+ self.read_only = vdi_struct.get('read_only', False)
+ self.image_uri = vdi_struct.get('uri', 'file:/dev/null')
+
+ def get_image_uri(self):
+ return self.image_uri
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|