mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
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': 'Bytes',
|
|
'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']/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:])
|