ia64/xen-unstable

view tools/python/xen/xend/XendNode.py @ 18107:f8221241d187

xend: portability cleanup

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jul 18 14:14:12 2008 +0100 (2008-07-18)
parents e65fe28b5288
children 9404bcb6d32e
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (c) 2006, 2007 Xensource Inc.
17 #============================================================================
19 import os
20 import socket
21 import xen.lowlevel.xc
23 from xen.util import Brctl
24 from xen.util import pci as PciUtil
25 from xen.xend import XendAPIStore
26 from xen.xend import osdep
28 import uuid, arch
29 from XendPBD import XendPBD
30 from XendError import *
31 from XendOptions import instance as xendoptions
32 from XendQCoWStorageRepo import XendQCoWStorageRepo
33 from XendLocalStorageRepo import XendLocalStorageRepo
34 from XendLogging import log
35 from XendPIF import *
36 from XendPIFMetrics import XendPIFMetrics
37 from XendNetwork import *
38 from XendStateStore import XendStateStore
39 from XendMonitor import XendMonitor
40 from XendPPCI import XendPPCI
42 class XendNode:
43 """XendNode - Represents a Domain 0 Host."""
45 def __init__(self):
46 """Initalises the state of all host specific objects such as
48 * host
49 * host_CPU
50 * host_metrics
51 * PIF
52 * PIF_metrics
53 * network
54 * Storage Repository
55 * PPCI
56 """
58 self.xc = xen.lowlevel.xc.xc()
59 self.state_store = XendStateStore(xendoptions().get_xend_state_path())
60 self.monitor = XendMonitor()
61 self.monitor.start()
63 # load host state from XML file
64 saved_host = self.state_store.load_state('host')
65 if saved_host and len(saved_host.keys()) == 1:
66 self.uuid = saved_host.keys()[0]
67 host = saved_host[self.uuid]
68 self.name = host.get('name_label', socket.gethostname())
69 self.desc = host.get('name_description', '')
70 self.host_metrics_uuid = host.get('metrics_uuid',
71 uuid.createString())
72 try:
73 self.other_config = eval(host['other_config'])
74 except:
75 self.other_config = {}
76 self.cpus = {}
77 else:
78 self.uuid = uuid.createString()
79 self.name = socket.gethostname()
80 self.desc = ''
81 self.other_config = {}
82 self.cpus = {}
83 self.host_metrics_uuid = uuid.createString()
85 # put some arbitrary params in other_config as this
86 # is directly exposed via XenAPI
87 self.other_config["xen_pagesize"] = self.xeninfo_dict()["xen_pagesize"]
88 self.other_config["platform_params"] = self.xeninfo_dict()["platform_params"]
90 # load CPU UUIDs
91 saved_cpus = self.state_store.load_state('cpu')
92 for cpu_uuid, cpu in saved_cpus.items():
93 self.cpus[cpu_uuid] = cpu
95 cpuinfo = osdep.get_cpuinfo()
96 physinfo = self.physinfo_dict()
97 cpu_count = physinfo['nr_cpus']
98 cpu_features = physinfo['hw_caps']
99 virt_caps = physinfo['virt_caps']
101 # If the number of CPUs don't match, we should just reinitialise
102 # the CPU UUIDs.
103 if cpu_count != len(self.cpus):
104 self.cpus = {}
105 for i in range(cpu_count):
106 u = uuid.createString()
107 self.cpus[u] = {'uuid': u, 'number': i }
109 for u in self.cpus.keys():
110 number = self.cpus[u]['number']
111 # We can run off the end of the cpuinfo list if domain0 does not
112 # have #vcpus == #pcpus. In that case we just replicate one that's
113 # in the hash table.
114 if not cpuinfo.has_key(number):
115 number = cpuinfo.keys()[0]
116 if arch.type == "x86":
117 self.cpus[u].update(
118 { 'host' : self.uuid,
119 'features' : cpu_features,
120 'virt_caps': virt_caps,
121 'speed' : int(float(cpuinfo[number]['cpu MHz'])),
122 'vendor' : cpuinfo[number]['vendor_id'],
123 'modelname': cpuinfo[number]['model name'],
124 'stepping' : cpuinfo[number]['stepping'],
125 'flags' : cpuinfo[number]['flags'],
126 })
127 elif arch.type == "ia64":
128 self.cpus[u].update(
129 { 'host' : self.uuid,
130 'features' : cpu_features,
131 'speed' : int(float(cpuinfo[number]['cpu MHz'])),
132 'vendor' : cpuinfo[number]['vendor'],
133 'modelname': cpuinfo[number]['family'],
134 'stepping' : cpuinfo[number]['model'],
135 'flags' : cpuinfo[number]['features'],
136 })
137 else:
138 self.cpus[u].update(
139 { 'host' : self.uuid,
140 'features' : cpu_features,
141 })
143 self.srs = {}
145 # Initialise networks
146 # First configure ones off disk
147 saved_networks = self.state_store.load_state('network')
148 if saved_networks:
149 for net_uuid, network in saved_networks.items():
150 try:
151 XendNetwork.recreate(network, net_uuid)
152 except CreateUnspecifiedAttributeError:
153 log.warn("Error recreating network %s", net_uuid)
155 # Next discover any existing bridges and check
156 # they are not already configured
157 bridges = Brctl.get_state().keys()
158 configured_bridges = [XendAPIStore.get(
159 network_uuid, "network")
160 .get_name_label()
161 for network_uuid in XendNetwork.get_all()]
162 unconfigured_bridges = [bridge
163 for bridge in bridges
164 if bridge not in configured_bridges]
165 for unconfigured_bridge in unconfigured_bridges:
166 XendNetwork.create_phy(unconfigured_bridge)
168 # Initialise PIFs
169 # First configure ones off disk
170 saved_pifs = self.state_store.load_state('pif')
171 if saved_pifs:
172 for pif_uuid, pif in saved_pifs.items():
173 try:
174 XendPIF.recreate(pif, pif_uuid)
175 except CreateUnspecifiedAttributeError:
176 log.warn("Error recreating PIF %s", pif_uuid)
178 # Next discover any existing PIFs and check
179 # they are not already configured
180 configured_pifs = [XendAPIStore.get(
181 pif_uuid, "PIF")
182 .get_interface_name()
183 for pif_uuid in XendPIF.get_all()]
184 unconfigured_pifs = [(name, mtu, mac)
185 for name, mtu, mac in linux_get_phy_ifaces()
186 if name not in configured_pifs]
188 # Get a mapping from interface to bridge
189 if_to_br = dict([(i,b)
190 for (b,ifs) in Brctl.get_state().items()
191 for i in ifs])
193 for name, mtu, mac in unconfigured_pifs:
194 # Check PIF is on bridge
195 # if not, ignore
196 bridge_name = if_to_br.get(name, None)
197 if bridge_name is not None:
198 # Translate bridge name to network uuid
199 for network_uuid in XendNetwork.get_all():
200 network = XendAPIStore.get(
201 network_uuid, 'network')
202 if network.get_name_label() == bridge_name:
203 XendPIF.create_phy(network_uuid, name,
204 mac, mtu)
205 break
206 else:
207 log.debug("Cannot find network for bridge %s "
208 "when configuring PIF %s",
209 (bridge_name, name))
211 # initialise storage
212 saved_srs = self.state_store.load_state('sr')
213 if saved_srs:
214 for sr_uuid, sr_cfg in saved_srs.items():
215 if sr_cfg['type'] == 'qcow_file':
216 self.srs[sr_uuid] = XendQCoWStorageRepo(sr_uuid)
217 elif sr_cfg['type'] == 'local':
218 self.srs[sr_uuid] = XendLocalStorageRepo(sr_uuid)
220 # Create missing SRs if they don't exist
221 if not self.get_sr_by_type('local'):
222 image_sr_uuid = uuid.createString()
223 self.srs[image_sr_uuid] = XendLocalStorageRepo(image_sr_uuid)
225 if not self.get_sr_by_type('qcow_file'):
226 qcow_sr_uuid = uuid.createString()
227 self.srs[qcow_sr_uuid] = XendQCoWStorageRepo(qcow_sr_uuid)
229 saved_pbds = self.state_store.load_state('pbd')
230 if saved_pbds:
231 for pbd_uuid, pbd_cfg in saved_pbds.items():
232 try:
233 XendPBD.recreate(pbd_uuid, pbd_cfg)
234 except CreateUnspecifiedAttributeError:
235 log.warn("Error recreating PBD %s", pbd_uuid)
238 # Initialise PPCIs
239 saved_ppcis = self.state_store.load_state('ppci')
240 saved_ppci_table = {}
241 if saved_ppcis:
242 for ppci_uuid, ppci_record in saved_ppcis.items():
243 try:
244 saved_ppci_table[ppci_record['name']] = ppci_uuid
245 except KeyError:
246 pass
248 for pci_dev in PciUtil.get_all_pci_devices():
249 ppci_record = {
250 'domain': pci_dev.domain,
251 'bus': pci_dev.bus,
252 'slot': pci_dev.slot,
253 'func': pci_dev.func,
254 'vendor_id': pci_dev.vendor,
255 'vendor_name': pci_dev.vendorname,
256 'device_id': pci_dev.device,
257 'device_name': pci_dev.devicename,
258 'revision_id': pci_dev.revision,
259 'class_code': pci_dev.classcode,
260 'class_name': pci_dev.classname,
261 'subsystem_vendor_id': pci_dev.subvendor,
262 'subsystem_vendor_name': pci_dev.subvendorname,
263 'subsystem_id': pci_dev.subdevice,
264 'subsystem_name': pci_dev.subdevicename,
265 'driver': pci_dev.driver
266 }
267 # If saved uuid exists, use it. Otherwise create one.
268 ppci_uuid = saved_ppci_table.get(pci_dev.name, uuid.createString())
269 XendPPCI(ppci_uuid, ppci_record)
272 ## def network_destroy(self, net_uuid):
273 ## del self.networks[net_uuid]
274 ## self.save_networks()
277 def get_PIF_refs(self):
278 log.debug(XendPIF.get_all())
279 return XendPIF.get_all()
281 ## def _PIF_create(self, name, mtu, vlan, mac, network, persist = True,
282 ## pif_uuid = None, metrics_uuid = None):
283 ## for pif in self.pifs.values():
284 ## if pif.network == network:
285 ## raise NetworkAlreadyConnected(pif.uuid)
287 ## if pif_uuid is None:
288 ## pif_uuid = uuid.createString()
289 ## if metrics_uuid is None:
290 ## metrics_uuid = uuid.createString()
292 ## metrics = XendPIFMetrics(metrics_uuid)
293 ## pif = XendPIF(pif_uuid, metrics, name, mtu, vlan, mac, network, self)
294 ## metrics.set_PIF(pif)
296 ## self.pif_metrics[metrics_uuid] = metrics
297 ## self.pifs[pif_uuid] = pif
299 ## if persist:
300 ## self.save_PIFs()
301 ## self.refreshBridges()
302 ## return pif_uuid
304 ## def PIF_destroy(self, pif_uuid):
305 ## pif = self.pifs[pif_uuid]
307 ## if pif.vlan == -1:
308 ## raise PIFIsPhysical()
310 ## del self.pifs[pif_uuid]
311 ## self.save_PIFs()
314 def get_PPCI_refs(self):
315 return XendPPCI.get_all()
317 def get_ppci_by_uuid(self, ppci_uuid):
318 if ppci_uuid in self.get_PPCI_refs():
319 return ppci_uuid
320 return None
323 def save(self):
324 # save state
325 host_record = {self.uuid: {'name_label':self.name,
326 'name_description':self.desc,
327 'metrics_uuid': self.host_metrics_uuid,
328 'other_config': self.other_config}}
329 self.state_store.save_state('host',host_record)
330 self.state_store.save_state('cpu', self.cpus)
331 self.save_PIFs()
332 self.save_networks()
333 self.save_PBDs()
334 self.save_SRs()
335 self.save_PPCIs()
337 def save_PIFs(self):
338 pif_records = dict([(pif_uuid, XendAPIStore.get(
339 pif_uuid, "PIF").get_record())
340 for pif_uuid in XendPIF.get_all()])
341 self.state_store.save_state('pif', pif_records)
343 def save_networks(self):
344 net_records = dict([(network_uuid, XendAPIStore.get(
345 network_uuid, "network").get_record())
346 for network_uuid in XendNetwork.get_all()])
347 self.state_store.save_state('network', net_records)
349 def save_PBDs(self):
350 pbd_records = dict([(pbd_uuid, XendAPIStore.get(
351 pbd_uuid, "PBD").get_record())
352 for pbd_uuid in XendPBD.get_all()])
353 self.state_store.save_state('pbd', pbd_records)
355 def save_SRs(self):
356 sr_records = dict([(k, v.get_record(transient = False))
357 for k, v in self.srs.items()])
358 self.state_store.save_state('sr', sr_records)
360 def save_PPCIs(self):
361 ppci_records = dict([(ppci_uuid, XendAPIStore.get(
362 ppci_uuid, "PPCI").get_record())
363 for ppci_uuid in XendPPCI.get_all()])
364 self.state_store.save_state('ppci', ppci_records)
366 def shutdown(self):
367 return 0
369 def reboot(self):
370 return 0
372 def notify(self, _):
373 return 0
375 #
376 # Ref validation
377 #
379 def is_valid_host(self, host_ref):
380 return (host_ref == self.uuid)
382 def is_valid_cpu(self, cpu_ref):
383 return (cpu_ref in self.cpus)
385 def is_valid_sr(self, sr_ref):
386 return (sr_ref in self.srs)
388 def is_valid_vdi(self, vdi_ref):
389 for sr in self.srs.values():
390 if sr.is_valid_vdi(vdi_ref):
391 return True
392 return False
394 #
395 # Storage Repositories
396 #
398 def get_sr(self, sr_uuid):
399 return self.srs.get(sr_uuid)
401 def get_sr_by_type(self, sr_type):
402 return [sr.uuid for sr in self.srs.values() if sr.type == sr_type]
404 def get_sr_by_name(self, name):
405 return [sr.uuid for sr in self.srs.values() if sr.name_label == name]
407 def get_all_sr_uuid(self):
408 return self.srs.keys()
410 def get_vdi_by_uuid(self, vdi_uuid):
411 for sr in self.srs.values():
412 if sr.is_valid_vdi(vdi_uuid):
413 return sr.get_vdi_by_uuid(vdi_uuid)
414 return None
416 def get_vdi_by_name_label(self, name):
417 for sr in self.srs.values():
418 vdi = sr.get_vdi_by_name_label(name)
419 if vdi:
420 return vdi
421 return None
423 def get_sr_containing_vdi(self, vdi_uuid):
424 for sr in self.srs.values():
425 if sr.is_valid_vdi(vdi_uuid):
426 return sr
427 return None
430 #
431 # Host Functions
432 #
434 def xen_version(self):
435 info = self.xc.xeninfo()
437 info = {'Xen': '%(xen_major)d.%(xen_minor)d' % info}
439 # Add xend_config_format
440 info.update(self.xendinfo_dict())
442 # Add version info about machine
443 info.update(self.nodeinfo_dict())
445 # Add specific xen version info
446 xeninfo_dict = self.xeninfo_dict()
448 info.update({
449 "xen_major": xeninfo_dict["xen_major"],
450 "xen_minor": xeninfo_dict["xen_minor"],
451 "xen_extra": xeninfo_dict["xen_extra"],
452 "cc_compiler": xeninfo_dict["cc_compiler"],
453 "cc_compile_by": xeninfo_dict["cc_compile_by"],
454 "cc_compile_domain": xeninfo_dict["cc_compile_domain"],
455 "cc_compile_date": xeninfo_dict["cc_compile_date"],
456 "xen_changeset": xeninfo_dict["xen_changeset"]
457 })
459 return info
461 def get_name(self):
462 return self.name
464 def set_name(self, new_name):
465 self.name = new_name
467 def get_description(self):
468 return self.desc
470 def set_description(self, new_desc):
471 self.desc = new_desc
473 def get_uuid(self):
474 return self.uuid
476 def get_capabilities(self):
477 return self.xc.xeninfo()['xen_caps'].split(" ")
479 #
480 # Host CPU Functions
481 #
483 def get_host_cpu_by_uuid(self, host_cpu_uuid):
484 if host_cpu_uuid in self.cpus:
485 return host_cpu_uuid
486 raise XendError('Invalid CPU UUID')
488 def get_host_cpu_refs(self):
489 return self.cpus.keys()
491 def get_host_cpu_uuid(self, host_cpu_ref):
492 if host_cpu_ref in self.cpus:
493 return host_cpu_ref
494 else:
495 raise XendError('Invalid CPU Reference')
497 def get_host_cpu_field(self, ref, field):
498 try:
499 return self.cpus[ref][field]
500 except KeyError:
501 raise XendError('Invalid CPU Reference')
503 def get_host_cpu_load(self, host_cpu_ref):
504 host_cpu = self.cpus.get(host_cpu_ref)
505 if not host_cpu:
506 return 0.0
508 vcpu = int(host_cpu['number'])
509 cpu_loads = self.monitor.get_domain_vcpus_util()
510 if 0 in cpu_loads and vcpu in cpu_loads[0]:
511 return cpu_loads[0][vcpu]
513 return 0.0
515 def get_vcpus_policy(self):
516 sched_id = self.xc.sched_id_get()
517 if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF:
518 return 'sedf'
519 elif sched_id == xen.lowlevel.xc.XEN_SCHEDULER_CREDIT:
520 return 'credit'
521 else:
522 return 'unknown'
524 def get_cpu_configuration(self):
525 phys_info = self.physinfo_dict()
527 cpu_info = {
528 "nr_nodes": phys_info["nr_nodes"],
529 "nr_cpus": phys_info["nr_cpus"],
530 "cores_per_socket": phys_info["cores_per_socket"],
531 "threads_per_core": phys_info["threads_per_core"]
532 }
534 return cpu_info
536 #
537 # Network Functions
538 #
540 def bridge_to_network(self, bridge):
541 """
542 Determine which network a particular bridge is attached to.
544 @param bridge The name of the bridge. If empty, the default bridge
545 will be used instead (the first one in the list returned by brctl
546 show); this is the behaviour of the vif-bridge script.
547 @return The XendNetwork instance to which this bridge is attached.
548 @raise Exception if the interface is not connected to a network.
549 """
550 if not bridge:
551 rc, bridge = commands.getstatusoutput(
552 'brctl show | cut -d "\n" -f 2 | cut -f 1')
553 if rc != 0 or not bridge:
554 raise Exception(
555 'Could not find default bridge, and none was specified')
557 for network_uuid in XendNetwork.get_all():
558 network = XendAPIStore.get(network_uuid, "network")
559 if network.get_name_label() == bridge:
560 return network
561 else:
562 raise Exception('Cannot find network for bridge %s' % bridge)
564 #
565 # Debug keys.
566 #
568 def send_debug_keys(self, keys):
569 return self.xc.send_debug_keys(keys)
571 #
572 # Getting host information.
573 #
575 def info(self):
576 return (self.nodeinfo() + self.physinfo() + self.xeninfo() +
577 self.xendinfo())
579 def nodeinfo(self):
580 (sys, host, rel, ver, mch) = os.uname()
581 return [['system', sys],
582 ['host', host],
583 ['release', rel],
584 ['version', ver],
585 ['machine', mch]]
587 def list_to_rangepairs(self,cmap):
588 cmap.sort()
589 pairs = []
590 x = y = 0
591 for i in range(0,len(cmap)):
592 try:
593 if ((cmap[y+1] - cmap[i]) > 1):
594 pairs.append((cmap[x],cmap[y]))
595 x = y = i+1
596 else:
597 y = y + 1
598 # if we go off the end, then just add x to y
599 except IndexError:
600 pairs.append((cmap[x],cmap[y]))
602 return pairs
604 def format_pairs(self,pairs):
605 if not pairs:
606 return "no cpus"
607 out = ""
608 for f,s in pairs:
609 if (f==s):
610 out += '%d'%f
611 else:
612 out += '%d-%d'%(f,s)
613 out += ','
614 # trim trailing ','
615 return out[:-1]
617 def list_to_strrange(self,list):
618 return self.format_pairs(self.list_to_rangepairs(list))
620 def format_node_to_cpu(self, pinfo):
621 str=''
622 whitespace=''
623 try:
624 node_to_cpu=pinfo['node_to_cpu']
625 for i in range(0, pinfo['nr_nodes']):
626 str+='%snode%d:%s\n' % (whitespace,
627 i,
628 self.list_to_strrange(node_to_cpu[i]))
629 whitespace='%25s' % ''
630 except:
631 str='none\n'
632 return str[:-1];
633 def format_node_to_memory(self, pinfo):
634 str=''
635 whitespace=''
636 try:
637 node_to_memory=pinfo['node_to_memory']
638 for i in range(0, pinfo['nr_nodes']):
639 str+='%snode%d:%d\n' % (whitespace,
640 i,
641 node_to_memory[i] / 1024)
642 whitespace='%25s' % ''
643 except:
644 str='none\n'
645 return str[:-1];
648 def physinfo(self):
649 info = self.xc.physinfo()
651 info['cpu_mhz'] = info['cpu_khz'] / 1000
653 # physinfo is in KiB, need it in MiB
654 info['total_memory'] = info['total_memory'] / 1024
655 info['free_memory'] = info['free_memory'] / 1024
656 info['node_to_cpu'] = self.format_node_to_cpu(info)
657 info['node_to_memory'] = self.format_node_to_memory(info)
659 ITEM_ORDER = ['nr_cpus',
660 'nr_nodes',
661 'cores_per_socket',
662 'threads_per_core',
663 'cpu_mhz',
664 'hw_caps',
665 'virt_caps',
666 'total_memory',
667 'free_memory',
668 'node_to_cpu',
669 'node_to_memory'
670 ]
672 return [[k, info[k]] for k in ITEM_ORDER]
674 def xenschedinfo(self):
675 sched_id = self.xc.sched_id_get()
676 if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF:
677 return 'sedf'
678 elif sched_id == xen.lowlevel.xc.XEN_SCHEDULER_CREDIT:
679 return 'credit'
680 else:
681 return 'unknown'
683 def xeninfo(self):
684 info = self.xc.xeninfo()
685 info['xen_scheduler'] = self.xenschedinfo()
687 ITEM_ORDER = ['xen_major',
688 'xen_minor',
689 'xen_extra',
690 'xen_caps',
691 'xen_scheduler',
692 'xen_pagesize',
693 'platform_params',
694 'xen_changeset',
695 'cc_compiler',
696 'cc_compile_by',
697 'cc_compile_domain',
698 'cc_compile_date',
699 ]
701 return [[k, info[k]] for k in ITEM_ORDER]
703 def xendinfo(self):
704 return [['xend_config_format', 4]]
706 #
707 # utilisation tracking
708 #
710 def get_vcpu_util(self, domid, vcpuid):
711 cpu_loads = self.monitor.get_domain_vcpus_util()
712 if domid in cpu_loads:
713 return cpu_loads[domid].get(vcpuid, 0.0)
714 return 0.0
716 def get_vif_util(self, domid, vifid):
717 vif_loads = self.monitor.get_domain_vifs_util()
718 if domid in vif_loads:
719 return vif_loads[domid].get(vifid, (0.0, 0.0))
720 return (0.0, 0.0)
722 def get_vif_stat(self, domid, vifid):
723 vif_loads = self.monitor.get_domain_vifs_stat()
724 if domid in vif_loads:
725 return vif_loads[domid].get(vifid, (0.0, 0.0))
726 return (0.0, 0.0)
728 def get_vbd_util(self, domid, vbdid):
729 vbd_loads = self.monitor.get_domain_vbds_util()
730 if domid in vbd_loads:
731 return vbd_loads[domid].get(vbdid, (0.0, 0.0))
732 return (0.0, 0.0)
734 # dictionary version of *info() functions to get rid of
735 # SXPisms.
736 def nodeinfo_dict(self):
737 return dict(self.nodeinfo())
738 def xendinfo_dict(self):
739 return dict(self.xendinfo())
740 def xeninfo_dict(self):
741 return dict(self.xeninfo())
742 def physinfo_dict(self):
743 return dict(self.physinfo())
744 def info_dict(self):
745 return dict(self.info())
747 def instance():
748 global inst
749 try:
750 inst
751 except:
752 inst = XendNode()
753 inst.save()
754 return inst