[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@xensource.com>
This commit is contained in:
Alastair Tse committed 2006-10-13 15:13:21 +01:00
1 parent 2556368450
commit 76b24ff4e2
8 files changed
+474 -115

No files matched your search

+60 -5
View File
@@ -21,15 +21,23 @@ from optparse import *
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
#
+7
View File
@@ -0,0 +1,7 @@
name_label = 'VDI 1'
name_description = ''
virtual_size = 10 * 1024
sector_size = 1024
type = 'system'
sharable = False
read_only = False
+21 -5
View File
@@ -21,8 +21,9 @@ An enhanced XML-RPC client/server interface for Python.
"""
import string
import types
import fcntl
from types import *
from httplib import HTTPConnection, HTTP
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
@@ -39,6 +40,23 @@ except ImportError:
# 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
# form:
@@ -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.ThreadingMixIn, SimpleXMLRPCServer):
# to transmit the string using Python encoding.
# Thanks to David Mertz <mertz@gnosis.cx> 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,)
+143 -61
View File
@@ -25,23 +25,10 @@ from xen.xend.XendClient import ERROR_INVALID_DOMAIN
from xen.xend.XendLogging import log
from xen.xend.XendAPIConstants import *
from xen.util.xmlrpclib2 import stringify
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
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:
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:
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)
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)
+17 -1
View File
@@ -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 ''
+26 -1
View File
@@ -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')
+98 -33
View File
@@ -31,7 +31,8 @@ XEND_STORAGE_MAX_IGNORE = -1
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()
bytes_free = self._get_free_space()
try:
if size_kb < kb_free:
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
+102 -9
View File
@@ -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
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.