ia64/xen-unstable

view tools/python/xen/xend/XendNode.py @ 13263:3157b54eb465

[XEND] Prevent exception if PIF does not have a network.

Signed-off-by: Alastair Tse <atse@xensource.com>
author Alastair Tse <atse@xensource.com>
date Thu Jan 04 16:34:19 2007 +0000 (2007-01-04)
parents 615109616bb6
children 3dcd2664853a
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 Xensource Inc.
17 #============================================================================
19 import os
20 import socket
21 import xen.lowlevel.xc
23 from xen.util import Brctl
25 from xen.xend import uuid
26 from xen.xend.XendError import XendError, NetworkAlreadyConnected
27 from xen.xend.XendRoot import instance as xendroot
28 from xen.xend.XendStorageRepository import XendStorageRepository
29 from xen.xend.XendLogging import log
30 from xen.xend.XendPIF import *
31 from xen.xend.XendNetwork import *
32 from xen.xend.XendStateStore import XendStateStore
34 class XendNode:
35 """XendNode - Represents a Domain 0 Host."""
37 def __init__(self):
38 """Initalises the state of all host specific objects such as
40 * Host
41 * Host_CPU
42 * PIF
43 * Network
44 * Storage Repository
45 """
47 self.xc = xen.lowlevel.xc.xc()
48 self.state_store = XendStateStore(xendroot().get_xend_state_path())
50 # load host state from XML file
51 saved_host = self.state_store.load_state('host')
52 if saved_host and len(saved_host.keys()) == 1:
53 self.uuid = saved_host.keys()[0]
54 host = saved_host[self.uuid]
55 self.name = host.get('name_label', socket.gethostname())
56 self.desc = host.get('name_description', '')
57 self.cpus = {}
58 else:
59 self.uuid = uuid.createString()
60 self.name = socket.gethostname()
61 self.desc = ''
62 self.cpus = {}
64 # load CPU UUIDs
65 saved_cpus = self.state_store.load_state('cpu')
66 for cpu_uuid, cpu in saved_cpus.items():
67 self.cpus[cpu_uuid] = cpu
69 # verify we have enough cpus here
70 physinfo = self.physinfo_dict()
71 cpu_count = physinfo['nr_cpus']
72 cpu_features = physinfo['hw_caps']
74 # If the number of CPUs don't match, we should just reinitialise
75 # the CPU UUIDs.
76 if cpu_count != len(self.cpus):
77 self.cpus = {}
78 for i in range(cpu_count):
79 cpu_uuid = uuid.createString()
80 cpu_info = {'uuid': cpu_uuid,
81 'host': self.uuid,
82 'number': i,
83 'features': cpu_features}
84 self.cpus[cpu_uuid] = cpu_info
86 self.pifs = {}
87 self.networks = {}
89 # initialise networks
90 saved_networks = self.state_store.load_state('network')
91 if saved_networks:
92 for net_uuid, network in saved_networks.items():
93 self.network_create(network.get('name_label'),
94 network.get('name_description', ''),
95 network.get('default_gateway', ''),
96 network.get('default_netmask', ''),
97 False, net_uuid)
98 else:
99 gateway, netmask = linux_get_default_network()
100 self.network_create('net0', '', gateway, netmask, False)
102 # initialise PIFs
103 saved_pifs = self.state_store.load_state('pif')
104 if saved_pifs:
105 for pif_uuid, pif in saved_pifs.items():
106 if pif.get('network') in self.networks:
107 network = self.networks[pif['network']]
108 try:
109 self.PIF_create(pif['name'], pif['MTU'], pif['VLAN'],
110 pif['MAC'], network, False, pif_uuid)
111 except NetworkAlreadyConnected, exn:
112 log.error('Cannot load saved PIF %s, as network %s ' +
113 'is already connected to PIF %s',
114 pif_uuid, pif['network'], exn.pif_uuid)
115 else:
116 for name, mtu, mac in linux_get_phy_ifaces():
117 network = self.networks.values()[0]
118 self.PIF_create(name, mtu, '', mac, network, False)
120 # initialise storage
121 saved_sr = self.state_store.load_state('sr')
122 if saved_sr and len(saved_sr) == 1:
123 sr_uuid = saved_sr.keys()[0]
124 self.sr = XendStorageRepository(sr_uuid)
125 else:
126 sr_uuid = uuid.createString()
127 self.sr = XendStorageRepository(sr_uuid)
130 def network_create(self, name_label, name_description,
131 default_gateway, default_netmask, persist = True,
132 net_uuid = None):
133 if net_uuid is None:
134 net_uuid = uuid.createString()
135 self.networks[net_uuid] = XendNetwork(net_uuid, name_label,
136 name_description,
137 default_gateway,
138 default_netmask)
139 if persist:
140 self.save_networks()
141 return net_uuid
144 def network_destroy(self, net_uuid):
145 del self.networks[net_uuid]
146 self.save_networks()
149 def PIF_create(self, name, mtu, vlan, mac, network, persist = True,
150 pif_uuid = None):
151 for pif in self.pifs.values():
152 if pif.network == network:
153 raise NetworkAlreadyConnected(pif.uuid)
155 if pif_uuid is None:
156 pif_uuid = uuid.createString()
157 self.pifs[pif_uuid] = XendPIF(pif_uuid, name, mtu, vlan, mac, network,
158 self)
159 if persist:
160 self.save_PIFs()
161 self.refreshBridges()
162 return pif_uuid
165 def PIF_create_VLAN(self, pif_uuid, network_uuid, vlan):
166 pif = self.pifs[pif_uuid]
167 network = self.networks[network_uuid]
168 return self.PIF_create(pif.name, pif.mtu, vlan, pif.mac, network)
171 def PIF_destroy(self, pif_uuid):
172 del self.pifs[pif_uuid]
173 self.save_PIFs()
176 def save(self):
177 # save state
178 host_record = {self.uuid: {'name_label':self.name,
179 'name_description':self.desc}}
180 self.state_store.save_state('host',host_record)
181 self.state_store.save_state('cpu', self.cpus)
182 self.save_PIFs()
183 self.save_networks()
185 sr_record = {self.sr.uuid: self.sr.get_record()}
186 self.state_store.save_state('sr', sr_record)
188 def save_PIFs(self):
189 pif_records = dict([(k, v.get_record(transient = False))
190 for k, v in self.pifs.items()])
191 self.state_store.save_state('pif', pif_records)
193 def save_networks(self):
194 net_records = dict([(k, v.get_record(transient = False))
195 for k, v in self.networks.items()])
196 self.state_store.save_state('network', net_records)
198 def shutdown(self):
199 return 0
201 def reboot(self):
202 return 0
204 def notify(self, _):
205 return 0
208 #
209 # Ref validation
210 #
212 def is_valid_host(self, host_ref):
213 return (host_ref == self.uuid)
215 def is_valid_cpu(self, cpu_ref):
216 return (cpu_ref in self.cpus)
218 def is_valid_network(self, network_ref):
219 return (network_ref in self.networks)
221 #
222 # Storage Repo
223 #
225 def get_sr(self):
226 return self.sr
228 #
229 # Host Functions
230 #
232 def xen_version(self):
233 info = self.xc.xeninfo()
234 try:
235 from xen import VERSION
236 return {'Xen': '%(xen_major)d.%(xen_minor)d' % info,
237 'Xend': VERSION}
238 except (ImportError, AttributeError):
239 return {'Xen': '%(xen_major)d.%(xen_minor)d' % info,
240 'Xend': '3.0.3'}
242 def get_name(self):
243 return self.name
245 def set_name(self, new_name):
246 self.name = new_name
248 def get_description(self):
249 return self.desc
251 def set_description(self, new_desc):
252 self.desc = new_desc
254 def get_uuid(self):
255 return self.uuid
257 #
258 # Host CPU Functions
259 #
261 def get_host_cpu_by_uuid(self, host_cpu_uuid):
262 if host_cpu_uuid in self.cpus:
263 return host_cpu_uuid
264 raise XendError('Invalid CPU UUID')
266 def get_host_cpu_refs(self):
267 return self.cpus.keys()
269 def get_host_cpu_uuid(self, host_cpu_ref):
270 if host_cpu_ref in self.cpus:
271 return host_cpu_ref
272 else:
273 raise XendError('Invalid CPU Reference')
275 def get_host_cpu_features(self, host_cpu_ref):
276 try:
277 return self.cpus[host_cpu_ref]['features']
278 except KeyError:
279 raise XendError('Invalid CPU Reference')
281 def get_host_cpu_number(self, host_cpu_ref):
282 try:
283 return self.cpus[host_cpu_ref]['number']
284 except KeyError:
285 raise XendError('Invalid CPU Reference')
287 def get_host_cpu_load(self, host_cpu_ref):
288 return 0.0
291 #
292 # Network Functions
293 #
295 def get_network_refs(self):
296 return self.networks.keys()
298 def get_network(self, network_ref):
299 return self.networks[network_ref]
301 def bridge_to_network(self, bridge):
302 """
303 Determine which network a particular bridge is attached to.
305 @param bridge The name of the bridge. If empty, the default bridge
306 will be used instead (the first one in the list returned by brctl
307 show); this is the behaviour of the vif-bridge script.
308 @return The XendNetwork instance to which this bridge is attached.
309 @raise Exception if the interface is not connected to a network.
310 """
311 if not bridge:
312 rc, bridge = commands.getstatusoutput(
313 'brctl show | cut -d "\n" -f 2 | cut -f 1')
314 if rc != 0 or not bridge:
315 raise Exception(
316 'Could not find default bridge, and none was specified')
318 bridges = Brctl.get_state()
319 if bridge not in bridges:
320 raise Exception('Bridge %s is not up' % bridge)
321 for pif in self.pifs.values():
322 if pif.interface_name() in bridges[bridge]:
323 return pif.network
324 raise Exception('Bridge %s is not connected to a network' % bridge)
327 #
328 # Getting host information.
329 #
331 def info(self):
332 return (self.nodeinfo() + self.physinfo() + self.xeninfo() +
333 self.xendinfo())
335 def nodeinfo(self):
336 (sys, host, rel, ver, mch) = os.uname()
337 return [['system', sys],
338 ['host', host],
339 ['release', rel],
340 ['version', ver],
341 ['machine', mch]]
343 def physinfo(self):
344 info = self.xc.physinfo()
346 info['nr_cpus'] = (info['nr_nodes'] *
347 info['sockets_per_node'] *
348 info['cores_per_socket'] *
349 info['threads_per_core'])
350 info['cpu_mhz'] = info['cpu_khz'] / 1000
351 # physinfo is in KiB
352 info['total_memory'] = info['total_memory'] / 1024
353 info['free_memory'] = info['free_memory'] / 1024
355 ITEM_ORDER = ['nr_cpus',
356 'nr_nodes',
357 'sockets_per_node',
358 'cores_per_socket',
359 'threads_per_core',
360 'cpu_mhz',
361 'hw_caps',
362 'total_memory',
363 'free_memory',
364 ]
366 return [[k, info[k]] for k in ITEM_ORDER]
369 def xeninfo(self):
370 info = self.xc.xeninfo()
372 ITEM_ORDER = ['xen_major',
373 'xen_minor',
374 'xen_extra',
375 'xen_caps',
376 'xen_pagesize',
377 'platform_params',
378 'xen_changeset',
379 'cc_compiler',
380 'cc_compile_by',
381 'cc_compile_domain',
382 'cc_compile_date',
383 ]
385 return [[k, info[k]] for k in ITEM_ORDER]
387 def xendinfo(self):
388 return [['xend_config_format', 3]]
390 # dictionary version of *info() functions to get rid of
391 # SXPisms.
392 def nodeinfo_dict(self):
393 return dict(self.nodeinfo())
394 def xendinfo_dict(self):
395 return dict(self.xendinfo())
396 def xeninfo_dict(self):
397 return dict(self.xeninfo())
398 def physinfo_dict(self):
399 return dict(self.physinfo())
400 def info_dict(self):
401 return dict(self.info())
404 def refreshBridges(self):
405 for pif in self.pifs.values():
406 pif.refresh(Brctl.get_state())
409 def instance():
410 global inst
411 try:
412 inst
413 except:
414 inst = XendNode()
415 inst.save()
416 return inst