ia64/xen-unstable

view tools/python/xen/xm/xenapi_create.py @ 14704:45e9f6d7e422

Remove unused import.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Tue Apr 03 10:36:31 2007 +0100 (2007-04-03)
parents a02b39eaba58
children 38f3a6dedad6
line source
1 #!/usr/bin/python
2 #============================================================================
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of version 2.1 of the GNU Lesser General Public
5 # License as published by the Free Software Foundation.
6 #
7 # This library is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 # Lesser General Public License for more details.
11 #
12 # You should have received a copy of the GNU Lesser General Public
13 # License along with this library; if not, write to the Free Software
14 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 #============================================================================
16 # Copyright (C) 2007 Tom Wilkie <tom.wilkie@gmail.com>
17 #============================================================================
18 """Domain creation using new XenAPI
19 """
21 from xen.xm.main import server, get_default_SR
22 from xml.dom.minidom import parse, getDOMImplementation
23 from xml.parsers.xmlproc import xmlproc, xmlval, xmldtd
24 from xen.xend import sxp
25 from xen.xend.XendAPIConstants import XEN_API_ON_NORMAL_EXIT, \
26 XEN_API_ON_CRASH_BEHAVIOUR
27 from xen.xm.opts import OptionError
29 import sys
30 import os
31 import traceback
33 def log(_, msg):
34 #print "> " + msg
35 pass
37 DEBUG = 0
39 def get_name_label(node):
40 name_node = node.getElementsByTagName("name")[0]
41 label_node = name_node.getElementsByTagName("label")[0]
42 return " ".join([child.nodeValue for child in label_node.childNodes])
44 def get_name_description(node):
45 name_node = node.getElementsByTagName("name")[0]
46 description_node = name_node.getElementsByTagName("description")[0]
47 return " ".join([child.nodeValue for child in description_node.childNodes])
49 def get_text_in_child_node(node, child):
50 tag_node = node.getElementsByTagName(child)[0]
51 return tag_node.nodeValue
53 def get_child_node_attribute(node, child, attribute):
54 tag_node = node.getElementsByTagName(child)[0]
55 return tag_node.attributes[attribute].value
57 def get_child_nodes_as_dict(node, child_name,
58 key_attribute_name,
59 value_attribute_name):
60 return dict([(child.attributes[key_attribute_name].value,
61 child.attributes[value_attribute_name].value)
62 for child in node.getElementsByTagName(child_name)])
64 def try_quietly(fn, *args):
65 try:
66 return fn(*args)
67 except:
68 return None
70 class xenapi_create:
72 def __init__(self):
73 self.DEFAULT_STORAGE_REPOSITORY = get_default_SR()
75 self.dtd = "/usr/lib/python/xen/xm/create.dtd"
77 def create(self, filename=None, document=None, skipdtd=False):
78 """
79 Create a domain from an XML file or DOM tree
80 """
81 if skipdtd:
82 print "Skipping DTD checks. Dangerous!"
84 if filename is not None:
85 if not skipdtd:
86 self.check_dtd(filename)
87 document = parse(filename)
88 elif document is not None:
89 if not skipdtd:
90 self.check_dom_against_dtd(document)
92 self.check_doc(document)
94 vdis = document.getElementsByTagName("vdi")
95 vdi_refs_dict = self.create_vdis(vdis)
97 try:
98 vms = document.getElementsByTagName("vm")
99 return self.create_vms(vms, vdi_refs_dict)
100 except Exception, exn:
101 try_quietly(self.cleanup_vdis(vdi_refs_dict))
102 raise exn
104 # Methods to check xml file
105 # try to use dtd to check where possible
106 def check_dtd(self, file):
107 """
108 Check file against DTD.
109 Use this if possible as it gives nice
110 error messages
111 """
112 dtd = xmldtd.load_dtd(self.dtd)
113 parser = xmlproc.XMLProcessor()
114 parser.set_application(xmlval.ValidatingApp(dtd, parser))
115 parser.dtd = dtd
116 parser.ent = dtd
117 parser.parse_resource(file)
119 def check_dom_against_dtd(self, dom):
120 """
121 Check DOM again DTD.
122 Doesn't give as nice error messages.
123 (no location info)
124 """
125 dtd = xmldtd.load_dtd(self.dtd)
126 app = xmlval.ValidatingApp(dtd, self)
127 app.set_locator(self)
128 self.dom2sax(dom, app)
130 # Get errors back from ValidatingApp
131 def report_error(self, number, args=None):
132 self.errors = xmlproc.errors.english
133 try:
134 msg = self.errors[number]
135 if args != None:
136 msg = msg % args
137 except KeyError:
138 msg = self.errors[4002] % number # Unknown err msg :-)
139 print msg
140 sys.exit(-1)
142 # Here for compatibility with ValidatingApp
143 def get_line(self):
144 return -1
146 def get_column(self):
147 return -1
149 def dom2sax(self, dom, app):
150 """
151 Take a dom tree and tarverse it,
152 issuing SAX calls to app.
153 """
154 for child in dom.childNodes:
155 if child.nodeType == child.TEXT_NODE:
156 data = child.nodeValue
157 app.handle_data(data, 0, len(data))
158 else:
159 app.handle_start_tag(
160 child.nodeName,
161 self.attrs_to_dict(child.attributes))
162 self.dom2sax(child, app)
163 app.handle_end_tag(child.nodeName)
165 def attrs_to_dict(self, attrs):
166 return dict(attrs.items())
168 #
169 # Checks which cannot be done with dtd
170 #
171 def check_doc(self, doc):
172 vms = doc.getElementsByTagName("vm")
173 self.check_vms(vms)
175 def check_vms(self, vms):
176 map(self.check_vm, vms)
178 def check_vm(self, vm):
179 vifs = vm.getElementsByTagName("vif")
180 self.check_vifs(vifs)
182 def check_vifs(self, vifs):
183 map(self.check_vif, vifs)
185 def check_vif(self, vif):
186 pass
188 # Cleanup methods here
189 def cleanup_vdis(self, vdi_refs_dict):
190 map(self.cleanup_vdi, vdi_refs_dict.values())
192 def cleanup_vdi(self, vdi_ref):
193 server.xenapi.VDI.destroy(vdi_ref)
195 def cleanup_vms(self, vm_refs):
196 map(self.cleanup_vm, vm_refs)
198 def cleanup_vm(self, vm_ref):
199 server.xenapi.VM.destroy(vm_ref)
201 # Create methods here
202 def create_vdis(self, vdis):
203 log(DEBUG, "create_vdis")
204 return dict(map(self.create_vdi, vdis))
206 def create_vdi(self, vdi):
207 log(DEBUG, "create_vdi")
209 vdi_record = {
210 "name_label": get_name_label(vdi),
211 "name_description": get_name_description(vdi),
212 "SR": self.DEFAULT_STORAGE_REPOSITORY,
213 "virtual_size": vdi.attributes["size"].value,
214 "type": vdi.attributes["type"].value,
215 "shareable": vdi.attributes["shareable"].value,
216 "read_only": vdi.attributes["read_only"].value,
217 "other_config": {"location":
218 vdi.attributes["src"].value}
219 }
221 key = vdi.attributes["name"].value
222 value = server.xenapi.VDI.create(vdi_record)
224 return (key, value)
226 def create_vms(self, vms, vdis):
227 log(DEBUG, "create_vms")
228 return map(lambda vm: self.create_vm(vm, vdis), vms)
230 def create_vm(self, vm, vdis):
231 log(DEBUG, "create_vm")
233 vm_record = {
234 "name_label":
235 get_name_label(vm),
236 "name_description":
237 get_name_description(vm),
238 "user_version":
239 get_text_in_child_node(vm, "version"),
240 "is_a_template":
241 vm.attributes["is_a_template"].value == 'true',
242 "auto_power_on":
243 vm.attributes["auto_power_on"].value == 'true',
244 "memory_static_max":
245 get_child_node_attribute(vm, "memory", "static_max"),
246 "memory_static_min":
247 get_child_node_attribute(vm, "memory", "static_min"),
248 "memory_dynamic_max":
249 get_child_node_attribute(vm, "memory", "dynamic_max"),
250 "memory_dynamic_min":
251 get_child_node_attribute(vm, "memory", "dynamic_min"),
252 "VCPUs_params":
253 get_child_nodes_as_dict(vm, "vcpu_param", "key", "value"),
254 "VCPUs_max":
255 vm.attributes["vcpus_max"].value,
256 "VCPUs_at_startup":
257 vm.attributes["vcpus_at_startup"].value,
258 "actions_after_shutdown":
259 vm.attributes["actions_after_shutdown"].value,
260 "actions_after_reboot":
261 vm.attributes["actions_after_reboot"].value,
262 "actions_after_crash":
263 vm.attributes["actions_after_crash"].value,
264 "platform":
265 get_child_nodes_as_dict(vm, "platform", "key", "value"),
266 "other_config":
267 get_child_nodes_as_dict(vm, "other_config", "key", "value")
268 }
270 if len(vm.getElementsByTagName("pv")) > 0:
271 vm_record.update({
272 "PV_bootloader":
273 get_child_node_attribute(vm, "pv", "bootloader"),
274 "PV_kernel":
275 get_child_node_attribute(vm, "pv", "kernel"),
276 "PV_ramdisk":
277 get_child_node_attribute(vm, "pv", "ramdisk"),
278 "PV_args":
279 get_child_node_attribute(vm, "pv", "args"),
280 "PV_bootloader_args":
281 get_child_node_attribute(vm, "pv", "bootloader_args")
282 })
283 else:
284 hvm = vm.getElementsByTagName("hvm")[0]
285 vm_record.update({
286 "HVM_boot_policy":
287 get_child_node_attribute(vm, "hvm", "boot_policy"),
288 "HVM_boot_params":
289 get_child_nodes_as_dict(hvm, "boot_param", "key", "value")
290 })
291 try:
292 vm_ref = server.xenapi.VM.create(vm_record)
293 except:
294 traceback.print_exc()
295 sys.exit(-1)
297 try:
298 # Now create vbds
300 vbds = vm.getElementsByTagName("vbd")
302 self.create_vbds(vm_ref, vbds, vdis)
304 # Now create vifs
306 vifs = vm.getElementsByTagName("vif")
308 self.create_vifs(vm_ref, vifs)
310 # Now create consoles
312 consoles = vm.getElementsByTagName("console")
314 self.create_consoles(vm_ref, consoles)
316 return vm_ref
317 except:
318 server.xenapi.VM.destroy(vm_ref)
319 raise
321 def create_vbds(self, vm_ref, vbds, vdis):
322 log(DEBUG, "create_vbds")
323 return map(lambda vbd: self.create_vbd(vm_ref, vbd, vdis), vbds)
325 def create_vbd(self, vm_ref, vbd, vdis):
326 log(DEBUG, "create_vbd")
328 vbd_record = {
329 "VM":
330 vm_ref,
331 "VDI":
332 vdis[vbd.attributes["vdi"].value],
333 "device":
334 vbd.attributes["device"].value,
335 "bootable":
336 vbd.attributes["bootable"].value,
337 "mode":
338 vbd.attributes["mode"].value,
339 "type":
340 vbd.attributes["type"].value,
341 "qos_algorithm_type":
342 vbd.attributes["qos_algorithm_type"].value,
343 "qos_algorithm_params":
344 get_child_nodes_as_dict(vbd,
345 "qos_algorithm_param", "key", "value")
346 }
348 return server.xenapi.VBD.create(vbd_record)
350 def create_vifs(self, vm_ref, vifs):
351 log(DEBUG, "create_vifs")
352 return map(lambda vif: self.create_vif(vm_ref, vif), vifs)
354 def create_vif(self, vm_ref, vif):
355 log(DEBUG, "create_vif")
357 if "network" in vif.attributes.keys():
358 networks = [network_ref
359 for network_ref in server.xenapi.network.get_all()
360 if server.xenapi.network.get_name_label(network_ref)
361 == vif.attributes["network"].value]
362 if len(networks) > 0:
363 network = networks[0]
364 else:
365 raise OptionError("Network %s doesn't exist"
366 % vif.attributes["network"].value)
367 else:
368 network = self._get_network_ref()
370 vif_record = {
371 "device":
372 vif.attributes["device"].value,
373 "network":
374 network,
375 "VM":
376 vm_ref,
377 "MAC":
378 vif.attributes["mac"].value,
379 "MTU":
380 vif.attributes["mtu"].value,
381 "qos_algorithm_type":
382 vif.attributes["qos_algorithm_type"].value,
383 "qos_algorithm_params":
384 get_child_nodes_as_dict(vif,
385 "qos_algorithm_param", "key", "value")
386 }
388 return server.xenapi.VIF.create(vif_record)
390 _network_refs = []
392 def _get_network_ref(self):
393 try:
394 return self._network_refs.pop(0)
395 except IndexError:
396 self._network_refs = server.xenapi.network.get_all()
397 return self._network_refs.pop(0)
399 def create_consoles(self, vm_ref, consoles):
400 log(DEBUG, "create_consoles")
401 return map(lambda console: self.create_console(vm_ref, console),
402 consoles)
404 def create_console(self, vm_ref, console):
405 log(DEBUG, "create_consoles")
407 console_record = {
408 "VM":
409 vm_ref,
410 "protocol":
411 console.attributes["protocol"].value,
412 "other_params":
413 get_child_nodes_as_dict(console,
414 "other_param", "key", "value")
415 }
417 return server.xenapi.console.create(console_record)
419 def get_child_by_name(exp, childname, default = None):
420 try:
421 return [child for child in sxp.children(exp)
422 if child[0] == childname][0][1]
423 except:
424 return default
426 # Convert old sxp into new xml
428 class sxp2xml:
430 def convert_sxp_to_xml(self, config, transient=False):
432 devices = [child for child in sxp.children(config)
433 if len(child) > 0 and child[0] == "device"]
435 vbds_sxp = map(lambda x: x[1], [device for device in devices
436 if device[1][0] == "vbd"])
438 vifs_sxp = map(lambda x: x[1], [device for device in devices
439 if device[1][0] == "vif"])
440 # Create XML Document
442 impl = getDOMImplementation()
444 document = impl.createDocument(None, "xm", None)
446 # Lets make the VM tag..
448 vm = document.createElement("vm")
450 # Some string compatibility
452 actions_after_shutdown \
453 = get_child_by_name(config, "on_poweroff", "destroy")
454 actions_after_reboot \
455 = get_child_by_name(config, "on_reboot", "restart")
456 actions_after_crash \
457 = get_child_by_name(config, "on_crash", "restart")
459 def conv_chk(val, vals):
460 val.replace("-", "_")
461 if val not in vals:
462 raise "Invalid value: " + val
463 else:
464 return val
466 actions_after_shutdown = conv_chk(actions_after_shutdown,\
467 XEN_API_ON_NORMAL_EXIT)
468 actions_after_reboot = conv_chk(actions_after_reboot, \
469 XEN_API_ON_NORMAL_EXIT)
470 actions_after_crash = conv_chk(actions_after_crash, \
471 XEN_API_ON_CRASH_BEHAVIOUR)
472 # Flesh out tag attributes
474 vm.attributes["is_a_template"] = "false"
475 vm.attributes["auto_power_on"] = "false"
476 vm.attributes["actions_after_shutdown"] \
477 = actions_after_shutdown
478 vm.attributes["actions_after_reboot"] \
479 = actions_after_reboot
480 vm.attributes["actions_after_crash"] \
481 = actions_after_crash
482 vm.attributes["PCI_bus"] = ""
484 vm.attributes["vcpus_max"] \
485 = str(get_child_by_name(config, "vcpus", 1))
486 vm.attributes["vcpus_at_startup"] \
487 = str(get_child_by_name(config, "vcpus", 1))
489 # Make the name tag
491 vm.appendChild(self.make_name_tag(
492 get_child_by_name(config, "name"), document))
494 # Make version tag
496 version = document.createElement("version")
497 version.appendChild(document.createTextNode("1.0"))
498 vm.appendChild(version)
500 # Make pv or hvm tag
502 image = get_child_by_name(config, "image")
504 if image[0] == "linux":
505 pv = document.createElement("pv")
506 pv.attributes["kernel"] \
507 = get_child_by_name(image, "kernel", "")
508 pv.attributes["bootloader"] = ""
509 pv.attributes["ramdisk"] \
510 = get_child_by_name(image, "ramdisk", "")
511 pv.attributes["args"] \
512 = "root=" + get_child_by_name(image, "root", "") \
513 + " " + get_child_by_name(image, "args", "")
514 pv.attributes["bootloader_args"] = ""
516 vm.appendChild(pv)
517 elif image[0] == "hvm":
518 hvm = document.createElement("hvm")
519 hvm.attributes["boot_policy"] = "BIOS order"
521 boot_order = document.createElement("boot_param")
522 boot_order.attributes["key"] = "order"
523 boot_order.attributes["value"] \
524 = get_child_by_name(image, "boot", "abcd")
525 hvm.appendChild
527 vm.appendChild(hvm)
529 # Make memory tag
531 memory = document.createElement("memory")
533 memory_str = str(int(
534 get_child_by_name(config, "memory"))*1024*1024)
536 memory.attributes["static_min"] = str(0)
537 memory.attributes["static_max"] = memory_str
538 memory.attributes["dynamic_min"] = memory_str
539 memory.attributes["dynamic_max"] = memory_str
541 if get_child_by_name(config, "maxmem"):
542 memory.attributes["static_max"] = \
543 str(int(get_child_by_name(config, "maxmem")*1024*1024))
545 vm.appendChild(memory)
547 # And now the vbds
549 vbds = map(lambda vbd: self.extract_vbd(vbd, document), vbds_sxp)
551 map(vm.appendChild, vbds)
553 # And now the vifs
555 vifs = map(lambda vif: self.extract_vif(vif, document), vifs_sxp)
557 map(vm.appendChild, vifs)
559 # Last but not least the consoles...
561 consoles = self.extract_consoles(image, document)
563 map(vm.appendChild, consoles)
565 # Platform variables...
567 platform = self.extract_platform(image, document)
569 map(vm.appendChild, platform)
571 # transient?
573 if transient:
574 other_config = document.createElement("other_config")
575 other_config.attributes["key"] = "transient"
576 other_config.attributes["value"] = "True"
577 vm.appendChild(other_config)
579 # Add it to doc_root
581 document.documentElement.appendChild(vm)
583 # We want to pull out vdis
585 vdis = map(lambda vdb: self.extract_vdi(vdb, document), vbds_sxp)
587 map(document.documentElement.appendChild, vdis)
589 return document
591 def make_name_tag(self, label_text, document):
592 name = document.createElement("name")
594 label = document.createElement("label")
595 label.appendChild(document.createTextNode(str(label_text)))
596 name.appendChild(label)
598 description = document.createElement("description")
599 description.appendChild(document.createTextNode(" "))
600 name.appendChild(description)
602 return name
604 def extract_vbd(self, vbd_sxp, document):
605 src = get_child_by_name(vbd_sxp, "uname")
606 name = str(src.__hash__())
608 vbd = document.createElement("vbd")
610 vbd.attributes["name"] = "vdb" + name
611 vbd.attributes["vdi"] = "vdi" + name
612 vbd.attributes["mode"] \
613 = get_child_by_name(vbd_sxp, "mode") != "w" \
614 and "RO" or "RW"
615 vbd.attributes["device"] \
616 = get_child_by_name(vbd_sxp, "dev")
617 vbd.attributes["bootable"] = "1"
618 vbd.attributes["type"] = "disk"
619 vbd.attributes["qos_algorithm_type"] = ""
621 return vbd
623 def extract_vdi(self, vbd_sxp, document):
624 src = get_child_by_name(vbd_sxp, "uname")
625 name = "vdi" + str(src.__hash__())
627 vdi = document.createElement("vdi")
629 vdi.attributes["src"] = src
630 vdi.attributes["read_only"] \
631 = (get_child_by_name(vbd_sxp, "mode") != "w") \
632 and "true" or "false"
633 vdi.attributes["size"] = '-1'
634 vdi.attributes["type"] = "system"
635 vdi.attributes["shareable"] = "false"
636 vdi.attributes["name"] = name
638 vdi.appendChild(self.make_name_tag(name, document))
640 return vdi
642 def extract_vif(self, vif_sxp, document):
644 vif = document.createElement("vif")
646 dev = get_child_by_name(vif_sxp, "vifname", None)
648 if dev is None:
649 dev = self.getFreshEthDevice()
651 vif.attributes["name"] \
652 = "vif" + str(dev.__hash__())
653 vif.attributes["mac"] \
654 = get_child_by_name(vif_sxp, "mac", "")
655 vif.attributes["mtu"] \
656 = get_child_by_name(vif_sxp, "mtu", "")
657 vif.attributes["device"] = dev
658 vif.attributes["qos_algorithm_type"] = ""
660 if get_child_by_name(vif_sxp, "bridge") is not None:
661 vif.attributes["network"] \
662 = get_child_by_name(vif_sxp, "bridge")
664 return vif
666 _eths = -1
668 def mk_other_config(self, key, value, document):
669 other_config = document.createElement("other_config")
670 other_config.attributes["key"] = key
671 other_config.attributes["value"] = value
672 return other_config
674 def extract_consoles(self, image, document):
675 consoles = []
677 if int(get_child_by_name(image, "nographic", "1")) == 1:
678 return consoles
680 if int(get_child_by_name(image, "vnc", "0")) == 1:
681 console = document.createElement("console")
682 console.attributes["protocol"] = "rfb"
683 console.appendChild(self.mk_other_config(
684 "vncunused", str(get_child_by_name(image, "vncunused", "0")),
685 document))
686 console.appendChild(self.mk_other_config(
687 "vnclisten",
688 get_child_by_name(image, "vnclisten", "127.0.0.1"),
689 document))
690 console.appendChild(self.mk_other_config(
691 "vncpasswd", get_child_by_name(image, "vncpasswd", ""),
692 document))
693 consoles.append(console)
694 if int(get_child_by_name(image, "sdl", "0")) == 1:
695 console = document.createElement("console")
696 console.attributes["protocol"] = "sdl"
697 console.appendChild(self.mk_other_config(
698 "display", get_child_by_name(image, "display", ""),
699 document))
700 console.appendChild(self.mk_other_config(
701 "xauthority",
702 get_child_by_name(image, "vxauthority", "127.0.0.1"),
703 document))
704 console.appendChild(self.mk_other_config(
705 "vncpasswd", get_child_by_name(image, "vncpasswd", ""),
706 document))
707 consoles.append(console)
709 return consoles
712 def extract_platform(self, image, document):
713 platform_keys = ['acpi', 'apic', 'pae']
715 def extract_platform_key(key):
716 platform = document.createElement("platform")
717 platform.attributes["key"] = key
718 platform.attributes["value"] \
719 = str(get_child_by_name(image, key, "1"))
720 return platform
722 return map(extract_platform_key, platform_keys)
724 def getFreshEthDevice(self):
725 self._eths += 1
726 return "eth%i" % self._eths