mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
This patch merges the way VFB are represented inside Xend by making HVM VNC consoles use the VFB as its configuration object. It preserves the way options are specified through xm but will create a new VFB device that is used by image.py to put vnc config into qemu-dm's command line. The parsing is moved into image.py's parseDeviceModel() rather than in configVNC(). Through the Xen API, you can create a 'console' of protocol 'rfb' and end up with a VNC console, on both HVM and PV guests. The location of the connecting port is stored in the location attribute of the console object. This is updated on each XendDomainInfo.update() if it changes. Also fixes missing read of the vnclisten and HVM_boot from the config when initialised via xm. Makes sure bootable attribute for VBD is store as an int when making SXP config. Signed-off-by: Alastair Tse <atse@xensource.com>
881 lines
29 KiB
Python
881 lines
29 KiB
Python
#!/usr/bin/python
|
|
#============================================================================
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#============================================================================
|
|
# Copyright (C) 2006 XenSource Ltd.
|
|
#============================================================================
|
|
|
|
import sys
|
|
import time
|
|
import re
|
|
import os
|
|
sys.path.append('/usr/lib/python')
|
|
|
|
from xen.util.xmlrpclib2 import ServerProxy
|
|
from optparse import *
|
|
from pprint import pprint
|
|
from types import DictType
|
|
from getpass import getpass
|
|
|
|
# Get default values from the environment
|
|
SERVER_URI = os.environ.get('XAPI_SERVER_URI', 'http://localhost:9363/')
|
|
SERVER_USER = os.environ.get('XAPI_SERVER_USER', '')
|
|
SERVER_PASS = os.environ.get('XAPI_SERVER_PASS', '')
|
|
|
|
MB = 1024 * 1024
|
|
|
|
HOST_INFO_FORMAT = '%-20s: %-50s'
|
|
VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(VCPUs_number)-5s'\
|
|
' %(power_state)-10s %(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'
|
|
VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s'
|
|
TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s'
|
|
VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s'
|
|
CONSOLE_LIST_FORMAT = '%(uuid)-36s %(protocol)-8s %(location)-32s'
|
|
|
|
COMMANDS = {
|
|
'host-info': ('', 'Get Xen Host Info'),
|
|
'host-set-name': ('', 'Set host name'),
|
|
'pif-list': ('', 'List all PIFs'),
|
|
'sr-list': ('', 'List all SRs'),
|
|
'vbd-list': ('', 'List all VBDs'),
|
|
'vbd-create': ('<domname> <pycfg> [opts]',
|
|
'Create VBD attached to domname'),
|
|
'vdi-create': ('<pycfg> [opts]', 'Create a VDI'),
|
|
'vdi-list' : ('', 'List all VDI'),
|
|
'vdi-rename': ('<vdi_uuid> <new_name>', 'Rename VDI'),
|
|
'vdi-destroy': ('<vdi_uuid>', 'Delete VDI'),
|
|
'vif-create': ('<domname> <pycfg>', 'Create VIF attached to domname'),
|
|
'vtpm-create' : ('<domname> <pycfg>', 'Create VTPM attached to domname'),
|
|
|
|
'vm-create': ('<pycfg>', 'Create VM with python config'),
|
|
'vm-destroy': ('<domname>', 'Delete VM'),
|
|
|
|
'vm-list': ('[--long]', 'List all domains.'),
|
|
'vm-name': ('<uuid>', 'Name of UUID.'),
|
|
'vm-shutdown': ('<name> [opts]', 'Shutdown VM with name'),
|
|
'vm-start': ('<name>', 'Start VM with name'),
|
|
'vm-uuid': ('<name>', 'UUID of a domain by name.'),
|
|
'async-vm-start': ('<name>', 'Start VM asynchronously'),
|
|
}
|
|
|
|
OPTIONS = {
|
|
'sr-list': [(('-l', '--long'),
|
|
{'action':'store_true',
|
|
'help':'List all properties of SR'})
|
|
],
|
|
|
|
'vdi-list': [(('-l', '--long'),
|
|
{'action':'store_true',
|
|
'help':'List all properties of VDI'})
|
|
],
|
|
'vif-list': [(('-l', '--long'),
|
|
{'action':'store_true',
|
|
'help':'List all properties of VIF'})
|
|
],
|
|
'vm-list': [(('-l', '--long'),
|
|
{'action':'store_true',
|
|
'help':'List all properties of VMs'})
|
|
],
|
|
'vm-shutdown': [(('-f', '--force'), {'help': 'Shutdown Forcefully',
|
|
'action': 'store_true'})],
|
|
|
|
'vdi-create': [(('--name-label',), {'help': 'Name for VDI'}),
|
|
(('--name-description',), {'help': 'Description for VDI'}),
|
|
(('--sector-size',), {'type': 'int',
|
|
'help': 'Sector size',
|
|
'default': 0}),
|
|
(('--virtual-size',), {'type': 'int',
|
|
'default': 0,
|
|
'help': 'Size of VDI in sectors'}),
|
|
(('--type',), {'choices': ['system', 'user', 'ephemeral'],
|
|
'default': 'system',
|
|
'help': 'VDI type'}),
|
|
(('--sharable',), {'action': 'store_true',
|
|
'help': 'VDI sharable'}),
|
|
(('--read-only',), {'action': 'store_true',
|
|
'help': 'Read only'}),
|
|
(('--sr',), {})],
|
|
|
|
'vbd-create': [(('--VDI',), {'help': 'UUID of VDI to attach to.'}),
|
|
(('--mode',), {'choices': ['RO', 'RW'],
|
|
'help': 'device mount mode'}),
|
|
(('--driver',), {'choices':['paravirtualised', 'ioemu'],
|
|
'help': 'Driver for VBD'}),
|
|
(('--device',), {'help': 'Device name on guest domain'})]
|
|
|
|
}
|
|
|
|
class OptionError(Exception):
|
|
pass
|
|
|
|
class XenAPIError(Exception):
|
|
pass
|
|
|
|
#
|
|
# Extra utility functions
|
|
#
|
|
|
|
class IterableValues(Values):
|
|
"""Better interface to the list of values from optparse."""
|
|
|
|
def __iter__(self):
|
|
for opt, val in self.__dict__.items():
|
|
if opt[0] == '_' or callable(val):
|
|
continue
|
|
yield opt, val
|
|
|
|
|
|
def parse_args(cmd_name, args, set_defaults = False):
|
|
argstring, desc = COMMANDS[cmd_name]
|
|
parser = OptionParser(usage = 'xapi %s %s' % (cmd_name, argstring),
|
|
description = desc)
|
|
if cmd_name in OPTIONS:
|
|
for optargs, optkwds in OPTIONS[cmd_name]:
|
|
parser.add_option(*optargs, **optkwds)
|
|
|
|
if set_defaults:
|
|
default_values = parser.get_default_values()
|
|
defaults = IterableValues(default_values.__dict__)
|
|
else:
|
|
defaults = IterableValues()
|
|
(opts, extraargs) = parser.parse_args(args = list(args),
|
|
values = defaults)
|
|
return opts, extraargs
|
|
|
|
def execute(server, fn, args, async = False):
|
|
if async:
|
|
func = eval('server.Async.%s' % fn)
|
|
else:
|
|
func = eval('server.%s' % fn)
|
|
|
|
result = func(*args)
|
|
if type(result) != DictType:
|
|
raise TypeError("Function returned object of type: %s" %
|
|
str(type(result)))
|
|
if 'Value' not in result:
|
|
raise XenAPIError(*result['ErrorDescription'])
|
|
return result['Value']
|
|
|
|
_initialised = False
|
|
_server = None
|
|
_session = None
|
|
def connect(*args):
|
|
global _server, _session, _initialised
|
|
|
|
if not _initialised:
|
|
# try without password or default credentials
|
|
try:
|
|
_server = ServerProxy(SERVER_URI)
|
|
_session = execute(_server.session, 'login_with_password',
|
|
(SERVER_USER, SERVER_PASS))
|
|
except:
|
|
login = raw_input("Login: ")
|
|
password = getpass()
|
|
creds = (login, password)
|
|
_server = ServerProxy(SERVER_URI)
|
|
_session = execute(_server.session, 'login_with_password',
|
|
creds)
|
|
|
|
_initialised = True
|
|
return (_server, _session)
|
|
|
|
def _stringify(adict):
|
|
return dict([(k, str(v)) for k, v in adict.items()])
|
|
|
|
def _read_python_cfg(filename):
|
|
cfg = {}
|
|
execfile(filename, {}, cfg)
|
|
return cfg
|
|
|
|
def resolve_vm(server, session, vm_name):
|
|
vm_uuid = execute(server, 'VM.get_by_name_label', (session, vm_name))
|
|
if not vm_uuid:
|
|
return None
|
|
else:
|
|
return vm_uuid[0]
|
|
|
|
def resolve_vdi(server, session, vdi_name):
|
|
vdi_uuid = execute(server, 'VDI.get_by_name_label', (session, vdi_name))
|
|
if not vdi_uuid:
|
|
return None
|
|
else:
|
|
return vdi_uuid[0]
|
|
|
|
#
|
|
# Actual commands
|
|
#
|
|
|
|
def xapi_host_info(args, async = False):
|
|
server, session = connect()
|
|
hosts = execute(server, 'host.get_all', (session,))
|
|
for host in hosts: # there is only one, but ..
|
|
hostinfo = execute(server, 'host.get_record', (session, host))
|
|
print HOST_INFO_FORMAT % ('Name', hostinfo['name_label'])
|
|
print HOST_INFO_FORMAT % ('Version', hostinfo['software_version'])
|
|
print HOST_INFO_FORMAT % ('CPUs', len(hostinfo['host_CPUs']))
|
|
print HOST_INFO_FORMAT % ('VMs', len(hostinfo['resident_VMs']))
|
|
print HOST_INFO_FORMAT % ('UUID', host)
|
|
|
|
for host_cpu_uuid in hostinfo['host_CPUs']:
|
|
host_cpu = execute(server, 'host_cpu.get_record',
|
|
(session, host_cpu_uuid))
|
|
print 'CPU %s Util: %.2f' % (host_cpu['number'],
|
|
float(host_cpu['utilisation']))
|
|
|
|
def xapi_host_set_name(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No hostname specified")
|
|
|
|
server, session = connect()
|
|
hosts = execute(server, 'host.get_all', (session,))
|
|
if len(hosts) > 0:
|
|
execute(server, 'host.set_name_label', (session, hosts[0], args[0]))
|
|
print 'Hostname: %s' % execute(server, 'host.get_name_label',
|
|
(session, hosts[0]))
|
|
|
|
def xapi_vm_uuid(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No domain name specified")
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, args[0])
|
|
print vm_uuid
|
|
|
|
def xapi_vm_name(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No UUID specified")
|
|
|
|
server, session = connect()
|
|
vm_name = execute(server, 'VM.get_name_label', (session, args[0]))
|
|
print vm_name
|
|
|
|
def xapi_vm_list(args, async = False):
|
|
opts, args = parse_args('vm-list', args, set_defaults = True)
|
|
is_long = opts and opts.long
|
|
|
|
list_only = args
|
|
|
|
server, session = connect()
|
|
vm_uuids = execute(server, 'VM.get_all', (session,))
|
|
if not is_long:
|
|
print VM_LIST_FORMAT % {'name_label':'Name',
|
|
'memory_actual':'Mem',
|
|
'VCPUs_number': 'VCPUs',
|
|
'power_state': 'State',
|
|
'uuid': 'UUID'}
|
|
|
|
for uuid in vm_uuids:
|
|
vm_info = execute(server, 'VM.get_record', (session, uuid))
|
|
|
|
# skip domain if we don't want
|
|
if list_only and vm_info['name_label'] not in list_only:
|
|
continue
|
|
|
|
if is_long:
|
|
vbds = vm_info['VBDs']
|
|
vifs = vm_info['VIFs']
|
|
vtpms = vm_info['VTPMs']
|
|
vif_infos = []
|
|
vbd_infos = []
|
|
vtpm_infos = []
|
|
for vbd in vbds:
|
|
vbd_info = execute(server, 'VBD.get_record', (session, vbd))
|
|
vbd_infos.append(vbd_info)
|
|
for vif in vifs:
|
|
vif_info = execute(server, 'VIF.get_record', (session, vif))
|
|
vif_infos.append(vif_info)
|
|
for vtpm in vtpms:
|
|
vtpm_info = execute(server, 'VTPM.get_record', (session, vtpm))
|
|
vtpm_infos.append(vtpm_info)
|
|
vm_info['VBDs'] = vbd_infos
|
|
vm_info['VIFs'] = vif_infos
|
|
vm_info['VTPMs'] = vtpm_infos
|
|
pprint(vm_info)
|
|
else:
|
|
print VM_LIST_FORMAT % _stringify(vm_info)
|
|
|
|
def xapi_vm_create(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("Configuration file not specified")
|
|
|
|
filename = args[0]
|
|
cfg = _read_python_cfg(filename)
|
|
|
|
print 'Creating VM from %s ..' % filename
|
|
server, session = connect()
|
|
uuid = execute(server, 'VM.create', (session, cfg), async = async)
|
|
print 'Done. (%s)' % uuid
|
|
print uuid
|
|
|
|
def xapi_vm_destroy(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No domain name specified.")
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, args[0])
|
|
print 'Destroying VM %s (%s)' % (args[0], vm_uuid)
|
|
success = execute(server, 'VM.destroy', (session, vm_uuid), async = async)
|
|
print 'Done.'
|
|
|
|
|
|
def xapi_vm_start(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No Domain name specified.")
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, args[0])
|
|
print 'Starting VM %s (%s)' % (args[0], vm_uuid)
|
|
success = execute(server, 'VM.start', (session, vm_uuid, False), async = async)
|
|
if async:
|
|
print 'Task started: %s' % success
|
|
else:
|
|
print 'Done.'
|
|
|
|
def xapi_vm_suspend(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No Domain name specified.")
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, args[0])
|
|
print 'Suspending VM %s (%s)' % (args[0], vm_uuid)
|
|
success = execute(server, 'VM.suspend', (session, vm_uuid), async = async)
|
|
if async:
|
|
print 'Task started: %s' % success
|
|
else:
|
|
print 'Done.'
|
|
|
|
|
|
def xapi_vm_resume(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No Domain name specified.")
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, args[0])
|
|
print 'Resuming VM %s (%s)' % (args[0], vm_uuid)
|
|
success = execute(server, 'VM.resume', (session, vm_uuid, False), async = async)
|
|
if async:
|
|
print 'Task started: %s' % success
|
|
else:
|
|
print 'Done.'
|
|
|
|
def xapi_vm_pause(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No Domain name specified.")
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, args[0])
|
|
print 'Pausing VM %s (%s)' % (args[0], vm_uuid)
|
|
success = execute(server, 'VM.pause', (session, vm_uuid), async = async)
|
|
if async:
|
|
print 'Task started: %s' % success
|
|
else:
|
|
print 'Done.'
|
|
|
|
def xapi_vm_unpause(args, async = False):
|
|
if len(args) < 1:
|
|
raise OptionError("No Domain name specified.")
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, args[0])
|
|
print 'Pausing VM %s (%s)' % (args[0], vm_uuid)
|
|
success = execute(server, 'VM.unpause', (session, vm_uuid), async = async)
|
|
if async:
|
|
print 'Task started: %s' % success
|
|
else:
|
|
print 'Done.'
|
|
|
|
def xapi_task_list(args, async = False):
|
|
server, session = connect()
|
|
all_tasks = execute(server, 'task.get_all', (session,))
|
|
|
|
print TASK_LIST_FORMAT % {'name_label': 'Task Name',
|
|
'uuid': 'UUID',
|
|
'status': 'Status',
|
|
'progress': '%'}
|
|
|
|
for task_uuid in all_tasks:
|
|
task = execute(server, 'task.get_record', (session, task_uuid))
|
|
print TASK_LIST_FORMAT % task
|
|
|
|
def xapi_task_clear(args, async = False):
|
|
server, session = connect()
|
|
all_tasks = execute(server, 'task.get_all', (session,))
|
|
for task_uuid in all_tasks:
|
|
success = execute(server, 'task.destroy', (session, task_uuid))
|
|
print 'Destroyed Task %s' % task_uuid
|
|
|
|
def xapi_vm_shutdown(args, async = False):
|
|
opts, args = parse_args("vm-shutdown", args, set_defaults = True)
|
|
|
|
if len(args) < 1:
|
|
raise OptionError("No Domain name specified.")
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, args[0])
|
|
if opts.force:
|
|
print 'Forcefully shutting down VM %s (%s)' % (args[0], vm_uuid)
|
|
success = execute(server, 'VM.hard_shutdown', (session, vm_uuid), async = async)
|
|
else:
|
|
print 'Shutting down VM %s (%s)' % (args[0], vm_uuid)
|
|
success = execute(server, 'VM.clean_shutdown', (session, vm_uuid), async = async)
|
|
|
|
if async:
|
|
print 'Task started: %s' % success
|
|
else:
|
|
print 'Done.'
|
|
|
|
def xapi_vbd_create(args, async = False):
|
|
opts, args = parse_args('vbd-create', args)
|
|
|
|
if len(args) < 2:
|
|
raise OptionError("Configuration file and domain not specified")
|
|
|
|
domname = args[0]
|
|
|
|
if len(args) > 1:
|
|
filename = args[1]
|
|
cfg = _read_python_cfg(filename)
|
|
else:
|
|
cfg = {}
|
|
|
|
for opt, val in opts:
|
|
cfg[opt] = val
|
|
|
|
print 'Creating VBD ...',
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, domname)
|
|
cfg['VM'] = vm_uuid
|
|
vbd_uuid = execute(server, 'VBD.create', (session, cfg), async = async)
|
|
if async:
|
|
print 'Task started: %s' % vbd_uuid
|
|
else:
|
|
print 'Done. (%s)' % vbd_uuid
|
|
|
|
def xapi_vif_create(args, async = False):
|
|
if len(args) < 2:
|
|
raise OptionError("Configuration file not specified")
|
|
|
|
domname = args[0]
|
|
filename = args[1]
|
|
cfg = _read_python_cfg(filename)
|
|
|
|
print 'Creating VIF from %s ..' % filename
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, domname)
|
|
cfg['VM'] = vm_uuid
|
|
vif_uuid = execute(server, 'VIF.create', (session, cfg), async = async)
|
|
if async:
|
|
print 'Task started: %s' % vif_uuid
|
|
else:
|
|
print 'Done. (%s)' % vif_uuid
|
|
|
|
def xapi_vbd_list(args, async = False):
|
|
server, session = connect()
|
|
domname = args[0]
|
|
|
|
dom_uuid = resolve_vm(server, session, domname)
|
|
vbds = execute(server, 'VM.get_VBDs', (session, dom_uuid))
|
|
|
|
print VBD_LIST_FORMAT % {'device': 'Device',
|
|
'uuid' : 'UUID',
|
|
'VDI': 'VDI'}
|
|
|
|
for vbd in vbds:
|
|
vbd_struct = execute(server, 'VBD.get_record', (session, vbd))
|
|
print VBD_LIST_FORMAT % vbd_struct
|
|
|
|
|
|
def xapi_vbd_stats(args, async = False):
|
|
server, session = connect()
|
|
domname = args[0]
|
|
dom_uuid = resolve_vm(server, session, domname)
|
|
|
|
vbds = execute(server, 'VM.get_VBDs', (session, dom_uuid))
|
|
for vbd_uuid in vbds:
|
|
print execute(server, 'VBD.get_io_read_kbs', (session, vbd_uuid))
|
|
|
|
def xapi_vif_list(args, async = False):
|
|
server, session = connect()
|
|
opts, args = parse_args('vdi-list', args, set_defaults = True)
|
|
is_long = opts and opts.long
|
|
|
|
domname = args[0]
|
|
|
|
dom_uuid = resolve_vm(server, session, domname)
|
|
vifs = execute(server, 'VM.get_VIFs', (session, dom_uuid))
|
|
|
|
if not is_long:
|
|
print VIF_LIST_FORMAT % {'name': 'Name',
|
|
'device': 'Device',
|
|
'uuid' : 'UUID',
|
|
'MAC': 'MAC'}
|
|
|
|
for vif in vifs:
|
|
vif_struct = execute(server, 'VIF.get_record', (session, vif))
|
|
print VIF_LIST_FORMAT % vif_struct
|
|
else:
|
|
for vif in vifs:
|
|
vif_struct = execute(server, 'VIF.get_record', (session, vif))
|
|
pprint(vif_struct)
|
|
|
|
def xapi_console_list(args, async = False):
|
|
server, session = connect()
|
|
opts, args = parse_args('vdi-list', args, set_defaults = True)
|
|
is_long = opts and opts.long
|
|
|
|
domname = args[0]
|
|
|
|
dom_uuid = resolve_vm(server, session, domname)
|
|
consoles = execute(server, 'VM.get_consoles', (session, dom_uuid))
|
|
|
|
if not is_long:
|
|
print CONSOLE_LIST_FORMAT % {'protocol': 'Protocol',
|
|
'location': 'Location',
|
|
'uuid': 'UUID'}
|
|
|
|
for console in consoles:
|
|
console_struct = execute(server, 'console.get_record',
|
|
(session, console))
|
|
print CONSOLE_LIST_FORMAT % console_struct
|
|
else:
|
|
for console in consoles:
|
|
console_struct = execute(server, 'console.get_record',
|
|
(session, console))
|
|
pprint(console_struct)
|
|
|
|
|
|
def xapi_vdi_list(args, async = False):
|
|
opts, args = parse_args('vdi-list', args, set_defaults = True)
|
|
is_long = opts and opts.long
|
|
|
|
server, session = connect()
|
|
vdis = execute(server, 'VDI.get_all', (session,))
|
|
|
|
if not is_long:
|
|
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
|
|
|
|
else:
|
|
for vdi in vdis:
|
|
vdi_struct = execute(server, 'VDI.get_record', (session, vdi))
|
|
pprint(vdi_struct)
|
|
|
|
def xapi_sr_list(args, async = False):
|
|
opts, args = parse_args('sr-list', args, set_defaults = True)
|
|
is_long = opts and opts.long
|
|
|
|
server, session = connect()
|
|
srs = execute(server, 'SR.get_all', (session,))
|
|
if not is_long:
|
|
print SR_LIST_FORMAT % {'name_label': 'SR Label',
|
|
'uuid' : 'UUID',
|
|
'physical_size': 'Size (MB)',
|
|
'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
|
|
else:
|
|
for sr in srs:
|
|
sr_struct = execute(server, 'SR.get_record', (session, sr))
|
|
pprint(sr_struct)
|
|
|
|
def xapi_sr_rename(args, async = False):
|
|
server, session = connect()
|
|
sr = execute(server, 'SR.get_by_name_label', (session, args[0]))
|
|
execute(server, 'SR.set_name_label', (session, sr[0], args[1]))
|
|
|
|
def xapi_vdi_create(args, async = False):
|
|
opts, args = parse_args('vdi-create', args)
|
|
|
|
if len(args) > 0:
|
|
cfg = _read_python_cfg(args[0])
|
|
else:
|
|
cfg = {}
|
|
|
|
for opt, val in opts:
|
|
cfg[opt] = val
|
|
|
|
server, session = connect()
|
|
srs = []
|
|
if cfg.get('SR'):
|
|
srs = execute(server, 'SR.get_by_name_label', (session, cfg['SR']))
|
|
else:
|
|
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), async = async)
|
|
if async:
|
|
print 'Task started: %s' % uuid
|
|
else:
|
|
print 'Done. (%s)' % uuid
|
|
|
|
|
|
def xapi_vdi_destroy(args, async = False):
|
|
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), async = async)
|
|
if async:
|
|
print 'Task started: %s' % result
|
|
else:
|
|
print 'Done.'
|
|
|
|
def xapi_vdi_rename(args, async = False):
|
|
server, session = connect()
|
|
if len(args) < 2:
|
|
raise OptionError('Not enough arguments')
|
|
|
|
vdi_uuid = execute(server, 'VDI.get_by_name_label', session, args[0])
|
|
vdi_name = args[1]
|
|
|
|
print 'Renaming VDI %s to %s' % (vdi_uuid[0], vdi_name)
|
|
result = execute(server, 'VDI.set_name_label',
|
|
(session, vdi_uuid[0], vdi_name), async = async)
|
|
if async:
|
|
print 'Task started: %s' % result
|
|
else:
|
|
print 'Done.'
|
|
|
|
|
|
|
|
def xapi_vtpm_create(args, async = False):
|
|
server, session = connect()
|
|
domname = args[0]
|
|
cfg = _read_python_cfg(args[1])
|
|
|
|
vm_uuid = resolve_vm(server, session, domname)
|
|
cfg['VM'] = vm_uuid
|
|
print "Creating vTPM with cfg = %s" % cfg
|
|
vtpm_uuid = execute(server, 'VTPM.create', (session, cfg))
|
|
print "Done. (%s)" % vtpm_uuid
|
|
|
|
|
|
def xapi_pif_list(args, async = False):
|
|
server, session = connect()
|
|
pif_uuids = execute(server, 'PIF.get_all', (session,))
|
|
for pif_uuid in pif_uuids:
|
|
pif = execute(server, 'PIF.get_record', (session, pif_uuid))
|
|
print pif
|
|
|
|
|
|
def xapi_debug_wait(args, async = False):
|
|
secs = 10
|
|
if len(args) > 0:
|
|
secs = int(args[0])
|
|
server, session = connect()
|
|
task_uuid = execute(server, 'debug.wait', (session, secs), async=async)
|
|
print 'Task UUID: %s' % task_uuid
|
|
|
|
def xapi_vm_stat(args, async = False):
|
|
domname = args[0]
|
|
|
|
server, session = connect()
|
|
vm_uuid = resolve_vm(server, session, domname)
|
|
vif_uuids = execute(server, 'VM.get_VIFs', (session, vm_uuid))
|
|
vbd_uuids = execute(server, 'VM.get_VBDs', (session, vm_uuid))
|
|
vcpus_utils = execute(server, 'VM.get_VCPUs_utilisation',
|
|
(session, vm_uuid))
|
|
|
|
for vcpu_num in sorted(vcpus_utils.keys()):
|
|
print 'CPU %s : %5.2f%%' % (vcpu_num, vcpus_utils[vcpu_num] * 100)
|
|
|
|
for vif_uuid in vif_uuids:
|
|
vif = execute(server, 'VIF.get_record', (session, vif_uuid))
|
|
print '%(device)s: rx: %(io_read_kbs)10.2f tx: %(io_write_kbs)10.2f' \
|
|
% vif
|
|
for vbd_uuid in vbd_uuids:
|
|
vbd = execute(server, 'VBD.get_record', (session, vbd_uuid))
|
|
print '%(device)s: rd: %(io_read_kbs)10.2f wr: %(io_write_kbs)10.2f' \
|
|
% vbd
|
|
|
|
#
|
|
# Command Line Utils
|
|
#
|
|
import cmd
|
|
import shlex
|
|
|
|
class XenAPICmd(cmd.Cmd):
|
|
def __init__(self, server, session):
|
|
cmd.Cmd.__init__(self)
|
|
self.server = server
|
|
self.session = session
|
|
self.prompt = ">>> "
|
|
|
|
def default(self, line):
|
|
words = shlex.split(line)
|
|
if len(words) > 0:
|
|
cmd_name = words[0].replace('-', '_')
|
|
is_async = 'async' in cmd_name
|
|
if is_async:
|
|
cmd_name = re.sub('async_', '', cmd_name)
|
|
|
|
func_name = 'xapi_%s' % cmd_name
|
|
func = globals().get(func_name)
|
|
|
|
if func:
|
|
try:
|
|
args = tuple(words[1:])
|
|
func(args, async = is_async)
|
|
return True
|
|
except SystemExit:
|
|
return False
|
|
except OptionError, e:
|
|
print 'Error:', str(e)
|
|
return False
|
|
except Exception, e:
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
print '*** Unknown command: %s' % words[0]
|
|
return False
|
|
|
|
def do_EOF(self, line):
|
|
print
|
|
sys.exit(0)
|
|
|
|
def do_help(self, line):
|
|
usage(print_usage = False)
|
|
|
|
def emptyline(self):
|
|
pass
|
|
|
|
def postcmd(self, stop, line):
|
|
return False
|
|
|
|
def precmd(self, line):
|
|
words = shlex.split(line)
|
|
if len(words) > 0:
|
|
words0 = words[0].replace('-', '_')
|
|
return ' '.join([words0] + words[1:])
|
|
else:
|
|
return line
|
|
|
|
def shell():
|
|
server, session = connect()
|
|
x = XenAPICmd(server, session)
|
|
x.cmdloop('Xen API Prompt. Type "help" for a list of functions')
|
|
|
|
def usage(command = None, print_usage = True):
|
|
if not command:
|
|
if print_usage:
|
|
print 'Usage: xapi <subcommand> [options] [args]'
|
|
print
|
|
print 'Subcommands:'
|
|
print
|
|
|
|
for func in sorted(globals().keys()):
|
|
if func.startswith('xapi_'):
|
|
command = func[5:].replace('_', '-')
|
|
args, description = COMMANDS.get(command, ('', ''))
|
|
print '%-16s %-40s' % (command, description)
|
|
print
|
|
else:
|
|
parse_args(command, ['-h'])
|
|
|
|
def main(args):
|
|
|
|
# poor man's optparse that doesn't abort on unrecognised opts
|
|
|
|
options = {}
|
|
remaining = []
|
|
|
|
arg_n = 0
|
|
while args:
|
|
arg = args.pop(0)
|
|
|
|
if arg in ('--help', '-h'):
|
|
options['help'] = True
|
|
elif arg in ('--server', '-s') and args:
|
|
options['server'] = args.pop(0)
|
|
elif arg in ('--user', '-u') and args:
|
|
options['user'] = args.pop(0)
|
|
elif arg in ('--password', '-p') and args:
|
|
options['password'] = args.pop(0)
|
|
else:
|
|
remaining.append(arg)
|
|
|
|
# abort here if these conditions are true
|
|
|
|
if options.get('help') and not remaining:
|
|
usage()
|
|
sys.exit(1)
|
|
|
|
if options.get('help') and remaining:
|
|
usage(remaining[0])
|
|
sys.exit(1)
|
|
|
|
if not remaining:
|
|
usage()
|
|
sys.exit(1)
|
|
|
|
if options.get('server'):
|
|
# it is ugly to use a global, but it is simple
|
|
global SERVER_URI
|
|
SERVER_URI = options['server']
|
|
|
|
if options.get('user'):
|
|
global SERVER_USER
|
|
SERVER_USER = options['user']
|
|
|
|
if options.get('password'):
|
|
global SERVER_PASS
|
|
SERVER_PASS = options['password']
|
|
|
|
subcmd = remaining[0].replace('-', '_')
|
|
is_async = 'async' in subcmd
|
|
if is_async:
|
|
subcmd = re.sub('async_', '', subcmd)
|
|
subcmd_func_name = 'xapi_' + subcmd
|
|
subcmd_func = globals().get(subcmd_func_name, None)
|
|
|
|
if subcmd == 'shell':
|
|
shell()
|
|
elif not subcmd_func or not callable(subcmd_func):
|
|
print 'Error: Unable to find subcommand \'%s\'' % subcmd
|
|
usage()
|
|
sys.exit(1)
|
|
|
|
try:
|
|
subcmd_func(remaining[1:], async = is_async)
|
|
except XenAPIError, e:
|
|
print 'Error: %s' % str(e.args[0])
|
|
sys.exit(2)
|
|
except OptionError, e:
|
|
print 'Error: %s' % e
|
|
|
|
sys.exit(0)
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
main(sys.argv[1:])
|