ia64/xen-unstable

changeset 13184:765ada5f74cc

Plumb the new PIF and network implementations in through the XendAPI class.
Use the new stateful records to save host, SR, network, and PIF configuration.
Add extra functionality to the SR class, to calculate capacities et al.

By Alastair Tse <atse@xensource.com>.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Mon Dec 25 15:04:28 2006 +0000 (2006-12-25)
parents 4fbefd9cb85e
children bd10d08598b0
files tools/python/xen/xend/XendAPI.py tools/python/xen/xend/XendNode.py tools/python/xen/xend/XendStorageRepository.py
line diff
     1.1 --- a/tools/python/xen/xend/XendAPI.py	Mon Dec 25 14:59:11 2006 +0000
     1.2 +++ b/tools/python/xen/xend/XendAPI.py	Mon Dec 25 15:04:28 2006 +0000
     1.3 @@ -266,6 +266,29 @@ def valid_sr(func):
     1.4  
     1.5      return check_sr_ref
     1.6  
     1.7 +
     1.8 +def valid_pif(func):
     1.9 +    """Decorator to verify if sr_ref is valid before calling
    1.10 +    method.
    1.11 +
    1.12 +    @param func: function with params: (self, session, sr_ref)
    1.13 +    @rtype: callable object
    1.14 +    """
    1.15 +    def check_pif_ref(self, session, pif_ref, *args, **kwargs):
    1.16 +        xennode = XendNode.instance()
    1.17 +        if type(pif_ref) == type(str()) and pif_ref in xennode.pifs:
    1.18 +            return func(self, session, pif_ref, *args, **kwargs)
    1.19 +        else:
    1.20 +            return xen_api_error(['PIF_HANDLE_INVALID', pif_ref])
    1.21 +
    1.22 +    # make sure we keep the 'api' attribute
    1.23 +    if hasattr(func, 'api'):
    1.24 +        check_pif_ref.api = func.api
    1.25 +        
    1.26 +    return check_pif_ref
    1.27 +
    1.28 +
    1.29 +
    1.30  # -----------------------------
    1.31  # Bridge to Legacy XM API calls
    1.32  # -----------------------------
    1.33 @@ -477,16 +500,81 @@ class XendAPI:
    1.34  
    1.35      # Xen API: Class Network
    1.36      # ----------------------------------------------------------------
    1.37 -    # TODO: NOT IMPLEMENTED
    1.38  
    1.39 -    Network_attr_ro = ['VIFs']
    1.40 +    Network_attr_ro = ['VIFs', 'PIFs']
    1.41      Network_attr_rw = ['name_label',
    1.42                         'name_description',
    1.43 -                       'NIC',
    1.44 -                       'VLAN',
    1.45                         'default_gateway',
    1.46                         'default_netmask']
    1.47  
    1.48 +    # Xen API: Class PIF
    1.49 +    # ----------------------------------------------------------------
    1.50 +
    1.51 +    PIF_attr_ro = ['io_read_kbs',
    1.52 +                   'io_write_kbs']
    1.53 +    PIF_attr_rw = ['name',
    1.54 +                   'network',
    1.55 +                   'host',
    1.56 +                   'MAC',
    1.57 +                   'MTU',
    1.58 +                   'VLAN']
    1.59 +
    1.60 +    PIF_attr_inst = PIF_attr_rw
    1.61 +
    1.62 +    # object methods
    1.63 +    def PIF_get_record(self, session, pif_ref):
    1.64 +        node = XendNode.instance()
    1.65 +        return xen_api_success(node.pifs[pif_ref].get_record())
    1.66 +
    1.67 +    def PIF_get_all(self, session):
    1.68 +        return xen_api_success(XendNode.instance().pifs.keys())
    1.69 +
    1.70 +    def PIF_set_name(self, session, pif_ref, name):
    1.71 +        node = XendNode.instance()
    1.72 +        pif = node.pifs.get(pif_ref)
    1.73 +        if pif:
    1.74 +            pif.set_name(name)
    1.75 +        return xen_api_void()        
    1.76 +
    1.77 +    def PIF_set_mac(self, session, pif_ref, mac):
    1.78 +        node = XendNode.instance()
    1.79 +        pif = node.pifs.get(pif_ref)
    1.80 +        if pif:
    1.81 +            pif.set_mac(mac)
    1.82 +        return xen_api_void()
    1.83 +
    1.84 +    def PIF_set_mtu(self, session, pif_ref, mtu):
    1.85 +        node = XendNode.instance()
    1.86 +        pif = node.pifs.get(pif_ref)
    1.87 +        if pif:
    1.88 +            pif.set_mtu(mtu)
    1.89 +        return xen_api_void()    
    1.90 +
    1.91 +    def PIF_get_mac(self, session, pif_ref):
    1.92 +        node = XendNode.instance()
    1.93 +        return xen_api_success(node.pifs[pif_ref].get_mac())
    1.94 +
    1.95 +    def PIF_get_mtu(self, session, pif_ref):
    1.96 +        node = XendNode.instance()
    1.97 +        return xen_api_success(node.pifs[pif_ref].get_mtu())
    1.98 +
    1.99 +    def PIF_get_vlan(self, session, pif_ref):
   1.100 +        node = XendNode.instance()
   1.101 +        return xen_api_success(node.pifs[pif_ref].get_vlan())
   1.102 +
   1.103 +    def PIF_get_name(self, session, pif_ref):
   1.104 +        node = XendNode.instance()
   1.105 +        return xen_api_success(node.pifs[pif_ref].get_name())
   1.106 +
   1.107 +    def PIF_get_io_read_kbs(self, session, pif_ref):
   1.108 +        node = XendNode.instance()
   1.109 +        return xen_api_success(node.pifs[pif_ref].get_io_read_kbs())
   1.110 +
   1.111 +    def PIF_get_io_write_kbs(self, session, pif_ref):
   1.112 +        node = XendNode.instance()
   1.113 +        return xen_api_success(node.pifs[pif_ref].get_io_write_kbs())    
   1.114 +    
   1.115 +
   1.116      # Xen API: Class VM
   1.117      # ----------------------------------------------------------------        
   1.118  
   1.119 @@ -1189,9 +1277,16 @@ class XendAPI:
   1.120          return xen_api_error(XEND_ERROR_UNSUPPORTED)
   1.121  
   1.122      def VDI_set_sharable(self, session, vdi_ref, value):
   1.123 -        return xen_api_todo()
   1.124 +        sr = XendNode.instance().get_sr()
   1.125 +        image = sr.xen_api_get_by_uuid(vdi_ref)
   1.126 +        image.sharable = bool(value)
   1.127 +        return xen_api_success_void()
   1.128 +    
   1.129      def VDI_set_read_only(self, session, vdi_ref, value):
   1.130 -        return xen_api_todo()
   1.131 +        sr = XendNode.instance().get_sr()
   1.132 +        image = sr.xen_api_get_by_uuid(vdi_ref)
   1.133 +        image.read_only = bool(value)
   1.134 +        return xen_api_success_void()
   1.135  
   1.136      # Object Methods
   1.137      def VDI_snapshot(self, session, vdi_ref):
   1.138 @@ -1383,17 +1478,7 @@ class XendAPI:
   1.139      
   1.140      def SR_get_record(self, session, sr_ref):
   1.141          sr = XendNode.instance().get_sr()
   1.142 -        return xen_api_success({
   1.143 -            'uuid': sr.uuid,
   1.144 -            'name_label': sr.name_label,
   1.145 -            'name_description': sr.name_description,
   1.146 -            'VDIs': sr.list_images(),
   1.147 -            'virtual_allocation': sr.used_space_bytes(),
   1.148 -            'physical_utilisation': sr.used_space_bytes(),
   1.149 -            'physical_size': sr.total_space_bytes(),
   1.150 -            'type': sr.type,
   1.151 -            'location': sr.location
   1.152 -            })
   1.153 +        return xen_api_success(sr.get_record())
   1.154  
   1.155      # Attribute acceess
   1.156      def SR_get_VDIs(self, session, sr_ref):
   1.157 @@ -1431,11 +1516,13 @@ class XendAPI:
   1.158      def SR_set_name_label(self, session, sr_ref, value):
   1.159          sr = XendNode.instance().get_sr()
   1.160          sr.name_label = value
   1.161 +        XendNode.instance().save()
   1.162          return xen_api_success_void()
   1.163      
   1.164      def SR_set_name_description(self, session, sr_ref, value):
   1.165          sr = XendNode.instance().get_sr()
   1.166          sr.name_description = value
   1.167 +        XendNode.instance().save()        
   1.168          return xen_api_success_void()
   1.169  
   1.170  
   1.171 @@ -1454,7 +1541,8 @@ def _decorate():
   1.172          'VIF': (valid_vif, session_required, catch_typeerror),
   1.173          'VDI': (valid_vdi, session_required, catch_typeerror),
   1.174          'VTPM':(valid_vtpm, session_required, catch_typeerror),
   1.175 -        'SR':  (valid_sr, session_required, catch_typeerror)}
   1.176 +        'SR':  (valid_sr, session_required, catch_typeerror),
   1.177 +        'PIF': (valid_pif, session_required, catch_typeerror)}
   1.178  
   1.179      # Cheat methods
   1.180      # -------------
     2.1 --- a/tools/python/xen/xend/XendNode.py	Mon Dec 25 14:59:11 2006 +0000
     2.2 +++ b/tools/python/xen/xend/XendNode.py	Mon Dec 25 15:04:28 2006 +0000
     2.3 @@ -21,32 +21,128 @@ import socket
     2.4  import xen.lowlevel.xc
     2.5  from xen.xend import uuid
     2.6  from xen.xend.XendError import XendError
     2.7 +from xen.xend.XendRoot import instance as xendroot
     2.8  from xen.xend.XendStorageRepository import XendStorageRepository
     2.9 +from xen.xend.XendLogging import log
    2.10 +from xen.xend.XendPIF import *
    2.11 +from xen.xend.XendNetwork import *
    2.12 +from xen.xend.XendStateStore import XendStateStore
    2.13  
    2.14  class XendNode:
    2.15      """XendNode - Represents a Domain 0 Host."""
    2.16      
    2.17      def __init__(self):
    2.18 +        """Initalises the state of all host specific objects such as
    2.19 +
    2.20 +        * Host
    2.21 +        * Host_CPU
    2.22 +        * PIF
    2.23 +        * Network
    2.24 +        * Storage Repository
    2.25 +        """
    2.26 +        
    2.27          self.xc = xen.lowlevel.xc.xc()
    2.28 -        self.uuid = uuid.createString()
    2.29 -        self.cpus = {}
    2.30 -        self.name = socket.gethostname()
    2.31 -        self.desc = ""
    2.32 -        self.sr = XendStorageRepository()
    2.33 -        
    2.34 +        self.state_store = XendStateStore(xendroot().get_xend_state_path())
    2.35 +
    2.36 +        # load host state from XML file
    2.37 +        saved_host = self.state_store.load_state('host')
    2.38 +        if saved_host and len(saved_host.keys()) == 1:
    2.39 +            self.uuid = saved_host.keys()[0]
    2.40 +            host = saved_host[self.uuid]
    2.41 +            self.name = host.get('name_label', socket.gethostname())
    2.42 +            self.desc = host.get('name_description', '')
    2.43 +            self.cpus = {}
    2.44 +        else:
    2.45 +            self.uuid = uuid.createString()
    2.46 +            self.name = socket.gethostname()
    2.47 +            self.desc = ''
    2.48 +            self.cpus = {}
    2.49 +            
    2.50 +        # load CPU UUIDs
    2.51 +        saved_cpus = self.state_store.load_state('cpu')
    2.52 +        for cpu_uuid, cpu in saved_cpus.items():
    2.53 +            self.cpus[cpu_uuid] = cpu
    2.54 +
    2.55 +        # verify we have enough cpus here
    2.56          physinfo = self.physinfo_dict()
    2.57          cpu_count = physinfo['nr_cpus']
    2.58          cpu_features = physinfo['hw_caps']
    2.59 -        
    2.60 -        for i in range(cpu_count):
    2.61 -            # construct uuid by appending extra bit on the host.
    2.62 -            # since CPUs belong to a host.
    2.63 -            cpu_uuid = self.uuid + '-%04d' % i
    2.64 -            cpu_info = {'uuid': cpu_uuid,
    2.65 -                        'host': self.uuid,
    2.66 -                        'number': i,
    2.67 -                        'features': cpu_features}
    2.68 -            self.cpus[cpu_uuid] = cpu_info
    2.69 +
    2.70 +        # If the number of CPUs don't match, we should just reinitialise 
    2.71 +        # the CPU UUIDs.
    2.72 +        if cpu_count != len(self.cpus):
    2.73 +            self.cpus = {}
    2.74 +            for i in range(cpu_count):
    2.75 +                cpu_uuid = uuid.createString()
    2.76 +                cpu_info = {'uuid': cpu_uuid,
    2.77 +                            'host': self.uuid,
    2.78 +                            'number': i,
    2.79 +                            'features': cpu_features}
    2.80 +                self.cpus[cpu_uuid] = cpu_info
    2.81 +
    2.82 +        self.pifs = {}
    2.83 +        self.networks = {}
    2.84 +
    2.85 +        # initialise PIFs
    2.86 +        saved_pifs = self.state_store.load_state('pif')
    2.87 +        if saved_pifs:
    2.88 +            for pif_uuid, pif in saved_pifs.items():
    2.89 +                self.pifs[pif_uuid] = XendPIF(pif_uuid,
    2.90 +                                              pif['name'],
    2.91 +                                              pif['MTU'],
    2.92 +                                              pif['MAC'])
    2.93 +        else:
    2.94 +            for name, mtu, mac in linux_get_phy_ifaces():
    2.95 +                pif_uuid = uuid.createString()
    2.96 +                pif = XendPIF(pif_uuid, name, mtu, mac)
    2.97 +                self.pifs[pif_uuid] = pif
    2.98 +
    2.99 +        # initialise networks
   2.100 +        saved_networks = self.state_store.load_state('network')
   2.101 +        if saved_networks:
   2.102 +            for net_uuid, network in saved_networks.items():
   2.103 +                self.networks[net_uuid] = XendNetwork(net_uuid,
   2.104 +                                network.get('name_label'),
   2.105 +                                network.get('name_description', ''),
   2.106 +                                network.get('default_gateway', ''),
   2.107 +                                network.get('default_netmask', ''))
   2.108 +                
   2.109 +                for pif_uuid in network.get('PIFs', {}).keys():
   2.110 +                    pif = self.pifs.get(pif_uuid)
   2.111 +                    if pif:
   2.112 +                        self.networks.pifs[pif_uuid] = pif
   2.113 +        else:
   2.114 +            gateway, netmask = linux_get_default_network()
   2.115 +            net_uuid = uuid.createString()
   2.116 +            net = XendNetwork(net_uuid, 'net0', '', gateway, netmask)
   2.117 +            self.networks[net_uuid] = net
   2.118 +
   2.119 +        # initialise storage
   2.120 +        saved_sr = self.state_store.load_state('sr')
   2.121 +        if saved_sr and len(saved_sr) == 1:
   2.122 +            sr_uuid = saved_sr.keys()[0]
   2.123 +            self.sr = XendStorageRepository(sr_uuid)
   2.124 +        else:
   2.125 +            sr_uuid = uuid.createString()
   2.126 +            self.sr = XendStorageRepository(sr_uuid)
   2.127 +        self.save()
   2.128 +
   2.129 +    def save(self):
   2.130 +        # save state
   2.131 +        host_record = {self.uuid: {'name_label':self.name,
   2.132 +                                   'name_description':self.desc}}
   2.133 +        self.state_store.save_state('host',host_record)
   2.134 +        self.state_store.save_state('cpu', self.cpus)
   2.135 +        pif_records = dict([(k, v.get_record())
   2.136 +                            for k, v in self.pifs.items()])
   2.137 +        self.state_store.save_state('pif', pif_records)
   2.138 +        net_records = dict([(k, v.get_record())
   2.139 +                            for k, v in self.networks.items()])
   2.140 +        self.state_store.save_state('network', net_records)
   2.141 +
   2.142 +
   2.143 +        sr_record = {self.sr.uuid: self.sr.get_record()}
   2.144 +        self.state_store.save_state('sr', sr_record)
   2.145  
   2.146      def shutdown(self):
   2.147          return 0
   2.148 @@ -56,7 +152,8 @@ class XendNode:
   2.149  
   2.150      def notify(self, _):
   2.151          return 0
   2.152 -    
   2.153 +
   2.154 +        
   2.155      #
   2.156      # Ref validation
   2.157      #
   2.158 @@ -100,6 +197,9 @@ class XendNode:
   2.159      def set_description(self, new_desc):
   2.160          self.desc = new_desc
   2.161  
   2.162 +    def get_uuid(self):
   2.163 +        return self.uuid
   2.164 +
   2.165      #
   2.166      # Host CPU Functions
   2.167      #
     3.1 --- a/tools/python/xen/xend/XendStorageRepository.py	Mon Dec 25 14:59:11 2006 +0000
     3.2 +++ b/tools/python/xen/xend/XendStorageRepository.py	Mon Dec 25 15:04:28 2006 +0000
     3.3 @@ -24,13 +24,17 @@ import logging
     3.4  import os
     3.5  import stat
     3.6  import threading
     3.7 +import re
     3.8 +import sys
     3.9 +import struct
    3.10  
    3.11  from xen.util import mkdir
    3.12  from xen.xend import uuid
    3.13  from xen.xend.XendError import XendError
    3.14  from xen.xend.XendVDI import *
    3.15  
    3.16 -XEND_STORAGE_MAX_IGNORE = -1
    3.17 +
    3.18 +XEND_STORAGE_NO_MAXIMUM = sys.maxint
    3.19  XEND_STORAGE_DIR = "/var/lib/xend/storage/"
    3.20  XEND_STORAGE_QCOW_FILENAME = "%s.qcow"
    3.21  XEND_STORAGE_VDICFG_FILENAME = "%s.vdi.xml"
    3.22 @@ -41,8 +45,17 @@ MB = 1024 * 1024
    3.23  log = logging.getLogger("xend.XendStorageRepository")
    3.24  
    3.25  
    3.26 -class DeviceInvalidError(Exception):
    3.27 -    pass
    3.28 +def qcow_virtual_size(qcow_file):
    3.29 +    """Read the first 32 bytes of the QCoW header to determine its size.
    3.30 +
    3.31 +    See: http://www.gnome.org/~markmc/qcow-image-format.html.
    3.32 +    """
    3.33 +    try:
    3.34 +        qcow_header = open(qcow_file, 'rb').read(32)
    3.35 +        parts = struct.unpack('>IIQIIQ', qcow_header)
    3.36 +        return parts[-1]
    3.37 +    except IOError:
    3.38 +        return -1
    3.39  
    3.40  class XendStorageRepository:
    3.41      """A simple file backed QCOW Storage Repository.
    3.42 @@ -54,11 +67,13 @@ class XendStorageRepository:
    3.43      The actual images are created in the format <uuid>.img and <uuid>.qcow.
    3.44      """
    3.45      
    3.46 -    def __init__(self, storage_dir = XEND_STORAGE_DIR,
    3.47 -                 storage_max = XEND_STORAGE_MAX_IGNORE):
    3.48 +    def __init__(self, uuid,
    3.49 +                 sr_type = "qcow_file",
    3.50 +                 name_label = "Local",
    3.51 +                 name_description = "Xend Storage Repository",
    3.52 +                 location = XEND_STORAGE_DIR,
    3.53 +                 storage_max = XEND_STORAGE_NO_MAXIMUM):
    3.54          """
    3.55 -        @keyword storage_dir: Where the images will be stored.
    3.56 -        @type    storage_dir: string
    3.57          @keyword storage_max: Maximum disk space to use in bytes.
    3.58          @type    storage_max: int
    3.59  
    3.60 @@ -67,71 +82,78 @@ class XendStorageRepository:
    3.61          @type    images: dictionary by image uuid.
    3.62          @ivar    lock:   lock to provide thread safety.
    3.63          """
    3.64 -        
    3.65 -        self.storage_dir = storage_dir
    3.66 -        self.storage_max = storage_max
    3.67 -        self.storage_free = 0
    3.68 +
    3.69 +        # XenAPI Parameters
    3.70 +        self.uuid = uuid
    3.71 +        self.type = sr_type
    3.72 +        self.location = location
    3.73 +        self.name_label = name_label
    3.74 +        self.name_description = name_description
    3.75          self.images = {}
    3.76  
    3.77 -        # XenAPI Parameters
    3.78 -        self.uuid = self._sr_uuid()
    3.79 -        self.type = "qcow-file"
    3.80 -        self.location = self.storage_dir
    3.81 -        self.name_label = "Local"
    3.82 -        self.name_description = "Xend Storage Repository"
    3.83 +        self.storage_max = storage_max
    3.84 +        self.storage_free = 0
    3.85 +        self.storage_used = 0
    3.86 +        self.storage_alloc = 0
    3.87  
    3.88          self.lock = threading.RLock()
    3.89 -        self._refresh()        
    3.90 +        self._refresh()
    3.91  
    3.92 -    def _sr_uuid(self):
    3.93 -        uuid_file = os.path.join(XEND_STORAGE_DIR, 'uuid')
    3.94 -        try:
    3.95 -            if uuid_file and os.path.exists(uuid_file):
    3.96 -                return open(uuid_file, 'r').read().strip()
    3.97 -            else:
    3.98 -                new_uuid = uuid.createString()
    3.99 -                open(uuid_file, 'w').write(new_uuid + '\n')
   3.100 -                return new_uuid
   3.101 -        except IOError:
   3.102 -            log.exception("Failed to determine SR UUID")
   3.103 +    def get_record(self):
   3.104 +        retval = {'uuid': self.uuid,
   3.105 +                  'name_label': self.name_label,
   3.106 +                  'name_description': self.name_description,
   3.107 +                  'virtual_allocation': self.storage_alloc,
   3.108 +                  'physical_utilisation': self.storage_used,
   3.109 +                  'physical_size': self.storage_max,
   3.110 +                  'type': self.type,
   3.111 +                  'location': self.location,
   3.112 +                  'VDIs': self.images.keys()}
   3.113 +        
   3.114 +        if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
   3.115 +            stfs = os.statvfs(self.location)
   3.116 +            retval['physical_size'] = stfs.f_blocks * stfs.f_frsize
   3.117  
   3.118 -        return uuid.createString()
   3.119 -
   3.120 +        return retval
   3.121 +        
   3.122      def _refresh(self):
   3.123          """Internal function that refreshes the state of the disk and
   3.124          updates the list of images available.
   3.125          """
   3.126          self.lock.acquire()
   3.127          try:
   3.128 -            mkdir.parents(XEND_STORAGE_DIR, stat.S_IRWXU)
   3.129 +            mkdir.parents(self.location, stat.S_IRWXU)
   3.130  
   3.131              # scan the directory and populate self.images
   3.132 -            total_used = 0
   3.133 +            virtual_alloc = 0
   3.134 +            physical_used = 0
   3.135              seen_images = []
   3.136 -            for filename in os.listdir(XEND_STORAGE_DIR):
   3.137 +            for filename in os.listdir(self.location):
   3.138                  if filename[-5:] == XEND_STORAGE_QCOW_FILENAME[-5:]:
   3.139                      image_uuid = filename[:-5]
   3.140                      seen_images.append(image_uuid)
   3.141 +
   3.142 +                    qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
   3.143 +                    cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
   3.144 +                    qcow_path = os.path.join(self.location, qcow_file)
   3.145 +                    cfg_path = os.path.join(self.location, cfg_file)
   3.146 +                    
   3.147 +                    phys_size = os.stat(qcow_path).st_size
   3.148 +                    virt_size = qcow_virtual_size(qcow_path)
   3.149                      
   3.150                      # add this image if we haven't seen it before
   3.151                      if image_uuid not in self.images:
   3.152 -                        qcow_file = XEND_STORAGE_QCOW_FILENAME % image_uuid
   3.153 -                        cfg_file = XEND_STORAGE_VDICFG_FILENAME % image_uuid
   3.154 -                        qcow_path = os.path.join(XEND_STORAGE_DIR, qcow_file)
   3.155 -                        cfg_path = os.path.join(XEND_STORAGE_DIR, cfg_file)
   3.156 -
   3.157 -                        qcow_size = os.stat(qcow_path).st_size
   3.158 -
   3.159 -                        # TODO: no way to stat virtual size of qcow
   3.160                          vdi = XendQCOWVDI(image_uuid, self.uuid,
   3.161                                            qcow_path, cfg_path,
   3.162 -                                          qcow_size, qcow_size) 
   3.163 +                                          virt_size, phys_size)
   3.164                          
   3.165                          if cfg_path and os.path.exists(cfg_path):
   3.166                              vdi.load_config(cfg_path)
   3.167                          
   3.168                          self.images[image_uuid] = vdi
   3.169 -                        total_used += qcow_size
   3.170 +
   3.171 +                    physical_used += phys_size
   3.172 +                    virtual_alloc += virt_size
   3.173  
   3.174              # remove images that aren't valid
   3.175              for image_uuid in self.images.keys():
   3.176 @@ -142,11 +164,14 @@ class XendStorageRepository:
   3.177                          pass
   3.178                      del self.images[image_uuid]
   3.179  
   3.180 +            self.storage_alloc = virtual_alloc
   3.181 +            self.storage_used = physical_used
   3.182 +
   3.183              # update free storage if we have to track that
   3.184 -            if self.storage_max != XEND_STORAGE_MAX_IGNORE:
   3.185 -                self.storage_free = self.storage_max - total_used
   3.186 +            if self.storage_max == XEND_STORAGE_NO_MAXIMUM:
   3.187 +                self.storage_free = self._get_free_space()
   3.188              else:
   3.189 -                self.storage_free = self._get_free_space()
   3.190 +                self.storage_free = self.storage_max - self.storage_alloc
   3.191                          
   3.192          finally:
   3.193              self.lock.release()
   3.194 @@ -158,7 +183,7 @@ class XendStorageRepository:
   3.195  
   3.196          @rtype: int
   3.197          """
   3.198 -        stfs = os.statvfs(self.storage_dir)
   3.199 +        stfs = os.statvfs(self.location)
   3.200          return stfs.f_bavail * stfs.f_frsize
   3.201  
   3.202      def _has_space_available_for(self, size_bytes):
   3.203 @@ -167,22 +192,19 @@ class XendStorageRepository:
   3.204  
   3.205          @rtype: bool
   3.206          """
   3.207 -        if self.storage_max != -1:
   3.208 -            return self.storage_free
   3.209 +        if self.storage_max != XEND_STORAGE_NO_MAXIMUM:
   3.210 +            return self.storage_free > size_bytes
   3.211          
   3.212          bytes_free = self._get_free_space()
   3.213 -        try:
   3.214 -            if size_bytes < bytes_free:
   3.215 -                return True
   3.216 -        except DeviceInvalidError:
   3.217 -            pass
   3.218 +        if size_bytes < bytes_free:
   3.219 +            return True
   3.220          return False
   3.221  
   3.222      def _create_image_files(self, desired_size_bytes):
   3.223          """Create an image and return its assigned UUID.
   3.224  
   3.225 -        @param desired_size_kb: Desired image size in KB.
   3.226 -        @type  desired_size_kb: int
   3.227 +        @param desired_size_bytes: Desired image size in bytes
   3.228 +        @type  desired_size_bytes: int
   3.229          @rtype: string
   3.230          @return: uuid
   3.231  
   3.232 @@ -194,7 +216,7 @@ class XendStorageRepository:
   3.233                  raise XendError("Not enough space")
   3.234  
   3.235              image_uuid = uuid.createString()
   3.236 -            qcow_path = os.path.join(XEND_STORAGE_DIR,
   3.237 +            qcow_path = os.path.join(self.location,
   3.238                                       XEND_STORAGE_QCOW_FILENAME % image_uuid)
   3.239              
   3.240              if qcow_path and os.path.exists(qcow_path):
   3.241 @@ -268,10 +290,7 @@ class XendStorageRepository:
   3.242          """
   3.243          self.lock.acquire()
   3.244          try:
   3.245 -            if self.storage_max != XEND_STORAGE_MAX_IGNORE:
   3.246 -                return self.storage_max
   3.247 -            else:
   3.248 -                return self.free_space_bytes() + self.used_space_bytes()
   3.249 +            return self.storage_max
   3.250          finally:
   3.251              self.lock.release()
   3.252              
   3.253 @@ -315,7 +334,7 @@ class XendStorageRepository:
   3.254  
   3.255              # save configuration to file
   3.256              cfg_filename =  XEND_STORAGE_VDICFG_FILENAME % image_uuid
   3.257 -            cfg_path = os.path.join(XEND_STORAGE_DIR, cfg_filename)
   3.258 +            cfg_path = os.path.join(self.location, cfg_filename)
   3.259              image.save_config(cfg_path)
   3.260              
   3.261          except Exception, e:
   3.262 @@ -327,10 +346,10 @@ class XendStorageRepository:
   3.263  
   3.264          return image_uuid
   3.265          
   3.266 -    def xen_api_get_by_label(self, label):
   3.267 +    def xen_api_get_by_name_label(self, label):
   3.268          self.lock.acquire()
   3.269          try:
   3.270 -            for image_uuid, val in self.images.values():
   3.271 +            for image_uuid, val in self.images.items():
   3.272                  if val.name_label == label:
   3.273                      return image_uuid
   3.274              return None