[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Support xm create through the Xen-API.



# HG changeset patch
# User Ewan Mellor <ewan@xxxxxxxxxxxxx>
# Date 1174175945 0
# Node ID 6b2875302558c69873cd63cf1e64d940788a5733
# Parent  cfb265b93b2d508a51d058fb19e279bba09a00f1
Support xm create through the Xen-API.

Signed-off-by: Tom Wilkie <tom.wilkie@xxxxxxxxx>
---
 tools/python/xen/xend/XendConfig.py     |  105 +++--
 tools/python/xen/xend/XendDomainInfo.py |   52 ++
 tools/python/xen/xend/XendNode.py       |    3 
 tools/python/xen/xm/create.dtd          |  118 +++++
 tools/python/xen/xm/create.py           |   82 ++--
 tools/python/xen/xm/new.py              |   13 
 tools/python/xen/xm/xenapi_create.py    |  634 ++++++++++++++++++++++++++++++++
 7 files changed, 939 insertions(+), 68 deletions(-)

diff -r cfb265b93b2d -r 6b2875302558 tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Sat Mar 17 23:57:17 2007 +0000
+++ b/tools/python/xen/xend/XendConfig.py       Sat Mar 17 23:59:05 2007 +0000
@@ -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, '')
@@ -631,13 +672,6 @@ class XendConfig(dict):
         for key in XENAPI_PLATFORM_CFG:
             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', {})
@@ -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()])
diff -r cfb265b93b2d -r 6b2875302558 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Sat Mar 17 23:57:17 2007 +0000
+++ b/tools/python/xen/xend/XendDomainInfo.py   Sat Mar 17 23:59:05 2007 +0000
@@ -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
@@ -1898,6 +1923,11 @@ class XendDomainInfo:
             info_key = XendConfig.LEGACY_CFG_TO_XENAPI_CFG.get(key, key)
             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:
diff -r cfb265b93b2d -r 6b2875302558 tools/python/xen/xend/XendNode.py
--- a/tools/python/xen/xend/XendNode.py Sat Mar 17 23:57:17 2007 +0000
+++ b/tools/python/xen/xend/XendNode.py Sat Mar 17 23:59:05 2007 +0000
@@ -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
 
diff -r cfb265b93b2d -r 6b2875302558 tools/python/xen/xm/create.dtd
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xm/create.dtd    Sat Mar 17 23:59:05 2007 +0000
@@ -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>
diff -r cfb265b93b2d -r 6b2875302558 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Sat Mar 17 23:57:17 2007 +0000
+++ b/tools/python/xen/xm/create.py     Sat Mar 17 23:59:05 2007 +0000
@@ -28,12 +28,14 @@ import xmlrpclib
 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 *
 
@@ -96,6 +98,11 @@ gopts.opt('dryrun', short='n',
 gopts.opt('dryrun', short='n',
           fn=set_true, default=0,
           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',
@@ -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)
diff -r cfb265b93b2d -r 6b2875302558 tools/python/xen/xm/new.py
--- a/tools/python/xen/xm/new.py        Sat Mar 17 23:57:17 2007 +0000
+++ b/tools/python/xen/xm/new.py        Sat Mar 17 23:59:05 2007 +0000
@@ -21,6 +21,9 @@ from xen.xend import PrettyPrint
 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__':
diff -r cfb265b93b2d -r 6b2875302558 tools/python/xen/xm/xenapi_create.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xm/xenapi_create.py      Sat Mar 17 23:59:05 2007 +0000
@@ -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@xxxxxxxxx>
+#============================================================================
+"""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
+
+
+
+
+

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.