[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [XEND] Updates to SR and VDI implementations



# HG changeset patch
# User Alastair Tse <atse@xxxxxxxxxxxxx>
# Node ID 91c7ee18c978f7327487b831b9b07428bae80675
# Parent  58521d4b7c7b6fae9fd3f82345d0e8df9e7ba0a1
[XEND] Updates to SR and VDI implementations

* Moved xenapi transport util method, stringify to xen.util.xmlrpclib2
* XenVDI now preserves configuration to an XML-ish file
* Update Xen API's class names to be all lowercase
* Update get_by_label to get_by_name_label and return sets as the API
  expects.
* Add support for VBD creation with a VDI reference.

Signed-off-by: Alastair Tse <atse@xxxxxxxxxxxxx>
---
 tools/python/scripts/xapi.py                   |   67 +++++++-
 tools/python/scripts/xapi.vdicfg.py            |    7 
 tools/python/xen/util/xmlrpclib2.py            |   26 ++-
 tools/python/xen/xend/XendAPI.py               |  206 +++++++++++++++++--------
 tools/python/xen/xend/XendConfig.py            |   18 ++
 tools/python/xen/xend/XendDomainInfo.py        |   27 +++
 tools/python/xen/xend/XendStorageRepository.py |  133 ++++++++++++----
 tools/python/xen/xend/XendVDI.py               |  111 ++++++++++++-
 8 files changed, 477 insertions(+), 118 deletions(-)

diff -r 58521d4b7c7b -r 91c7ee18c978 tools/python/scripts/xapi.py
--- a/tools/python/scripts/xapi.py      Thu Oct 12 18:51:17 2006 +0100
+++ b/tools/python/scripts/xapi.py      Fri Oct 13 15:13:21 2006 +0100
@@ -21,15 +21,23 @@ from pprint import pprint
 from pprint import pprint
 from types import DictType
 
+MB = 1024 * 1024
+
 HOST_INFO_FORMAT = '%-20s: %-50s'
 VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(vcpus_number)-5s'\
-                 ' %(power_state)-12s %(uuid)-32s'
-
+                 ' %(power_state)-12s %(uuid)-36s'
+SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \
+                 '%(type)-10s'
+VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s '\
+                  '%(sector_size)-8s'
 LOGIN = ('atse', 'passwd')
 
 COMMANDS = {
     'host-info': ('', 'Get Xen Host Info'),
+    'sr-list':   ('', 'List all SRs'),
     'vbd-create': ('<domname> <pycfg>', 'Create VBD attached to domname'),
+    'vdi-list'  : ('', 'List all VDI'),
+    'vdi-delete': ('<vdi_uuid>', 'Delete VDI'),
     'vif-create': ('<domname> <pycfg>', 'Create VIF attached to domname'),
 
     'vm-create': ('<pycfg>', 'Create VM with python config'),
@@ -84,8 +92,8 @@ def execute(fn, *args):
 
 def _connect(*args):
     server = ServerProxy('httpu:///var/run/xend/xmlrpc.sock')        
-    session = execute(server.Session.login_with_password, *LOGIN)
-    host = execute(server.Session.get_this_host, session)
+    session = execute(server.session.login_with_password, *LOGIN)
+    host = execute(server.session.get_this_host, session)
     return (server, session)
 
 def _stringify(adict):
@@ -248,8 +256,55 @@ def xapi_vif_create(*args):
     vif_uuid = execute(server.VIF.create, session, cfg)
     print 'Done. (%s)' % vif_uuid
 
-    
-
+def xapi_vdi_list(*args):
+    server, session = _connect()
+    vdis = execute(server.VDI.get_all, session)
+
+    print VDI_LIST_FORMAT % {'name_label': 'VDI Label',
+                             'uuid' : 'UUID',
+                             'virtual_size': 'Sectors',
+                             'sector_size': 'Sector Size'}
+    
+    for vdi in vdis:
+        vdi_struct = execute(server.VDI.get_record, session, vdi)
+        print VDI_LIST_FORMAT % vdi_struct
+
+def xapi_sr_list(*args):
+    server, session = _connect()
+    srs = execute(server.SR.get_all, session)
+    print SR_LIST_FORMAT % {'name_label': 'SR Label',
+                            'uuid' : 'UUID',
+                            'physical_size': 'Size',
+                            'type': 'Type'}
+    for sr in srs:
+        sr_struct = execute(server.SR.get_record, session, sr)
+        sr_struct['physical_size'] = int(sr_struct['physical_size'])/MB
+        print SR_LIST_FORMAT % sr_struct
+
+def xapi_vdi_create(*args):
+    server, session = _connect()
+    cfg = _read_python_cfg(args[0])
+
+    srs = execute(server.SR.get_all, session)
+    sr = srs[0]
+    cfg['SR'] = sr
+
+    size = (cfg['virtual_size'] * cfg['sector_size'])/MB
+    print 'Creating VDI of size: %dMB' % size
+    uuid = execute(server.VDI.create, session, cfg)
+    print 'Done. (%s)' % uuid
+
+def xapi_vdi_delete(*args):
+    server, session = _connect()
+    if len(args) < 1:
+        raise OptionError('Not enough arguments')
+
+    vdi_uuid = args[0]
+    print 'Deleting VDI %s' % vdi_uuid
+    result = execute(server.VDI.destroy, session, vdi_uuid)
+    print 'Done.'
+    
+        
 #
 # Command Line Utils
 #
diff -r 58521d4b7c7b -r 91c7ee18c978 tools/python/xen/util/xmlrpclib2.py
--- a/tools/python/xen/util/xmlrpclib2.py       Thu Oct 12 18:51:17 2006 +0100
+++ b/tools/python/xen/util/xmlrpclib2.py       Fri Oct 13 15:13:21 2006 +0100
@@ -21,8 +21,9 @@ An enhanced XML-RPC client/server interf
 """
 
 import string
-import types
 import fcntl
+from types import *
+    
 
 from httplib import HTTPConnection, HTTP
 from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
@@ -38,6 +39,23 @@ except ImportError:
     # SSHTransport is disabled on Python <2.4, because it uses the subprocess
     # package.
     ssh_enabled = False
+
+#
+# Convert all integers to strings as described in the Xen API
+#
+
+
+def stringify(value):
+    if isinstance(value, IntType) and not isinstance(value, BooleanType):
+        return str(value)
+    elif isinstance(value, DictType):
+        for k, v in value.items():
+            value[k] = stringify(v)
+        return value
+    elif isinstance(value, (TupleType, ListType)):
+        return [stringify(v) for v in value]
+    else:
+        return value
 
 
 # A new ServerProxy that also supports httpu urls.  An http URL comes in the
@@ -91,8 +109,7 @@ class UnixTransport(xmlrpclib.Transport)
 
 # See _marshalled_dispatch below.
 def conv_string(x):
-    if (isinstance(x, types.StringType) or
-        isinstance(x, unicode)):
+    if isinstance(x, StringTypes):
         s = string.replace(x, "'", r"\047")
         exec "s = '" + s + "'"
         return s
@@ -169,8 +186,7 @@ class TCPXMLRPCServer(SocketServer.Threa
             # to transmit the string using Python encoding.
             # Thanks to David Mertz <mertz@xxxxxxxxx> for the trick (buried
             # in xml_pickle.py).
-            if (isinstance(response, types.StringType) or
-                isinstance(response, unicode)):
+            if isinstance(response, StringTypes):
                 response = repr(response)[1:-1]
 
             response = (response,)
diff -r 58521d4b7c7b -r 91c7ee18c978 tools/python/xen/xend/XendAPI.py
--- a/tools/python/xen/xend/XendAPI.py  Thu Oct 12 18:51:17 2006 +0100
+++ b/tools/python/xen/xend/XendAPI.py  Fri Oct 13 15:13:21 2006 +0100
@@ -25,23 +25,10 @@ from xen.xend.XendLogging import log
 from xen.xend.XendLogging import log
 
 from xen.xend.XendAPIConstants import *
-
-from types import *
-
-def _stringify(value):
-    if isinstance(value, IntType) and not isinstance(value, BooleanType):
-        return str(value)
-    elif isinstance(value, DictType):
-        for k, v in value.items():
-            value[k] = _stringify(v)
-        return value
-    elif isinstance(value, (TupleType, ListType)):
-        return [_stringify(v) for v in value]
-    else:
-        return value
-    
+from xen.util.xmlrpclib2 import stringify
+
 def xen_api_success(value):
-    return {"Status": "Success", "Value": _stringify(value)}
+    return {"Status": "Success", "Value": stringify(value)}
 
 def xen_api_success_void():
     """Return success, but caller expects no return value."""
@@ -252,7 +239,7 @@ class XendAPI:
         """
         
         classes = {
-            'Session': (session_required,),
+            'session': (session_required,),
             'host': (valid_host, session_required),
             'host_cpu': (valid_host_cpu, session_required),
             'VM': (valid_vm, session_required),
@@ -346,9 +333,9 @@ class XendAPI:
     # ----------------------------------------------------------------
     # NOTE: Left unwrapped by __init__
 
-    Session_attr_ro = ['this_host', 'this_user']
-    Session_methods = ['logout']
-    # Session_funcs = ['login_with_password']    
+    session_attr_ro = ['this_host', 'this_user']
+    session_methods = ['logout']
+    # session_funcs = ['login_with_password']    
 
     def session_login_with_password(self, username, password):
         try:
@@ -356,7 +343,7 @@ class XendAPI:
             return xen_api_success(session)
         except XendError, e:
             return xen_api_error(XEND_ERROR_AUTHENTICATION_FAILED)
-    session_login_with_password.api = 'Session.login_with_password'
+    session_login_with_password.api = 'session.login_with_password'
 
 
     # object methods
@@ -405,7 +392,7 @@ class XendAPI:
                     'reboot',
                     'shutdown']
     
-    host_funcs = ['get_by_label']
+    host_funcs = ['get_by_name_label']
 
     # attributes
     def host_get_name_label(self, session, host_ref):
@@ -572,7 +559,7 @@ class XendAPI:
                   'suspend',
                   'resume']
     
-    VM_funcs  = ['get_by_label']
+    VM_funcs  = ['get_by_name_label']
 
     # parameters required for _create()
     VM_attr_inst = [
@@ -892,7 +879,8 @@ class XendAPI:
     def vm_get_all(self, session):
         refs = [d.get_uuid() for d in XendDomain.instance().list()]
         return xen_api_success(refs)
-    def vm_get_by_label(self, session, label):
+    
+    def vm_get_by_name_label(self, session, label):
         xendom = XendDomain.instance()
         dom = xendom.domain_lookup_nr(label)
         if dom:
@@ -1022,16 +1010,27 @@ class XendAPI:
     # class methods
     def vbd_create(self, session, vbd_struct):
         xendom = XendDomain.instance()
-        if xendom.is_valid_vm(vbd_struct['VM']):
-            dom = xendom.get_vm_by_uuid(vbd_struct['VM'])
-            try:
+        if not xendom.is_valid_vm(vbd_struct['VM']):
+            return xen_api_error(XEND_ERROR_DOMAIN_INVALID)
+        
+        dom = xendom.get_vm_by_uuid(vbd_struct['VM'])
+        vbd_ref = ''
+        try:
+            if vbd_struct.get('VDI', None):
+                # this is a traditional VBD without VDI and SR 
                 vbd_ref = dom.create_vbd(vbd_struct)
-                xendom.managed_config_save(dom)
-                return xen_api_success(vbd_ref)
-            except XendError:
-                return xen_api_error(XEND_ERROR_TODO)
-        else:
-            return xen_api_error(XEND_ERROR_DOMAIN_INVALID)
+            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)
+                vdi_image_path = vdi_image.image_path
+                vbd_ref = dom.create_vbd_with_vdi(vbd_struct, vdi_image_path)
+        except XendError:
+            return xen_api_todo()
+
+        xendom.managed_config_save(dom)
+        return xen_api_success(vbd_ref)
 
     # attributes (rw)
     def vbd_get_vm(self, session, vbd_ref):
@@ -1118,61 +1117,144 @@ class XendAPI:
     VDI_attr_inst = VDI_attr_ro + VDI_attr_rw
 
     VDI_methods = ['snapshot']
-    VDI_funcs = ['get_by_label']
+    VDI_funcs = ['get_by_name_label']
+    
     def vdi_get_vbds(self, session, vdi_ref):
         return xen_api_todo()
+    
     def vdi_get_physical_utilisation(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.get_physical_utilisation())        
+    
     def vdi_get_sector_size(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.sector_size)        
+    
     def vdi_get_type(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.type)
+    
     def vdi_get_parent(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.parent)        
+    
     def vdi_get_children(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.children)        
+    
     def vdi_get_name_label(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.name_label)
+
     def vdi_get_name_description(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.name_description)
+
     def vdi_get_sr(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        return xen_api_success(sr.uuid)
+
     def vdi_get_virtual_size(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.virtual_size)
+
     def vdi_get_sharable(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.sharable)
+
     def vdi_get_read_only(self, session, vdi_ref):
-        return xen_api_todo()
-    def vdi_get_uuid(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        return xen_api_success(image.sharable)        
+
     def vdi_set_name_label(self, session, vdi_ref, value):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        image.name_label = value
+        return xen_api_success_void()
+
     def vdi_set_name_description(self, session, vdi_ref, value):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        image.name_description = value
+        return xen_api_success_void()
+
     def vdi_set_sr(self, session, vdi_ref, value):
-        return xen_api_todo()
+        return xen_api_error(XEND_ERROR_UNSUPPORTED)
+
     def vdi_set_virtual_size(self, session, vdi_ref, value):
-        return xen_api_todo()
+        return xen_api_error(XEND_ERROR_UNSUPPORTED)
+
     def vdi_set_sharable(self, session, vdi_ref, value):
         return xen_api_todo()
     def vdi_set_read_only(self, session, vdi_ref, value):
         return xen_api_todo()
+
+    # Object Methods
     def vdi_snapshot(self, session, vdi_ref):
         return xen_api_todo()
+    
     def vdi_destroy(self, session, vdi_ref):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        sr.destroy_image(vdi_ref)
+        return xen_api_success_void()
+
     def vdi_to_xml(self, session, vdi_ref):
         return xen_api_todo()
+    
     def vdi_get_record(self, session, vdi_ref):
-        return xen_api_todo()
-    def vdi_create(self, session):
-        return xen_api_todo()
-    def vdi_get_by_uuid(self, session):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        image = sr.xen_api_get_by_uuid(vdi_ref)
+        if image:
+            return xen_api_success({
+                'uuid': vdi_ref,
+                'name_label': image.name_label,
+                'name_description': image.name_description,
+                'SR': sr.uuid,
+                'VBDs': [], # TODO
+                'virtual_size': image.virtual_size,
+                'physical_utilisation': image.physical_utilisation,
+                'sector_size': image.sector_size,
+                'type': image.type,
+                'parent': image.parent,
+                'children': image.children,
+                'sharable': image.sharable,
+                'read_only': image.read_only,
+                })
+
+        return xen_api_error(XEND_ERROR_VDI_INVALID)
+
+    # Class Functions    
+    def vdi_create(self, session, vdi_struct):
+        sr = XendNode.instance().get_sr()
+        sr_ref = vdi_struct['SR']
+        if sr.uuid != sr_ref:
+            return xen_api_error(XEND_ERROR_SR_INVALID)
+
+        vdi_uuid = sr.create_image(vdi_struct)
+        return xen_api_success(vdi_uuid)
+
     def vdi_get_all(self, session):
-        return xen_api_todo()
-    def vdi_get_by_label(self, session):
-        return xen_api_todo()
+        sr = XendNode.instance().get_sr()
+        return xen_api_success(sr.list_images())
+    
+    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_error(XEND_ERROR_VDI_INVALID)
+
 
     # Xen API: Class SR
     # ----------------------------------------------------------------
@@ -1193,14 +1275,14 @@ class XendAPI:
                     'name_description']
     
     SR_methods = ['clone']
-    SR_funcs = ['get_by_label']
+    SR_funcs = ['get_by_name_label']
 
     # Class Functions
     def sr_get_all(self, session):
         sr = XendNode.instance().get_sr()
         return xen_api_success([sr.uuid])
 
-    def sr_get_by_label(self, session, label):
+    def sr_get_by_name_label(self, session, label):
         sr = XendNode.instance().get_sr()
         if sr.name_label != label:
             return xen_api_error(XEND_ERROR_SR_INVALID)
diff -r 58521d4b7c7b -r 91c7ee18c978 tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Thu Oct 12 18:51:17 2006 +0100
+++ b/tools/python/xen/xend/XendConfig.py       Fri Oct 13 15:13:21 2006 +0100
@@ -566,7 +566,7 @@ class XendConfig(dict):
         for dev_uuid, (dev_type, dev_info) in cfg['device'].items():
             if dev_type == 'vif':
                 cfg['vif_refs'].append(dev_uuid)
-            elif dev_type == 'vbd':
+            elif dev_type in ('vbd','tap'):
                 cfg['vbd_refs'].append(dev_uuid)
                 
         return cfg
@@ -771,6 +771,8 @@ class XendConfig(dict):
             self['device'][dev_uuid] = (dev_type, dev_info)
             if dev_type in ('vif', 'vbd'):
                 self['%s_refs' % dev_type].append(dev_uuid)
+            elif dev_type in ('tap',):
+                self['vbd_refs'].append(dev_uuid)
             return dev_uuid
 
         if cfg_xenapi:
@@ -805,7 +807,21 @@ class XendConfig(dict):
                 self['device'][dev_uuid] = (dev_type, dev_info)
                 self['vbd_refs'].append(dev_uuid)                
                 return dev_uuid
+            
+            elif dev_type == 'tap':
+                dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
+                dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
                 
+                if cfg_xenapi.get('mode') == 'RW':
+                    dev_info['mode'] = 'w'
+                else:
+                    dev_info['mode'] = 'r'
+
+                dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
+                dev_info['uuid'] = dev_uuid
+                self['device'][dev_uuid] = (dev_type, dev_info)
+                self['vbd_refs'].append(dev_uuid)                
+                return dev_uuid                
                 
         return ''
 
diff -r 58521d4b7c7b -r 91c7ee18c978 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Thu Oct 12 18:51:17 2006 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py   Fri Oct 13 15:13:21 2006 +0100
@@ -1826,8 +1826,33 @@ class XendDomainInfo:
 
         return dev_uuid
 
+    def create_vbd_with_vdi(self, xenapi_vbd, vdi_image_path):
+        """Create a VBD using a VDI from XendStorageRepository.
+
+        @param xenapi_vbd: vbd struct from the Xen API
+        @param vdi_image_path: VDI UUID
+        @rtype: string
+        @return: uuid of the device
+        """
+        xenapi_vbd['image'] = vdi_image_path
+        dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
+        if not dev_uuid:
+            raise XendError('Failed to create device')
+
+        if self.state in (XEN_API_VM_POWER_STATE_RUNNING,):
+            sxpr = self.info.device_sxpr(dev_uuid)
+            devid = self.getDeviceController('tap').createDevice(sxpr)
+            raise XendError("Device creation failed")
+
+        return dev_uuid
+
     def create_vif(self, xenapi_vif):
-        
+        """Create VIF device from the passed struct in Xen API format.
+
+        @param xenapi_vif: Xen API VIF Struct.
+        @rtype: string
+        @return: UUID
+        """
         dev_uuid = self.info.device_add('vif', cfg_xenapi = xenapi_vif)
         if not dev_uuid:
             raise XendError('Failed to create device')
diff -r 58521d4b7c7b -r 91c7ee18c978 
tools/python/xen/xend/XendStorageRepository.py
--- a/tools/python/xen/xend/XendStorageRepository.py    Thu Oct 12 18:51:17 
2006 +0100
+++ b/tools/python/xen/xend/XendStorageRepository.py    Fri Oct 13 15:13:21 
2006 +0100
@@ -31,7 +31,8 @@ XEND_STORAGE_DIR = "/var/lib/xend/storag
 XEND_STORAGE_DIR = "/var/lib/xend/storage/"
 XEND_STORAGE_QCOW_FILENAME = "%s.qcow"
 XEND_STORAGE_IMG_FILENAME = "%s.img"
-DF_COMMAND = "df -kl"
+XEND_STORAGE_VDICFG_FILENAME = "%s.vdi.xml"
+DF_COMMAND = "df -lP"
 QCOW_CREATE_COMMAND = "/usr/sbin/qcow-create %d %s %s"
 
 KB = 1024
@@ -55,7 +56,7 @@ class XendStorageRepository:
         """
         @keyword storage_dir: Where the images will be stored.
         @type    storage_dir: string
-        @keyword storage_max: Maximum disk space to use in KB.
+        @keyword storage_max: Maximum disk space to use in bytes.
         @type    storage_max: int
 
         @ivar    storage_free: storage space free for this repository
@@ -82,7 +83,7 @@ class XendStorageRepository:
     def _sr_uuid(self):
         uuid_file = os.path.join(XEND_STORAGE_DIR, 'uuid')
         try:
-            if os.path.exists(uuid_file):
+            if uuid_file and os.path.exists(uuid_file):
                 return open(uuid_file, 'r').read().strip()
             else:
                 new_uuid = uuid.createString()
@@ -114,16 +115,25 @@ class XendStorageRepository:
                     if image_uuid not in self.images:
                         image_file = XEND_STORAGE_IMG_FILENAME % image_uuid
                         qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
-                        image_path = os.path.join(XEND_STORAGE_DIR,
-                                                  image_file)
+                        cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
+                        
+                        image_path = os.path.join(XEND_STORAGE_DIR,image_file)
                         qcow_path = os.path.join(XEND_STORAGE_DIR, qcow_file)
-                        image_size_kb = (os.stat(image_path).st_size)/1024
+                        cfg_path = os.path.join(XEND_STORAGE_DIR, cfg_file)
+
+                        qcow_size = os.stat(qcow_path).st_size
+                        image_size = os.stat(image_path).st_size
 
                         vdi = XendQCOWVDI(image_uuid, self.uuid,
-                                          qcow_path, image_path,
-                                          image_size_kb, image_size_kb)
+                                          qcow_path, image_path, cfg_path,
+                                          image_size,
+                                          qcow_size + image_size)
+                        
+                        if cfg_path and os.path.exists(cfg_path):
+                            vdi.load_config(cfg_path)
+                        
                         self.images[image_uuid] = vdi
-                        total_used += image_size_kb
+                        total_used += image_size
 
             # remove images that aren't valid
             for image_uuid in self.images.keys():
@@ -147,7 +157,7 @@ class XendStorageRepository:
     def _get_df(self):
         """Returns the output of 'df' in a dictionary where the keys
         are the Linux device numbers, and the values are it's corresponding
-        free space in KB.
+        free space in bytes
 
         @rtype: dictionary
         """
@@ -162,7 +172,7 @@ class XendStorageRepository:
         return devnum_free
 
     def _get_free_space(self):
-        """Returns the amount of free space in KB available in the storage
+        """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.
 
@@ -175,7 +185,7 @@ class XendStorageRepository:
         raise DeviceInvalidError("Device not found for storage path: %s" %
                                  self.storage_dir)
 
-    def _has_space_available_for(self, size_kb):
+    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.
 
@@ -184,15 +194,15 @@ class XendStorageRepository:
         if self.storage_max != -1:
             return self.storage_free
         
-        kb_free = self._get_free_space()
-        try:
-            if size_kb < kb_free:
+        bytes_free = self._get_free_space()
+        try:
+            if size_bytes < bytes_free:
                 return True
         except DeviceInvalidError:
             pass
         return False
 
-    def create_image(self, desired_size_kb):
+    def _create_image_files(self, desired_size_bytes):
         """Create an image and return its assigned UUID.
 
         @param desired_size_kb: Desired image size in KB.
@@ -204,23 +214,28 @@ class XendStorageRepository:
         """
         self.lock.acquire()
         try:
-            if not self._has_space_available_for(desired_size_kb):
+            if not self._has_space_available_for(desired_size_bytes):
                 raise XendError("Not enough space")
 
             image_uuid = uuid.createString()
             # create file based image
             image_path = os.path.join(XEND_STORAGE_DIR,
                                       XEND_STORAGE_IMG_FILENAME % image_uuid)
-            block = '\x00' * 1024
+            
+            if image_path and os.path.exists(image_path):
+                raise XendError("Image with same UUID alreaady exists:" %
+                                image_uuid)
+            
+            block = '\x00' * KB
             img = open(image_path, 'w')
-            for i in range(desired_size_kb):
+            for i in range(desired_size_bytes/KB):
                 img.write(block)
             img.close()
             
             # TODO: create qcow image
             qcow_path = os.path.join(XEND_STORAGE_DIR,
                                      XEND_STORAGE_QCOW_FILENAME % image_uuid)
-            cmd = QCOW_CREATE_COMMAND % (desired_size_kb/1024,
+            cmd = QCOW_CREATE_COMMAND % (desired_size_bytes/MB,
                                          qcow_path, image_path)
 
             rc, output = commands.getstatusoutput(cmd)
@@ -233,7 +248,7 @@ class XendStorageRepository:
             return image_uuid
         finally:
             self.lock.release()
-        
+
     def destroy_image(self, image_uuid):
         """Destroy an image that is managed by this storage repository.
 
@@ -247,9 +262,12 @@ class XendStorageRepository:
                 # TODO: check if it is being used?
                 qcow_path = self.images[image_uuid].qcow_path
                 image_path = self.images[image_uuid].image_path
+                cfg_path = self.images[image_uuid].cfg_path
                 try:
                     os.unlink(qcow_path)
                     os.unlink(image_path)
+                    if cfg_path and os.path.exists(cfg_path):
+                        os.unlink(cfg_path)
                 except OSError:
                     # TODO: log warning
                     pass
@@ -272,7 +290,7 @@ class XendStorageRepository:
         finally:
             self.lock.release()
 
-    def free_space_kb(self):
+    def free_space_bytes(self):
         """Returns the amount of available space in KB.
         @rtype: int
         """
@@ -282,7 +300,7 @@ class XendStorageRepository:
         finally:
             self.lock.release()
             
-    def total_space_kb(self):
+    def total_space_bytes(self):
         """Returns the total usable space of the storage repo in KB.
         @rtype: int
         """
@@ -295,7 +313,7 @@ class XendStorageRepository:
         finally:
             self.lock.release()
             
-    def used_space_kb(self):
+    def used_space_bytes(self):
         """Returns the total amount of space used by this storage repository.
         @rtype: int
         """
@@ -308,25 +326,72 @@ class XendStorageRepository:
         finally:
             self.lock.release()
 
-    def used_space_bytes(self):
-        return self.used_space_kb() * KB
-    def free_space_bytes(self):
-        return self.free_space_kb() * KB
-    def total_space_bytes(self):
-        return self.total_space_kb() * KB
-
     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(XEND_STORAGE_DIR, 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_label(self, label):
+        self.lock.acquire()
+        try:
+            for image_uuid, val in self.images.values():
+                if val.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()        
+    
 
 # remove everything below this line!!
 if __name__ == "__main__":
     xsr = XendStorageRepository()
-    print 'Free Space: %d MB' % (xsr.free_space_kb()/1024)
+    print 'Free Space: %d MB' % (xsr.free_space_bytes()/MB)
     print "Create Image:",
-    print xsr.create_image(10 * 1024)
+    print xsr._create_image_files(10 * MB)
     print 'Delete all images:'
     for image_uuid in xsr.list_images():
         print image_uuid,
-        xsr.destroy_image(image_uuid)
+        xsr._destroy_image_files(image_uuid)
 
     print
diff -r 58521d4b7c7b -r 91c7ee18c978 tools/python/xen/xend/XendVDI.py
--- a/tools/python/xen/xend/XendVDI.py  Thu Oct 12 18:51:17 2006 +0100
+++ b/tools/python/xen/xend/XendVDI.py  Fri Oct 13 15:13:21 2006 +0100
@@ -19,26 +19,119 @@
 # Representation of a Xen API VDI
 #
 
+import os
+
+from xen.util.xmlrpclib2 import stringify
+from xmlrpclib import dumps, loads
+
 KB = 1024
 MB = 1024 * 1024
 
 class XendVDI:
+    """Generic Xen API compatible VDI representation.
+
+    @cvar SAVED_CFG: list of configuration attributes to save.
+    @cvar SAVED_CFG_INT: list of configurations that should be ints.
+    """
+    
+    SAVED_CFG = ['name_label',
+                 'name_description',
+                 'sector_size',
+                 'virtual_size',
+                 'physical_utilisation',
+                 'parent',
+                 'children',
+                 'sharable',
+                 'read_only']
+
+    SAVED_CFG_INT = ['sector_size', 'virtual_size', 'physical_utilisation']
+    
     def __init__(self, uuid, sr_uuid):
         self.uuid = uuid
         self.sr_uuid = sr_uuid
+        self.name_label = ""
+        self.name_description = ""
+        self.sector_size = 1024
+        self.virtual_size = 0
+        self.physical_utilisation = 0
+        self.parent = None
+        self.children = []
+        self.sharable = False
+        self.read_only = False
+        self.type = "system"
+
+        self.cfg_path = None
+
+    def load_config_dict(self, cfg):
+        """Loads configuration into the object from a dict.
+
+        @param cfg: configuration dict
+        @type  cfg: dict
+        """
+        for key in self.SAVED_CFG:
+            if key in cfg:
+                if key in self.SAVED_CFG_INT:
+                    setattr(self, key, int(cfg[key]))
+                else:
+                    setattr(self, key, cfg[key])
+
+    def load_config(self, cfg_path):
+        """Loads configuration from an XMLRPC parameter format.
+
+        @param cfg_path: configuration file path
+        @type  cfg_path: type
+        @rtype: bool
+        @return: Successful or not.
+        """
+        try:
+            cfg, _ = loads(open(cfg_path).read())
+            cfg = cfg[0]
+            self.load_config_dict(cfg)
+            self.cfg_path = cfg_path
+        except IOError, e:
+            return False
+        
+        return True
+
+    def save_config(self, cfg_path = None):
+        """Saves configuration at give path in XMLRPC parameter format.
+
+        If cfg_path is not give, it defaults to the where the VDI
+        configuration as loaded if it load_config was called.
+
+        @keyword cfg_path: optional configuration file path
+        @rtype: bool
+        @return: Successful or not.
+        """
+        try:
+            if not cfg_path and not self.cfg_path:
+                return False
+
+            if not cfg_path:
+                cfg_path = self.cfg_path
+                
+            cfg = {}
+            for key in self.SAVED_CFG:
+                try:
+                    cfg[key] = getattr(self, key)
+                except AttributeError:
+                    pass
+            open(cfg_path, 'w').write(dumps((stringify(cfg),),
+                                            allow_none = True))
+        except IOError, e:
+            return False
+
+        return True
 
 class XendQCOWVDI(XendVDI):
-    vdi_type = "system"
 
-    def __init__(self, uuid, sr_uuid, qcow_path, image_path, vsize, psize):
+    def __init__(self, uuid, sr_uuid, qcow_path, image_path, cfg_path,
+                 vsize, psize):
         XendVDI.__init__(self, uuid, sr_uuid)
         self.qcow_path = qcow_path
         self.image_path = image_path
-        self.vsize = vsize
-        self.psize = psize
+        self.cfg_path = cfg_path
+        self.physical_utilisation = psize
+        self.virtual_size = vsize
+        self.sector_size = 1
 
-    def get_physical_utilisation(self):
-        return self.psize * KB
-
-    def get_virtual_size(self):
-        return self.vsize * KB
diff -r 58521d4b7c7b -r 91c7ee18c978 tools/python/scripts/xapi.vdicfg.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/scripts/xapi.vdicfg.py       Fri Oct 13 15:13:21 2006 +0100
@@ -0,0 +1,7 @@
+name_label = 'VDI 1'
+name_description = ''
+virtual_size = 10 * 1024
+sector_size = 1024
+type = 'system'
+sharable = False
+read_only = False

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.