mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
Support xm create through the Xen-API.
Signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
This commit is contained in:
1 parent
c0767e1cc9
commit
61fd72f748
7 files changed
+939
-68
No files matched your search
@@ -105,8 +105,6 @@ XENAPI_CFG_TO_LEGACY_CFG = {
|
||||
'uuid': 'uuid',
|
||||
'vcpus_number': 'vcpus',
|
||||
'cpus': 'cpus',
|
||||
'memory_static_min': 'memory',
|
||||
'memory_static_max': 'maxmem',
|
||||
'name_label': 'name',
|
||||
'actions_after_shutdown': 'on_poweroff',
|
||||
'actions_after_reboot': 'on_reboot',
|
||||
@@ -136,11 +134,10 @@ XENAPI_CFG_TYPES = {
|
||||
'user_version': str,
|
||||
'is_a_template': bool0,
|
||||
'resident_on': str,
|
||||
'memory_static_min': int,
|
||||
'memory_static_min': int, # note these are stored in bytes, not KB!
|
||||
'memory_static_max': int,
|
||||
'memory_dynamic_min': int,
|
||||
'memory_dynamic_max': int,
|
||||
'memory_actual': int,
|
||||
'cpus': list,
|
||||
'vcpus_policy': str,
|
||||
'vcpus_params': dict,
|
||||
@@ -314,7 +311,6 @@ class XendConfig(dict):
|
||||
'shadow_memory': 0,
|
||||
'memory_static_max': 0,
|
||||
'memory_dynamic_max': 0,
|
||||
'memory_actual': 0,
|
||||
'devices': {},
|
||||
'security': None,
|
||||
'on_xend_start': 'ignore',
|
||||
@@ -334,20 +330,39 @@ class XendConfig(dict):
|
||||
|
||||
return defaults
|
||||
|
||||
#
|
||||
# Here we assume these values exist in the dict.
|
||||
# If they don't we have a bigger problem, lets not
|
||||
# try and 'fix it up' but acutually fix the cause ;-)
|
||||
#
|
||||
def _memory_sanity_check(self):
|
||||
if self['memory_static_min'] == 0:
|
||||
self['memory_static_min'] = self['memory_dynamic_min']
|
||||
|
||||
# If the static max is not set, let's set it to dynamic max.
|
||||
# If the static max is smaller than static min, then fix it!
|
||||
self['memory_static_max'] = max(self['memory_static_max'],
|
||||
self['memory_dynamic_max'],
|
||||
self['memory_static_min'])
|
||||
|
||||
for mem_type in ('memory_static_min', 'memory_static_max'):
|
||||
if self[mem_type] <= 0:
|
||||
raise XendConfigError('Memory value too low for %s: %d' %
|
||||
(mem_type, self[mem_type]))
|
||||
log.debug("_memory_sanity_check memory_static_min: %s, "
|
||||
"memory_static_max: %i, "
|
||||
"memory_dynamic_min: %i, "
|
||||
"memory_dynamic_max: %i",
|
||||
self["memory_static_min"],
|
||||
self["memory_static_max"],
|
||||
self["memory_dynamic_min"],
|
||||
self["memory_dynamic_max"])
|
||||
|
||||
if not self["memory_static_min"] <= self["memory_static_max"]:
|
||||
raise XendConfigError("memory_static_min must be less " \
|
||||
"than or equal to memory_static_max")
|
||||
if not self["memory_dynamic_min"] <= self["memory_dynamic_max"]:
|
||||
raise XendConfigError("memory_dynamic_min must be less " \
|
||||
"than or equal to memory_dynamic_max")
|
||||
if not self["memory_static_min"] <= self["memory_dynamic_min"]:
|
||||
raise XendConfigError("memory_static_min must be less " \
|
||||
"than or equal to memory_dynamic_min")
|
||||
if not self["memory_dynamic_max"] <= self["memory_static_max"]:
|
||||
raise XendConfigError("memory_dynamic_max must be less " \
|
||||
"than or equal to memory_static_max")
|
||||
if not self["memory_dynamic_max"] > 0:
|
||||
raise XendConfigError("memory_dynamic_max must be greater " \
|
||||
"than zero")
|
||||
if not self["memory_static_max"] > 0:
|
||||
raise XendConfigError("memory_static_max must be greater " \
|
||||
"than zero")
|
||||
|
||||
def _actions_sanity_check(self):
|
||||
for event in ['shutdown', 'reboot', 'crash']:
|
||||
@@ -392,8 +407,12 @@ class XendConfig(dict):
|
||||
self['domid'] = dominfo['domid']
|
||||
self['online_vcpus'] = dominfo['online_vcpus']
|
||||
self['vcpus_number'] = dominfo['max_vcpu_id'] + 1
|
||||
self['memory_dynamic_min'] = (dominfo['mem_kb'] + 1023)/1024
|
||||
self['memory_dynamic_max'] = (dominfo['maxmem_kb'] + 1023)/1024
|
||||
|
||||
self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
|
||||
self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
|
||||
self['memory_static_min'] = 0
|
||||
self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
|
||||
|
||||
self['cpu_time'] = dominfo['cpu_time']/1e9
|
||||
# TODO: i don't know what the security stuff expects here
|
||||
if dominfo.get('ssidref'):
|
||||
@@ -447,6 +466,13 @@ class XendConfig(dict):
|
||||
log.warn('Ignoring unrecognised value for deprecated option:'
|
||||
'restart = \'%s\'', restart)
|
||||
|
||||
# Handle memory, passed in as MiB
|
||||
|
||||
if sxp.child_value(sxp_cfg, "memory") != None:
|
||||
cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
|
||||
if sxp.child_value(sxp_cfg, "maxmem") != None:
|
||||
cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
|
||||
|
||||
# Only extract options we know about.
|
||||
extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
|
||||
extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
|
||||
@@ -616,6 +642,21 @@ class XendConfig(dict):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Lets try and handle memory correctly
|
||||
|
||||
MiB = 1024 * 1024
|
||||
|
||||
if "memory" in cfg:
|
||||
self["memory_static_min"] = 0
|
||||
self["memory_static_max"] = int(cfg["memory"]) * MiB
|
||||
self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
|
||||
self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
|
||||
|
||||
if "maxmem" in cfg:
|
||||
self["memory_static_max"] = int(cfg["maxmem"]) * MiB
|
||||
|
||||
self._memory_sanity_check()
|
||||
|
||||
def update_with(n, o):
|
||||
if not self.get(n):
|
||||
self[n] = cfg.get(o, '')
|
||||
@@ -632,13 +673,6 @@ class XendConfig(dict):
|
||||
if key in cfg:
|
||||
self['platform'][key] = cfg[key]
|
||||
|
||||
# make sure a sane maximum is set
|
||||
if self['memory_static_max'] <= 0:
|
||||
self['memory_static_max'] = self['memory_static_min']
|
||||
|
||||
self['memory_dynamic_max'] = self['memory_static_max']
|
||||
self['memory_dynamic_min'] = self['memory_static_min']
|
||||
|
||||
# set device references in the configuration
|
||||
self['devices'] = cfg.get('devices', {})
|
||||
self['console_refs'] = cfg.get('console_refs', [])
|
||||
@@ -812,6 +846,21 @@ class XendConfig(dict):
|
||||
else:
|
||||
sxpr.append([legacy, self[xenapi]])
|
||||
|
||||
MiB = 1024*1024
|
||||
|
||||
sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
|
||||
sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
|
||||
|
||||
if not legacy_only:
|
||||
sxpr.append(['memory_dynamic_min',
|
||||
int(self.get('memory_dynamic_min'))])
|
||||
sxpr.append(['memory_dynamic_max',
|
||||
int(self.get('memory_dynamic_max'))])
|
||||
sxpr.append(['memory_static_max',
|
||||
int(self.get('memory_static_max'))])
|
||||
sxpr.append(['memory_static_min',
|
||||
int(self.get('memory_static_min'))])
|
||||
|
||||
for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
|
||||
if legacy in ('domid', 'uuid'): # skip these
|
||||
continue
|
||||
@@ -820,8 +869,6 @@ class XendConfig(dict):
|
||||
|
||||
sxpr.append(['image', self.image_sxpr()])
|
||||
sxpr.append(['status', domain.state])
|
||||
sxpr.append(['memory_dynamic_min', self.get('memory_dynamic_min')])
|
||||
sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max')])
|
||||
|
||||
if domain.getDomid() is not None:
|
||||
sxpr.append(['state', self._get_old_state_string()])
|
||||
|
||||
@@ -576,7 +576,7 @@ class XendDomainInfo:
|
||||
if target <= 0:
|
||||
raise XendError('Invalid memory size')
|
||||
|
||||
self.info['memory_static_min'] = target
|
||||
self.info['memory_static_min'] = target * 1024 * 1024
|
||||
if self.domid >= 0:
|
||||
self.storeVm("memory", target)
|
||||
self.storeDom("memory/target", target << 10)
|
||||
@@ -664,6 +664,10 @@ class XendDomainInfo:
|
||||
if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG:
|
||||
xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg]
|
||||
self.info[xapiarg] = val
|
||||
elif arg == "memory":
|
||||
self.info["static_memory_min"] = val
|
||||
elif arg == "maxmem":
|
||||
self.info["static_memory_max"] = val
|
||||
else:
|
||||
self.info[arg] = val
|
||||
|
||||
@@ -780,7 +784,7 @@ class XendDomainInfo:
|
||||
'vm': self.vmpath,
|
||||
'name': self.info['name_label'],
|
||||
'console/limit': str(xoptions.get_console_limit() * 1024),
|
||||
'memory/target': str(self.info['memory_static_min'] * 1024),
|
||||
'memory/target': str(self.info['memory_dynamic_max'] / 1024),
|
||||
}
|
||||
|
||||
def f(n, v):
|
||||
@@ -864,7 +868,15 @@ class XendDomainInfo:
|
||||
xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg]
|
||||
if val != None and val != self.info[xapiarg]:
|
||||
self.info[xapiarg] = val
|
||||
changed= True
|
||||
changed = True
|
||||
elif arg == "memory":
|
||||
if val != None and val != self.info["static_memory_min"]:
|
||||
self.info["static_memory_min"] = val
|
||||
changed = True
|
||||
elif arg == "maxmem":
|
||||
if val != None and val != self.info["static_memory_max"]:
|
||||
self.info["static_memory_max"] = val
|
||||
changed = True
|
||||
|
||||
# Check whether image definition has been updated
|
||||
image_sxp = self._readVm('image')
|
||||
@@ -969,11 +981,12 @@ class XendDomainInfo:
|
||||
|
||||
def getMemoryTarget(self):
|
||||
"""Get this domain's target memory size, in KB."""
|
||||
return self.info['memory_static_min'] * 1024
|
||||
return self.info['memory_static_min'] / 1024
|
||||
|
||||
def getMemoryMaximum(self):
|
||||
"""Get this domain's maximum memory size, in KB."""
|
||||
return self.info['memory_static_max'] * 1024
|
||||
# remember, info now stores memory in bytes
|
||||
return self.info['memory_static_max'] / 1024
|
||||
|
||||
def getResume(self):
|
||||
return str(self._resume)
|
||||
@@ -1455,13 +1468,14 @@ class XendDomainInfo:
|
||||
# Use architecture- and image-specific calculations to determine
|
||||
# the various headrooms necessary, given the raw configured
|
||||
# values. maxmem, memory, and shadow are all in KiB.
|
||||
# but memory_static_max etc are all stored in bytes now.
|
||||
memory = self.image.getRequiredAvailableMemory(
|
||||
self.info['memory_static_min'] * 1024)
|
||||
self.info['memory_static_min'] / 1024)
|
||||
maxmem = self.image.getRequiredAvailableMemory(
|
||||
self.info['memory_static_max'] * 1024)
|
||||
self.info['memory_static_max'] / 1024)
|
||||
shadow = self.image.getRequiredShadowMemory(
|
||||
self.info['shadow_memory'] * 1024,
|
||||
self.info['memory_static_max'] * 1024)
|
||||
self.info['shadow_memory'] / 1024,
|
||||
self.info['memory_static_max'] / 1024)
|
||||
|
||||
log.debug("_initDomain:shadow_memory=0x%x, memory_static_max=0x%x, memory_static_min=0x%x.", self.info['shadow_memory'], self.info['memory_static_max'], self.info['memory_static_min'],)
|
||||
# Round shadow up to a multiple of a MiB, as shadow_mem_control
|
||||
@@ -1650,7 +1664,18 @@ class XendDomainInfo:
|
||||
log.exception("XendDomainInfo.destroy: xc.domain_destroy failed.")
|
||||
|
||||
from xen.xend import XendDomain
|
||||
XendDomain.instance().remove_domain(self)
|
||||
|
||||
if "transient" in self.info["other_config"]\
|
||||
and bool(self.info["other_config"]["transient"]):
|
||||
xendDomainInstance = XendDomain.instance()
|
||||
|
||||
xendDomainInstance.domains_lock.acquire()
|
||||
xendDomainInstance._refresh(refresh_shutdown = False)
|
||||
xendDomainInstance.domains_lock.release()
|
||||
|
||||
xendDomainInstance.domain_delete(self.info["name_label"])
|
||||
else:
|
||||
XendDomain.instance().remove_domain(self)
|
||||
|
||||
self.cleanupDomain()
|
||||
self._cleanup_phantom_devs(paths)
|
||||
@@ -1833,7 +1858,7 @@ class XendDomainInfo:
|
||||
# 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than
|
||||
# the minimum that Xen would allocate if no value were given.
|
||||
overhead_kb = self.info['vcpus_number'] * 1024 + \
|
||||
self.info['memory_static_max'] * 4
|
||||
(self.info['memory_static_max'] / 1024 / 1024) * 4
|
||||
overhead_kb = ((overhead_kb + 1023) / 1024) * 1024
|
||||
# The domain might already have some shadow memory
|
||||
overhead_kb -= xc.shadow_mem_control(self.domid) * 1024
|
||||
@@ -1899,6 +1924,11 @@ class XendDomainInfo:
|
||||
if self._infoIsSet(info_key):
|
||||
to_store[key] = str(self.info[info_key])
|
||||
|
||||
if self._infoIsSet("static_memory_min"):
|
||||
to_store["memory"] = str(self.info["static_memory_min"])
|
||||
if self._infoIsSet("static_memory_max"):
|
||||
to_store["maxmem"] = str(self.info["static_memory_max"])
|
||||
|
||||
image_sxpr = self.info.image_sxpr()
|
||||
if image_sxpr:
|
||||
to_store['image'] = sxp.to_string(image_sxpr)
|
||||
|
||||
@@ -530,7 +530,8 @@ class XendNode:
|
||||
info['cores_per_socket'] *
|
||||
info['threads_per_core'])
|
||||
info['cpu_mhz'] = info['cpu_khz'] / 1000
|
||||
# physinfo is in KiB
|
||||
|
||||
# physinfo is in KiB, need it in MiB
|
||||
info['total_memory'] = info['total_memory'] / 1024
|
||||
info['free_memory'] = info['free_memory'] / 1024
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<!ENTITY % HTMLlat1 PUBLIC
|
||||
"-//W3C//ENTITIES Latin 1 for XHTML//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
|
||||
%HTMLlat1;
|
||||
<!ENTITY % HTMLsymbol PUBLIC
|
||||
"-//W3C//ENTITIES Symbols for XHTML//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent">
|
||||
%HTMLsymbol;
|
||||
<!ENTITY % HTMLspecial PUBLIC
|
||||
"-//W3C//ENTITIES Special for XHTML//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent">
|
||||
%HTMLspecial;
|
||||
<!-- a Uniform Resource Identifier, see [RFC2396] -->
|
||||
<!ENTITY % URI "CDATA">
|
||||
<!ENTITY % NAMEID "name ID #REQUIRED">
|
||||
<!ENTITY % CRASH_BEHAVIOUR "( destroy
|
||||
| coredump_and_destroy
|
||||
| restart
|
||||
| coredump_and_restart
|
||||
| preserve
|
||||
| rename_restart )">
|
||||
<!ENTITY % NORMAL_EXIT "( destroy | restart )">
|
||||
<!ENTITY % VDI_TYPE "( system
|
||||
| user
|
||||
| ephemeral
|
||||
| suspend
|
||||
| crashdump )">
|
||||
|
||||
<!ELEMENT xm (vm*,
|
||||
vdi*)>
|
||||
|
||||
<!ELEMENT version (#PCDATA)>
|
||||
|
||||
<!ELEMENT vm (name,
|
||||
version,
|
||||
(pv|hvm),
|
||||
memory,
|
||||
vbd*,
|
||||
vif*,
|
||||
vcpu_param*,
|
||||
other_config*)>
|
||||
<!ATTLIST vm is_a_template CDATA #REQUIRED
|
||||
auto_power_on CDATA #REQUIRED
|
||||
vcpus_max CDATA #REQUIRED
|
||||
vcpus_at_startup CDATA #REQUIRED
|
||||
actions_after_shutdown %NORMAL_EXIT; #REQUIRED
|
||||
actions_after_reboot %NORMAL_EXIT; #REQUIRED
|
||||
actions_after_crash %CRASH_BEHAVIOUR; #REQUIRED
|
||||
platform_std_VGA CDATA #REQUIRED
|
||||
platform_serial CDATA #REQUIRED
|
||||
platform_localtime CDATA #REQUIRED
|
||||
platform_clock_offet CDATA #REQUIRED
|
||||
platform_enable_audio CDATA #REQUIRED
|
||||
PCI_bus CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT memory EMPTY>
|
||||
<!ATTLIST memory static_min CDATA #REQUIRED
|
||||
static_max CDATA #REQUIRED
|
||||
dynamic_min CDATA #REQUIRED
|
||||
dynamic_max CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT vbd (qos_algorithm_param*)>
|
||||
<!ATTLIST vbd %NAMEID;
|
||||
mode (RO | RW) #REQUIRED
|
||||
vdi IDREF #REQUIRED
|
||||
device CDATA #REQUIRED
|
||||
bootable CDATA #REQUIRED
|
||||
type (CD | disk) #REQUIRED
|
||||
qos_algorithm_type CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT vif (qos_algorithm_param*)>
|
||||
<!ATTLIST vif %NAMEID;
|
||||
mac CDATA #REQUIRED
|
||||
mtu CDATA #REQUIRED
|
||||
device CDATA #REQUIRED
|
||||
qos_algorithm_type CDATA #REQUIRED
|
||||
bridge CDATA #IMPLIED
|
||||
network CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT pv EMPTY>
|
||||
<!ATTLIST pv kernel CDATA #REQUIRED
|
||||
bootloader CDATA #REQUIRED
|
||||
ramdisk CDATA #REQUIRED
|
||||
args CDATA #REQUIRED
|
||||
bootloader_args CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT hvm (boot_param*)>
|
||||
<!ATTLIST hvm boot_policy CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT boot_param EMPTY>
|
||||
<!ATTLIST boot_param key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT vdi (name)>
|
||||
<!ATTLIST vdi %NAMEID;
|
||||
src %URI; #REQUIRED
|
||||
type %VDI_TYPE; #REQUIRED
|
||||
size CDATA #REQUIRED
|
||||
shareable CDATA #REQUIRED
|
||||
read_only CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT name (label,
|
||||
description)>
|
||||
|
||||
<!ELEMENT label (#PCDATA)>
|
||||
<!ELEMENT description (#PCDATA)>
|
||||
|
||||
<!ELEMENT vcpu_param EMPTY>
|
||||
<!ATTLIST vcpu_param key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT other_config EMPTY>
|
||||
<!ATTLIST other_config key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT qos_algorithm_param EMPTY>
|
||||
<!ATTLIST qos_algorithm_param key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED>
|
||||
@@ -28,12 +28,14 @@ import time
|
||||
import xmlrpclib
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend import PrettyPrint
|
||||
from xen.xend import PrettyPrint as SXPPrettyPrint
|
||||
from xen.xend import osdep
|
||||
import xen.xend.XendClient
|
||||
from xen.xend.XendBootloader import bootloader
|
||||
from xen.util import blkif
|
||||
from xen.util import security
|
||||
from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
|
||||
from xen.xm.xenapi_create import sxp2xml, xenapi_create
|
||||
|
||||
from xen.xm.opts import *
|
||||
|
||||
@@ -98,6 +100,11 @@ gopts.opt('dryrun', short='n',
|
||||
use="Dry run - prints the resulting configuration in SXP but "
|
||||
"does not create the domain.")
|
||||
|
||||
gopts.opt('xmldryrun', short='x',
|
||||
fn=set_true, default=0,
|
||||
use="XML dry run - prints the resulting configuration in XML but "
|
||||
"does not create the domain.")
|
||||
|
||||
gopts.opt('paused', short='p',
|
||||
fn=set_true, default=0,
|
||||
use='Leave the domain paused after it is created.')
|
||||
@@ -1241,34 +1248,57 @@ def main(argv):
|
||||
except IOError, exn:
|
||||
raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
sxp2xml_inst = sxp2xml()
|
||||
doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
|
||||
|
||||
if opts.vals.dryrun:
|
||||
PrettyPrint.prettyprint(config)
|
||||
SXPPrettyPrint.prettyprint(config)
|
||||
|
||||
if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
|
||||
from xml.dom.ext import PrettyPrint as XMLPrettyPrint
|
||||
XMLPrettyPrint(doc)
|
||||
|
||||
if opts.vals.dryrun or opts.vals.xmldryrun:
|
||||
return
|
||||
|
||||
if opts.vals.console_autoconnect:
|
||||
do_console(sxp.child_value(config, 'name', -1))
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
xenapi_create_inst = xenapi_create()
|
||||
vm_refs = xenapi_create_inst.create(document = doc)
|
||||
|
||||
map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
|
||||
else:
|
||||
if not create_security_check(config):
|
||||
raise security.ACMError('Security Configuration prevents domain from starting')
|
||||
else:
|
||||
if opts.vals.console_autoconnect:
|
||||
cpid = os.fork()
|
||||
if cpid != 0:
|
||||
for i in range(10):
|
||||
# Catch failure of the create process
|
||||
time.sleep(1)
|
||||
(p, rv) = os.waitpid(cpid, os.WNOHANG)
|
||||
if os.WIFEXITED(rv):
|
||||
if os.WEXITSTATUS(rv) != 0:
|
||||
sys.exit(os.WEXITSTATUS(rv))
|
||||
try:
|
||||
# Acquire the console of the created dom
|
||||
name = sxp.child_value(config, 'name', -1)
|
||||
dom = server.xend.domain(name)
|
||||
domid = int(sxp.child_value(dom, 'domid', '-1'))
|
||||
console.execConsole(domid)
|
||||
except:
|
||||
pass
|
||||
print("Could not start console\n");
|
||||
sys.exit(0)
|
||||
dom = make_domain(opts, config)
|
||||
|
||||
raise security.ACMError(
|
||||
'Security Configuration prevents domain from starting')
|
||||
dom = make_domain(opts, config)
|
||||
|
||||
def do_console(domain_name):
|
||||
cpid = os.fork()
|
||||
if cpid != 0:
|
||||
for i in range(10):
|
||||
# Catch failure of the create process
|
||||
time.sleep(1)
|
||||
(p, rv) = os.waitpid(cpid, os.WNOHANG)
|
||||
if os.WIFEXITED(rv):
|
||||
if os.WEXITSTATUS(rv) != 0:
|
||||
sys.exit(os.WEXITSTATUS(rv))
|
||||
try:
|
||||
# Acquire the console of the created dom
|
||||
if serverType == SERVER_XEN_API:
|
||||
domid = server.xenapi.VM.get_domid(
|
||||
get_single_vm(domain_name))
|
||||
else:
|
||||
dom = server.xend.domain(name)
|
||||
domid = int(sxp.child_value(dom, 'domid', '-1'))
|
||||
console.execConsole(domid)
|
||||
except:
|
||||
pass
|
||||
print("Could not start console\n");
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv)
|
||||
@@ -22,6 +22,9 @@ from xen.xend import PrettyPrint
|
||||
from xen.xend import sxp
|
||||
from xen.xend import XendClient
|
||||
|
||||
from xen.xm.main import serverType, SERVER_XEN_API
|
||||
from xen.xm.xenapi_create import *
|
||||
|
||||
from opts import *
|
||||
from create import *
|
||||
|
||||
@@ -65,7 +68,15 @@ def main(argv):
|
||||
|
||||
if opts.vals.dryrun:
|
||||
PrettyPrint.prettyprint(config)
|
||||
else:
|
||||
return
|
||||
|
||||
if serverType == SERVER_XEN_API:
|
||||
sxp2xml_inst = sxp2xml()
|
||||
doc = sxp2xml_inst.convert_sxp_to_xml(config)
|
||||
|
||||
xenapi_create_inst = xenapi_create()
|
||||
vm_refs = xenapi_create_inst.create(document = doc)
|
||||
else:
|
||||
make_unstarted_domain(opts, config)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -0,0 +1,634 @@
|
||||
#!/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) 2007 Tom Wilkie <tom.wilkie@gmail.com>
|
||||
#============================================================================
|
||||
"""Domain creation using new XenAPI
|
||||
"""
|
||||
|
||||
from xen.xm.main import server
|
||||
from xml.dom.minidom import parse, getDOMImplementation
|
||||
from xml.dom.ext import PrettyPrint
|
||||
from xml.parsers.xmlproc import xmlproc, xmlval, xmldtd
|
||||
from xen.xend import sxp
|
||||
from xen.xend.XendAPIConstants import XEN_API_ON_NORMAL_EXIT, \
|
||||
XEN_API_ON_CRASH_BEHAVIOUR
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
|
||||
def log(_, msg):
|
||||
#print "> " + msg
|
||||
pass
|
||||
|
||||
DEBUG = 0
|
||||
|
||||
def get_name_label(node):
|
||||
name_node = node.getElementsByTagName("name")[0]
|
||||
label_node = name_node.getElementsByTagName("label")[0]
|
||||
return " ".join([child.nodeValue for child in label_node.childNodes])
|
||||
|
||||
def get_name_description(node):
|
||||
name_node = node.getElementsByTagName("name")[0]
|
||||
description_node = name_node.getElementsByTagName("description")[0]
|
||||
return " ".join([child.nodeValue for child in description_node.childNodes])
|
||||
|
||||
def get_text_in_child_node(node, child):
|
||||
tag_node = node.getElementsByTagName(child)[0]
|
||||
return tag_node.nodeValue
|
||||
|
||||
def get_child_node_attribute(node, child, attribute):
|
||||
tag_node = node.getElementsByTagName(child)[0]
|
||||
return tag_node.attributes[attribute].value
|
||||
|
||||
def get_child_nodes_as_dict(node, child_name,
|
||||
key_attribute_name,
|
||||
value_attribute_name):
|
||||
return dict([(child.attributes[key_attribute_name].value,
|
||||
child.attributes[value_attribute_name].value)
|
||||
for child in node.getElementsByTagName(child_name)])
|
||||
|
||||
def try_quietly(fn, *args):
|
||||
try:
|
||||
return fn(*args)
|
||||
except:
|
||||
return None
|
||||
|
||||
class xenapi_create:
|
||||
|
||||
def __init__(self):
|
||||
self.DEFAULT_STORAGE_REPOSITORY = [sr_ref
|
||||
for sr_ref in server.xenapi.SR.get_all()
|
||||
if server.xenapi.SR.get_type(sr_ref) == "local"][0]
|
||||
|
||||
self.dtd = "/usr/lib/python/xen/xm/create.dtd"
|
||||
|
||||
def create(self, filename=None, document=None):
|
||||
"""
|
||||
Create a domain from an XML file or DOM tree
|
||||
"""
|
||||
if filename is not None:
|
||||
self.check_dtd(file)
|
||||
document = parse(file)
|
||||
elif document is not None:
|
||||
self.check_dom_against_dtd(document)
|
||||
|
||||
self.check_doc(document)
|
||||
|
||||
vdis = document.getElementsByTagName("vdi")
|
||||
vdi_refs_dict = self.create_vdis(vdis)
|
||||
|
||||
try:
|
||||
vms = document.getElementsByTagName("vm")
|
||||
return self.create_vms(vms, vdi_refs_dict)
|
||||
except Exception, exn:
|
||||
try_quietly(self.cleanup_vdis(vdi_refs_dict))
|
||||
raise exn
|
||||
|
||||
# Methods to check xml file
|
||||
# try to use dtd to check where possible
|
||||
def check_dtd(self, file):
|
||||
"""
|
||||
Check file against DTD.
|
||||
Use this if possible as it gives nice
|
||||
error messages
|
||||
"""
|
||||
dtd = xmldtd.load_dtd(self.dtd)
|
||||
parser = xmlproc.XMLProcessor()
|
||||
parser.set_application(xmlval.ValidatingApp(dtd, parser))
|
||||
parser.dtd = dtd
|
||||
parser.ent = dtd
|
||||
parser.parse_resource(file)
|
||||
|
||||
def check_dom_against_dtd(self, dom):
|
||||
"""
|
||||
Check DOM again DTD.
|
||||
Doesn't give as nice error messages.
|
||||
(no location info)
|
||||
"""
|
||||
dtd = xmldtd.load_dtd(self.dtd)
|
||||
app = xmlval.ValidatingApp(dtd, self)
|
||||
app.set_locator(self)
|
||||
self.dom2sax(dom, app)
|
||||
|
||||
# Get errors back from ValidatingApp
|
||||
def report_error(self, number, args=None):
|
||||
self.errors = xmlproc.errors.english
|
||||
try:
|
||||
msg = self.errors[number]
|
||||
if args != None:
|
||||
msg = msg % args
|
||||
except KeyError:
|
||||
msg = self.errors[4002] % number # Unknown err msg :-)
|
||||
print msg
|
||||
sys.exit(-1)
|
||||
|
||||
# Here for compatibility with ValidatingApp
|
||||
def get_line(self):
|
||||
return -1
|
||||
|
||||
def get_column(self):
|
||||
return -1
|
||||
|
||||
def dom2sax(self, dom, app):
|
||||
"""
|
||||
Take a dom tree and tarverse it,
|
||||
issuing SAX calls to app.
|
||||
"""
|
||||
for child in dom.childNodes:
|
||||
if child.nodeType == child.TEXT_NODE:
|
||||
data = child.nodeValue
|
||||
app.handle_data(data, 0, len(data))
|
||||
else:
|
||||
app.handle_start_tag(
|
||||
child.nodeName,
|
||||
self.attrs_to_dict(child.attributes))
|
||||
self.dom2sax(child, app)
|
||||
app.handle_end_tag(child.nodeName)
|
||||
|
||||
def attrs_to_dict(self, attrs):
|
||||
return dict(attrs.items())
|
||||
|
||||
#
|
||||
# Checks which cannot be done with dtd
|
||||
#
|
||||
def check_doc(self, doc):
|
||||
vms = doc.getElementsByTagName("vm")
|
||||
self.check_vms(vms)
|
||||
|
||||
def check_vms(self, vms):
|
||||
map(self.check_vm, vms)
|
||||
|
||||
def check_vm(self, vm):
|
||||
vifs = vm.getElementsByTagName("vif")
|
||||
self.check_vifs(vifs)
|
||||
|
||||
def check_vifs(self, vifs):
|
||||
map(self.check_vif, vifs)
|
||||
|
||||
def check_vif(self, vif):
|
||||
"""
|
||||
Check that the vif has
|
||||
either a bridge or network
|
||||
name but not both
|
||||
"""
|
||||
if "bridge" in vif.attributes.keys() \
|
||||
and "network" in vif.attributes.keys():
|
||||
raise "You cannot specify both a bridge and\
|
||||
a network name."
|
||||
|
||||
# Cleanup methods here
|
||||
def cleanup_vdis(self, vdi_refs_dict):
|
||||
map(self.cleanup_vdi, vdi_refs_dict.values())
|
||||
|
||||
def cleanup_vdi(self, vdi_ref):
|
||||
server.xenapi.VDI.destroy(vdi_ref)
|
||||
|
||||
def cleanup_vms(self, vm_refs):
|
||||
map(self.cleanup_vm, vm_refs)
|
||||
|
||||
def cleanup_vm(self, vm_ref):
|
||||
server.xenapi.VM.destroy(vm_ref)
|
||||
|
||||
# Create methods here
|
||||
def create_vdis(self, vdis):
|
||||
log(DEBUG, "create_vdis")
|
||||
return dict(map(self.create_vdi, vdis))
|
||||
|
||||
def create_vdi(self, vdi):
|
||||
log(DEBUG, "create_vdi")
|
||||
|
||||
vdi_record = {
|
||||
"name_label": get_name_label(vdi),
|
||||
"name_description": get_name_description(vdi),
|
||||
"SR": self.DEFAULT_STORAGE_REPOSITORY,
|
||||
"virtual_size": vdi.attributes["size"].value,
|
||||
"type": vdi.attributes["type"].value,
|
||||
"shareable": vdi.attributes["shareable"].value,
|
||||
"read_only": vdi.attributes["read_only"].value,
|
||||
"other_config": {"location":
|
||||
vdi.attributes["src"].value}
|
||||
}
|
||||
|
||||
key = vdi.attributes["name"].value
|
||||
value = server.xenapi.VDI.create(vdi_record)
|
||||
|
||||
return (key, value)
|
||||
|
||||
def create_vms(self, vms, vdis):
|
||||
log(DEBUG, "create_vms")
|
||||
return map(lambda vm: self.create_vm(vm, vdis), vms)
|
||||
|
||||
def create_vm(self, vm, vdis):
|
||||
log(DEBUG, "create_vm")
|
||||
|
||||
vm_record = {
|
||||
"name_label":
|
||||
get_name_label(vm),
|
||||
"name_description":
|
||||
get_name_description(vm),
|
||||
"user_version":
|
||||
get_text_in_child_node(vm, "version"),
|
||||
"is_a_template":
|
||||
vm.attributes["is_a_template"].value,
|
||||
"auto_power_on":
|
||||
vm.attributes["auto_power_on"].value,
|
||||
"memory_static_max":
|
||||
get_child_node_attribute(vm, "memory", "static_max"),
|
||||
"memory_static_min":
|
||||
get_child_node_attribute(vm, "memory", "static_min"),
|
||||
"memory_dynamic_max":
|
||||
get_child_node_attribute(vm, "memory", "dynamic_max"),
|
||||
"memory_dynamic_min":
|
||||
get_child_node_attribute(vm, "memory", "dynamic_min"),
|
||||
"vcpus_params":
|
||||
get_child_nodes_as_dict(vm, "vcpu_param", "key", "value"),
|
||||
"vcpus_max":
|
||||
vm.attributes["vcpus_max"].value,
|
||||
"vcpus_at_startup":
|
||||
vm.attributes["vcpus_at_startup"].value,
|
||||
"actions_after_shutdown":
|
||||
vm.attributes["actions_after_shutdown"].value,
|
||||
"actions_after_reboot":
|
||||
vm.attributes["actions_after_reboot"].value,
|
||||
"actions_after_crash":
|
||||
vm.attributes["actions_after_crash"].value,
|
||||
"platform_std_VGA":
|
||||
vm.attributes["platform_std_VGA"].value,
|
||||
"platform_serial":
|
||||
vm.attributes["platform_serial"].value,
|
||||
"platform_localtime":
|
||||
vm.attributes["platform_localtime"].value,
|
||||
"platform_clock_offet":
|
||||
vm.attributes["platform_clock_offet"].value,
|
||||
"platform_enable_audio":
|
||||
vm.attributes["platform_enable_audio"].value,
|
||||
"PCI_bus":
|
||||
vm.attributes["platform_enable_audio"].value,
|
||||
"other_config":
|
||||
get_child_nodes_as_dict(vm, "other_config", "key", "value")
|
||||
}
|
||||
|
||||
if len(vm.getElementsByTagName("pv")) > 0:
|
||||
vm_record.update({
|
||||
"PV_bootloader":
|
||||
get_child_node_attribute(vm, "pv", "bootloader"),
|
||||
"PV_kernel":
|
||||
get_child_node_attribute(vm, "pv", "kernel"),
|
||||
"PV_ramdisk":
|
||||
get_child_node_attribute(vm, "pv", "ramdisk"),
|
||||
"PV_args":
|
||||
get_child_node_attribute(vm, "pv", "args"),
|
||||
"PV_bootloader_args":
|
||||
get_child_node_attribute(vm, "pv", "bootloader_args")
|
||||
})
|
||||
else:
|
||||
hvm = vm.getElementsByTagName("hvm")[0]
|
||||
vm_record.update({
|
||||
"HVM_boot_policy":
|
||||
get_child_node_attribute(vm, "hvm", "boot_policy"),
|
||||
"HVM_boot_params":
|
||||
get_child_nodes_as_dict(hvm, "boot_params", "key", "value")
|
||||
})
|
||||
try:
|
||||
vm_ref = server.xenapi.VM.create(vm_record)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
sys.exit(-1)
|
||||
|
||||
# Now create vbds
|
||||
|
||||
vbds = vm.getElementsByTagName("vbd")
|
||||
|
||||
self.create_vbds(vm_ref, vbds, vdis)
|
||||
|
||||
# Now create vifs
|
||||
|
||||
vifs = vm.getElementsByTagName("vif")
|
||||
|
||||
self.create_vifs(vm_ref, vifs)
|
||||
|
||||
return vm_ref
|
||||
|
||||
def create_vbds(self, vm_ref, vbds, vdis):
|
||||
log(DEBUG, "create_vbds")
|
||||
return map(lambda vbd: self.create_vbd(vm_ref, vbd, vdis), vbds)
|
||||
|
||||
def create_vbd(self, vm_ref, vbd, vdis):
|
||||
log(DEBUG, "create_vbd")
|
||||
|
||||
vbd_record = {
|
||||
"VM":
|
||||
vm_ref,
|
||||
"VDI":
|
||||
vdis[vbd.attributes["vdi"].value],
|
||||
"device":
|
||||
vbd.attributes["device"].value,
|
||||
"bootable":
|
||||
vbd.attributes["bootable"].value,
|
||||
"mode":
|
||||
vbd.attributes["mode"].value,
|
||||
"type":
|
||||
vbd.attributes["type"].value,
|
||||
"qos_algorithm_type":
|
||||
vbd.attributes["qos_algorithm_type"].value,
|
||||
"qos_algorithm_params":
|
||||
get_child_nodes_as_dict(vbd,
|
||||
"qos_algorithm_param", "key", "value")
|
||||
}
|
||||
|
||||
return server.xenapi.VBD.create(vbd_record)
|
||||
|
||||
def create_vifs(self, vm_ref, vifs):
|
||||
log(DEBUG, "create_vifs")
|
||||
return map(lambda vif: self.create_vif(vm_ref, vif), vifs)
|
||||
|
||||
def create_vif(self, vm_ref, vif):
|
||||
log(DEBUG, "create_vif")
|
||||
|
||||
if "bridge" in vif.attributes.keys():
|
||||
raise "Not allowed to add by bridge just yet"
|
||||
elif "network" in vif.attributes.keys():
|
||||
network = [network_ref
|
||||
for network_ref in server.xenapi.network.get_all()
|
||||
if server.xenapi.network.get_name_label(network_ref)
|
||||
== vif.attributes["network"].value][0]
|
||||
else:
|
||||
network = self._get_network_ref()
|
||||
|
||||
vif_record = {
|
||||
"device":
|
||||
vif.attributes["device"].value,
|
||||
"network":
|
||||
network,
|
||||
"VM":
|
||||
vm_ref,
|
||||
"MAC":
|
||||
vif.attributes["mac"].value,
|
||||
"MTU":
|
||||
vif.attributes["mtu"].value,
|
||||
"qos_algorithm_type":
|
||||
vif.attributes["qos_algorithm_type"].value,
|
||||
"qos_algorithm_params":
|
||||
get_child_nodes_as_dict(vif,
|
||||
"qos_algorithm_param", "key", "value")
|
||||
}
|
||||
|
||||
return server.xenapi.VIF.create(vif_record)
|
||||
|
||||
_network_refs = []
|
||||
|
||||
def _get_network_ref(self):
|
||||
try:
|
||||
return self._network_refs.pop(0)
|
||||
except IndexError:
|
||||
self._network_refs = server.xenapi.network.get_all()
|
||||
return self._network_refs.pop(0)
|
||||
|
||||
def get_child_by_name(exp, childname, default = None):
|
||||
try:
|
||||
return [child for child in sxp.children(exp)
|
||||
if child[0] == childname][0][1]
|
||||
except:
|
||||
return default
|
||||
|
||||
# Convert old sxp into new xml
|
||||
|
||||
class sxp2xml:
|
||||
|
||||
def convert_sxp_to_xml(self, config, transient=False):
|
||||
|
||||
devices = [child for child in sxp.children(config)
|
||||
if len(child) > 0 and child[0] == "device"]
|
||||
|
||||
vbds_sxp = map(lambda x: x[1], [device for device in devices
|
||||
if device[1][0] == "vbd"])
|
||||
|
||||
vifs_sxp = map(lambda x: x[1], [device for device in devices
|
||||
if device[1][0] == "vif"])
|
||||
# Create XML Document
|
||||
|
||||
impl = getDOMImplementation()
|
||||
|
||||
document = impl.createDocument(None, "xm", None)
|
||||
|
||||
# Lets make the VM tag..
|
||||
|
||||
vm = document.createElement("vm")
|
||||
|
||||
# Some string compatibility
|
||||
|
||||
actions_after_shutdown \
|
||||
= get_child_by_name(config, "on_poweroff", "destroy")
|
||||
actions_after_reboot \
|
||||
= get_child_by_name(config, "on_reboot", "restart")
|
||||
actions_after_crash \
|
||||
= get_child_by_name(config, "on_crash", "restart")
|
||||
|
||||
def conv_chk(val, vals):
|
||||
val.replace("-", "_")
|
||||
if val not in vals:
|
||||
raise "Invalid value: " + val
|
||||
else:
|
||||
return val
|
||||
|
||||
actions_after_shutdown = conv_chk(actions_after_shutdown,\
|
||||
XEN_API_ON_NORMAL_EXIT)
|
||||
actions_after_reboot = conv_chk(actions_after_reboot, \
|
||||
XEN_API_ON_NORMAL_EXIT)
|
||||
actions_after_crash = conv_chk(actions_after_crash, \
|
||||
XEN_API_ON_CRASH_BEHAVIOUR)
|
||||
# Flesh out tag attributes
|
||||
|
||||
vm.attributes["is_a_template"] = "false"
|
||||
vm.attributes["auto_power_on"] = "false"
|
||||
vm.attributes["actions_after_shutdown"] \
|
||||
= actions_after_shutdown
|
||||
vm.attributes["actions_after_reboot"] \
|
||||
= actions_after_reboot
|
||||
vm.attributes["actions_after_crash"] \
|
||||
= actions_after_crash
|
||||
vm.attributes["platform_std_VGA"] = "false"
|
||||
vm.attributes["platform_serial"] = ""
|
||||
vm.attributes["platform_localtime"] = ""
|
||||
vm.attributes["platform_clock_offet"] = ""
|
||||
vm.attributes["platform_enable_audio"] = ""
|
||||
vm.attributes["PCI_bus"] = ""
|
||||
|
||||
vm.attributes["vcpus_max"] \
|
||||
= str(get_child_by_name(config, "vcpus", 1))
|
||||
vm.attributes["vcpus_at_startup"] \
|
||||
= str(get_child_by_name(config, "vcpus", 1))
|
||||
|
||||
# Make the name tag
|
||||
|
||||
vm.appendChild(self.make_name_tag(
|
||||
get_child_by_name(config, "name"), document))
|
||||
|
||||
# Make version tag
|
||||
|
||||
version = document.createElement("version")
|
||||
version.appendChild(document.createTextNode("1.0"))
|
||||
vm.appendChild(version)
|
||||
|
||||
# Make pv or hvm tag
|
||||
|
||||
image = get_child_by_name(config, "image")
|
||||
|
||||
if image[0] == "linux":
|
||||
pv = document.createElement("pv")
|
||||
pv.attributes["kernel"] \
|
||||
= get_child_by_name(image, "kernel", "")
|
||||
pv.attributes["bootloader"] = ""
|
||||
pv.attributes["ramdisk"] \
|
||||
= get_child_by_name(image, "ramdisk", "")
|
||||
pv.attributes["args"] \
|
||||
= "root=" + get_child_by_name(image, "root", "") \
|
||||
+ " " + get_child_by_name(image, "args", "")
|
||||
pv.attributes["bootloader_args"] = ""
|
||||
|
||||
vm.appendChild(pv)
|
||||
elif image[0] == "hvm":
|
||||
hvm = document.createElement("hvm")
|
||||
hvm.attributes["boot_policy"] = ""
|
||||
|
||||
vm.appendChild(hvm)
|
||||
|
||||
# Make memory tag
|
||||
|
||||
memory = document.createElement("memory")
|
||||
|
||||
memory_str = str(int(
|
||||
get_child_by_name(config, "memory"))*1024*1024)
|
||||
|
||||
memory.attributes["static_min"] = memory_str
|
||||
memory.attributes["static_max"] = memory_str
|
||||
memory.attributes["dynamic_min"] = memory_str
|
||||
memory.attributes["dynamic_max"] = memory_str
|
||||
|
||||
vm.appendChild(memory)
|
||||
|
||||
# And now the vbds
|
||||
|
||||
vbds = map(lambda vbd: self.extract_vbd(vbd, document), vbds_sxp)
|
||||
|
||||
map(vm.appendChild, vbds)
|
||||
|
||||
# And now the vifs
|
||||
|
||||
vifs = map(lambda vif: self.extract_vif(vif, document), vifs_sxp)
|
||||
|
||||
map(vm.appendChild, vifs)
|
||||
|
||||
# transient?
|
||||
|
||||
if transient:
|
||||
other_config = document.createElement("other_config")
|
||||
other_config.attributes["key"] = "transient"
|
||||
other_config.attributes["value"] = "True"
|
||||
vm.appendChild(other_config)
|
||||
|
||||
# Add it to doc_root
|
||||
|
||||
document.documentElement.appendChild(vm)
|
||||
|
||||
# We want to pull out vdis
|
||||
|
||||
vdis = map(lambda vdb: self.extract_vdi(vdb, document), vbds_sxp)
|
||||
|
||||
map(document.documentElement.appendChild, vdis)
|
||||
|
||||
return document
|
||||
|
||||
def make_name_tag(self, label_text, document):
|
||||
name = document.createElement("name")
|
||||
|
||||
label = document.createElement("label")
|
||||
label.appendChild(document.createTextNode(str(label_text)))
|
||||
name.appendChild(label)
|
||||
|
||||
description = document.createElement("description")
|
||||
description.appendChild(document.createTextNode(" "))
|
||||
name.appendChild(description)
|
||||
|
||||
return name
|
||||
|
||||
def extract_vbd(self, vbd_sxp, document):
|
||||
src = get_child_by_name(vbd_sxp, "uname")
|
||||
name = str(src.__hash__())
|
||||
|
||||
vbd = document.createElement("vbd")
|
||||
|
||||
vbd.attributes["name"] = "vdb" + name
|
||||
vbd.attributes["vdi"] = "vdi" + name
|
||||
vbd.attributes["mode"] \
|
||||
= get_child_by_name(vbd_sxp, "mode") != "w" \
|
||||
and "RO" or "RW"
|
||||
vbd.attributes["device"] \
|
||||
= get_child_by_name(vbd_sxp, "dev")
|
||||
vbd.attributes["bootable"] = "1"
|
||||
vbd.attributes["type"] = "disk"
|
||||
vbd.attributes["qos_algorithm_type"] = ""
|
||||
|
||||
return vbd
|
||||
|
||||
def extract_vdi(self, vbd_sxp, document):
|
||||
src = get_child_by_name(vbd_sxp, "uname")
|
||||
name = "vdi" + str(src.__hash__())
|
||||
path = src[src.find(":")+1:]
|
||||
|
||||
vdi = document.createElement("vdi")
|
||||
|
||||
vdi.attributes["src"] = src
|
||||
vdi.attributes["read_only"] \
|
||||
= (get_child_by_name(vbd_sxp, "mode") != "w") \
|
||||
and "true" or "false"
|
||||
vdi.attributes["size"] \
|
||||
= str(os.path.getsize(path))
|
||||
vdi.attributes["type"] = "system"
|
||||
vdi.attributes["shareable"] = "false"
|
||||
vdi.attributes["name"] = name
|
||||
|
||||
vdi.appendChild(self.make_name_tag(name, document))
|
||||
|
||||
return vdi
|
||||
|
||||
def extract_vif(self, vif_sxp, document):
|
||||
|
||||
vif = document.createElement("vif")
|
||||
|
||||
dev = get_child_by_name(vif_sxp, "vifname", "eth0")
|
||||
|
||||
vif.attributes["name"] \
|
||||
= "vif" + str(dev.__hash__())
|
||||
vif.attributes["mac"] \
|
||||
= get_child_by_name(vif_sxp, "mac", "")
|
||||
vif.attributes["mtu"] \
|
||||
= get_child_by_name(vif_sxp, "mtu", "")
|
||||
vif.attributes["device"] = dev
|
||||
vif.attributes["qos_algorithm_type"] = ""
|
||||
|
||||
if get_child_by_name(vif_sxp, "bridge") is not None:
|
||||
vif.attributes["bridge"] \
|
||||
= get_child_by_name(vif_sxp, "bridge")
|
||||
|
||||
return vif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||