WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

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

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [XEND] Updates to SR and VDI implementations
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 02 Nov 2006 22:08:58 +0000
Delivery-date: Thu, 02 Nov 2006 21:40:20 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [XEND] Updates to SR and VDI implementations, Xen patchbot-unstable <=