ia64/xen-unstable

view tools/python/xen/xend/XendDomain.py @ 19580:a63d20d7a941

xend: Fix for op_pincpu in SrvDomain.py

op_pincpu method in SrvDomain.py does not currently work because
op_pincpu method gives string objects to a cpumap argument of
domain_pincpu method in XendDomain.py though the cpumap argument
expects list objects.

This patch solves the above problem as follows.

op_pincpu method gives string objects to the cpumap argument as is,
because op_pincpu method cannot give list objects to the cpumap
argument.
Instead, domain_pincpu method expects that the cpumap argument is
string objects, then domain_pincpu method converts the cpumap
argument into list objects.
Also, the patch modifies two methods (except for op_pincpu method)
calling domain_pincpu method. The methods give string objects to
the cpumap argument instead of list objects.

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Apr 27 15:42:38 2009 +0100 (2009-04-27)
parents 01873414cfc1
children 94bf7d4854eb
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) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
17 # Copyright (C) 2005 XenSource Ltd
18 #============================================================================
20 """Handler for domain operations.
21 Nothing here is persistent (across reboots).
22 Needs to be persistent for one uptime.
23 """
25 import os
26 import stat
27 import shutil
28 import socket
29 import tempfile
30 import threading
32 import xen.lowlevel.xc
35 from xen.xend import XendOptions, XendCheckpoint, XendDomainInfo
36 from xen.xend.PrettyPrint import prettyprint
37 from xen.xend import XendConfig, image
38 from xen.xend.XendError import XendError, XendInvalidDomain, VmError
39 from xen.xend.XendError import VMBadState
40 from xen.xend.XendLogging import log
41 from xen.xend.XendAPIConstants import XEN_API_VM_POWER_STATE
42 from xen.xend.XendConstants import XS_VMROOT
43 from xen.xend.XendConstants import DOM_STATE_HALTED, DOM_STATE_PAUSED
44 from xen.xend.XendConstants import DOM_STATE_RUNNING, DOM_STATE_SUSPENDED
45 from xen.xend.XendConstants import DOM_STATE_SHUTDOWN, DOM_STATE_UNKNOWN
46 from xen.xend.XendConstants import DOM_STATE_CRASHED, HVM_PARAM_ACPI_S_STATE
47 from xen.xend.XendConstants import TRIGGER_TYPE, TRIGGER_S3RESUME
48 from xen.xend.XendDevices import XendDevices
49 from xen.xend.XendAPIConstants import *
51 from xen.xend.xenstore.xstransact import xstransact
52 from xen.xend.xenstore.xswatch import xswatch
53 from xen.util import mkdir, rwlock
54 from xen.xend import uuid
56 xc = xen.lowlevel.xc.xc()
57 xoptions = XendOptions.instance()
59 __all__ = [ "XendDomain" ]
61 CACHED_CONFIG_FILE = 'config.sxp'
62 CHECK_POINT_FILE = 'checkpoint.chk'
63 DOM0_UUID = "00000000-0000-0000-0000-000000000000"
64 DOM0_NAME = "Domain-0"
65 DOM0_ID = 0
67 POWER_STATE_NAMES = dict([(x, XEN_API_VM_POWER_STATE[x])
68 for x in [DOM_STATE_HALTED,
69 DOM_STATE_PAUSED,
70 DOM_STATE_RUNNING,
71 DOM_STATE_SUSPENDED,
72 DOM_STATE_SHUTDOWN,
73 DOM_STATE_CRASHED,
74 DOM_STATE_UNKNOWN]])
75 POWER_STATE_ALL = 'all'
78 class XendDomain:
79 """Index of all domains. Singleton.
81 @ivar domains: map of domains indexed by domid
82 @type domains: dict of XendDomainInfo
83 @ivar managed_domains: domains that are not running and managed by Xend
84 @type managed_domains: dict of XendDomainInfo indexed by uuid
85 @ivar domains_lock: lock that must be held when manipulating self.domains
86 @type domains_lock: threaading.RLock
87 @ivar _allow_new_domains: Flag to set that allows creating of new domains.
88 @type _allow_new_domains: boolean
89 """
91 def __init__(self):
92 self.domains = {}
93 self.managed_domains = {}
94 self.domains_lock = threading.RLock()
96 self.policy_lock = rwlock.RWLock()
98 # xen api instance vars
99 # TODO: nothing uses this at the moment
100 self._allow_new_domains = True
102 # This must be called only the once, by instance() below. It is separate
103 # from the constructor because XendDomainInfo calls back into this class
104 # in order to check the uniqueness of domain names. This means that
105 # instance() must be able to return a valid instance of this class even
106 # during this initialisation.
107 def init(self):
108 """Singleton initialisation function."""
110 dom_path = self._managed_path()
111 mkdir.parents(dom_path, stat.S_IRWXU)
113 xstransact.Mkdir(XS_VMROOT)
114 xstransact.SetPermissions(XS_VMROOT, {'dom': DOM0_ID})
116 self.domains_lock.acquire()
117 try:
118 try:
119 dom0info = [d for d in self._running_domains() \
120 if d.get('domid') == DOM0_ID][0]
122 dom0info['name'] = DOM0_NAME
123 dom0 = XendDomainInfo.recreate(dom0info, True)
124 except IndexError:
125 raise XendError('Unable to find Domain 0')
127 self._setDom0CPUCount()
129 # This watch registration needs to be before the refresh call, so
130 # that we're sure that we haven't missed any releases, but inside
131 # the domains_lock, as we don't want the watch to fire until after
132 # the refresh call has completed.
133 xswatch("@introduceDomain", self._on_domains_changed)
134 xswatch("@releaseDomain", self._on_domains_changed)
136 self._init_domains()
137 finally:
138 self.domains_lock.release()
141 def _on_domains_changed(self, _):
142 """ Callback method when xenstore changes.
144 Calls refresh which will keep the local cache of domains
145 in sync.
147 @rtype: int
148 @return: 1
149 """
150 self.domains_lock.acquire()
151 try:
152 self._refresh()
153 finally:
154 self.domains_lock.release()
155 return 1
157 def _init_domains(self):
158 """Does the initial scan of managed and active domains to
159 populate self.domains.
161 Note: L{XendDomainInfo._checkName} will call back into XendDomain
162 to make sure domain name is not a duplicate.
164 """
165 self.domains_lock.acquire()
166 try:
167 running = self._running_domains()
168 managed = self._managed_domains()
170 # add all active domains
171 for dom in running:
172 if dom['dying'] == 1:
173 log.warn('Ignoring dying domain %d from now on' %
174 dom['domid'])
175 continue
177 if dom['domid'] != DOM0_ID:
178 try:
179 new_dom = XendDomainInfo.recreate(dom, False)
180 except Exception:
181 log.exception("Failed to create reference to running "
182 "domain id: %d" % dom['domid'])
184 image.cleanup_stale_sentinel_fifos()
186 # add all managed domains as dormant domains.
187 for dom in managed:
188 dom_uuid = dom.get('uuid')
189 if not dom_uuid:
190 continue
192 dom_name = dom.get('name_label', 'Domain-%s' % dom_uuid)
193 try:
194 running_dom = self.domain_lookup_nr(dom_name)
195 if not running_dom:
196 # instantiate domain if not started.
197 new_dom = XendDomainInfo.createDormant(dom)
198 self._managed_domain_register(new_dom)
199 else:
200 self._managed_domain_register(running_dom)
201 for key in XendConfig.XENAPI_CFG_TYPES.keys():
202 if key not in XendConfig.LEGACY_XENSTORE_VM_PARAMS and \
203 key in dom:
204 running_dom.info[key] = dom[key]
205 except Exception:
206 log.exception("Failed to create reference to managed "
207 "domain: %s" % dom_name)
209 finally:
210 self.domains_lock.release()
213 # -----------------------------------------------------------------
214 # Getting managed domains storage path names
216 def _managed_path(self, domuuid = None):
217 """Returns the path of the directory where managed domain
218 information is stored.
220 @keyword domuuid: If not None, will return the path to the domain
221 otherwise, will return the path containing
222 the directories which represent each domain.
223 @type: None or String.
224 @rtype: String
225 @return: Path.
226 """
227 dom_path = xoptions.get_xend_domains_path()
228 if domuuid:
229 dom_path = os.path.join(dom_path, domuuid)
230 return dom_path
232 def _managed_config_path(self, domuuid):
233 """Returns the path to the configuration file of a managed domain.
235 @param domname: Domain uuid
236 @type domname: String
237 @rtype: String
238 @return: path to config file.
239 """
240 return os.path.join(self._managed_path(domuuid), CACHED_CONFIG_FILE)
242 def _managed_check_point_path(self, domuuid):
243 """Returns absolute path to check point file for managed domain.
245 @param domuuid: Name of managed domain
246 @type domname: String
247 @rtype: String
248 @return: Path
249 """
250 return os.path.join(self._managed_path(domuuid), CHECK_POINT_FILE)
252 def _managed_config_remove(self, domuuid):
253 """Removes a domain configuration from managed list
255 @param domuuid: Name of managed domain
256 @type domname: String
257 @raise XendError: fails to remove the domain.
258 """
259 config_path = self._managed_path(domuuid)
260 try:
261 if os.path.exists(config_path) and os.path.isdir(config_path):
262 shutil.rmtree(config_path)
263 except IOError:
264 log.exception('managed_config_remove failed removing conf')
265 raise XendError("Unable to remove managed configuration"
266 " for domain: %s" % domuuid)
268 def managed_config_save(self, dominfo):
269 """Save a domain's configuration to disk
271 @param domninfo: Managed domain to save.
272 @type dominfo: XendDomainInfo
273 @raise XendError: fails to save configuration.
274 @rtype: None
275 """
276 if not self.is_domain_managed(dominfo):
277 return # refuse to save configuration this domain isn't managed
279 if dominfo:
280 domains_dir = self._managed_path()
281 dom_uuid = dominfo.get_uuid()
282 domain_config_dir = self._managed_path(dom_uuid)
284 def make_or_raise(path):
285 try:
286 mkdir.parents(path, stat.S_IRWXU)
287 except:
288 log.exception("%s could not be created." % path)
289 raise XendError("%s could not be created." % path)
291 make_or_raise(domains_dir)
292 make_or_raise(domain_config_dir)
294 try:
295 fd, fn = tempfile.mkstemp()
296 f = os.fdopen(fd, 'w+b')
297 try:
298 prettyprint(dominfo.sxpr(legacy_only = False), f,
299 width = 78)
300 finally:
301 f.close()
303 try:
304 shutil.move(fn, self._managed_config_path(dom_uuid))
305 except:
306 log.exception("Renaming %s to %s", fn,
307 self._managed_config_path(dom_uuid))
308 os.remove(fn)
309 except:
310 log.exception("Error occurred saving configuration file " +
311 "to %s" % domain_config_dir)
312 raise XendError("Failed to save configuration file to: %s" %
313 domain_config_dir)
314 else:
315 log.warn("Trying to save configuration for invalid domain")
318 def _managed_domains(self):
319 """ Returns list of domains that are managed.
321 Expects to be protected by domains_lock.
323 @rtype: list of XendConfig
324 @return: List of domain configurations that are managed.
325 """
326 dom_path = self._managed_path()
327 dom_uuids = os.listdir(dom_path)
328 doms = []
329 for dom_uuid in dom_uuids:
330 try:
331 cfg_file = self._managed_config_path(dom_uuid)
332 cfg = XendConfig.XendConfig(filename = cfg_file)
333 if cfg.get('uuid') != dom_uuid:
334 # something is wrong with the SXP
335 log.error("UUID mismatch in stored configuration: %s" %
336 cfg_file)
337 continue
338 doms.append(cfg)
339 except Exception:
340 log.exception('Unable to open or parse config.sxp: %s' % \
341 cfg_file)
342 return doms
344 def _managed_domain_unregister(self, dom):
345 try:
346 if self.is_domain_managed(dom):
347 self._managed_config_remove(dom.get_uuid())
348 del self.managed_domains[dom.get_uuid()]
349 dom.destroy_xapi_instances()
350 except ValueError:
351 log.warn("Domain is not registered: %s" % dom.get_uuid())
353 def _managed_domain_register(self, dom):
354 self.managed_domains[dom.get_uuid()] = dom
356 def is_domain_managed(self, dom = None):
357 return (dom.get_uuid() in self.managed_domains)
359 # End of Managed Domain Access
360 # --------------------------------------------------------------------
362 def _running_domains(self):
363 """Get table of domains indexed by id from xc.
365 @requires: Expects to be protected by domains_lock.
366 @rtype: list of dicts
367 @return: A list of dicts representing the running domains.
368 """
369 try:
370 return xc.domain_getinfo()
371 except RuntimeError, e:
372 log.exception("Unable to get domain information.")
373 return {}
375 def _setDom0CPUCount(self):
376 """Sets the number of VCPUs dom0 has. Retreived from the
377 Xend configuration, L{XendOptions}.
379 @requires: Expects to be protected by domains_lock.
380 @rtype: None
381 """
382 dom0 = self.privilegedDomain()
384 # get max number of vcpus to use for dom0 from config
385 target = int(xoptions.get_dom0_vcpus())
386 log.debug("number of vcpus to use is %d", target)
388 # target == 0 means use all processors
389 if target > 0:
390 dom0.setVCpuCount(target)
393 def _refresh(self, refresh_shutdown = True):
394 """Refresh the domain list. Needs to be called when
395 either xenstore has changed or when a method requires
396 up to date information (like uptime, cputime stats).
398 Expects to be protected by the domains_lock.
400 @rtype: None
401 """
403 txn = xstransact()
404 try:
405 self._refreshTxn(txn, refresh_shutdown)
406 txn.commit()
407 except:
408 txn.abort()
409 raise
411 def _refreshTxn(self, transaction, refresh_shutdown):
412 running = self._running_domains()
413 # Add domains that are not already tracked but running in Xen,
414 # and update domain state for those that are running and tracked.
415 for dom in running:
416 domid = dom['domid']
417 if domid in self.domains:
418 self.domains[domid].update(dom, refresh_shutdown, transaction)
419 elif domid not in self.domains and dom['dying'] != 1:
420 try:
421 new_dom = XendDomainInfo.recreate(dom, False)
422 except VmError:
423 log.exception("Unable to recreate domain")
424 try:
425 xc.domain_pause(domid)
426 XendDomainInfo.do_FLR(domid)
427 xc.domain_destroy(domid)
428 except:
429 log.exception("Hard destruction of domain failed: %d" %
430 domid)
432 # update information for all running domains
433 # - like cpu_time, status, dying, etc.
434 # remove domains that are not running from active domain list.
435 # The list might have changed by now, because the update call may
436 # cause new domains to be added, if the domain has rebooted. We get
437 # the list again.
438 running = self._running_domains()
439 running_domids = [d['domid'] for d in running if d['dying'] != 1]
440 for domid, dom in self.domains.items():
441 if domid not in running_domids and domid != DOM0_ID:
442 self._remove_domain(dom, domid)
445 def add_domain(self, info):
446 """Add a domain to the list of running domains
448 @requires: Expects to be protected by the domains_lock.
449 @param info: XendDomainInfo of a domain to be added.
450 @type info: XendDomainInfo
451 """
452 log.debug("Adding Domain: %s" % info.getDomid())
453 self.domains[info.getDomid()] = info
455 # update the managed domains with a new XendDomainInfo object
456 # if we are keeping track of it.
457 if info.get_uuid() in self.managed_domains:
458 self._managed_domain_register(info)
460 def remove_domain(self, info, domid = None):
461 """Remove the domain from the list of running domains, taking the
462 domains_lock first.
463 """
464 self.domains_lock.acquire()
465 try:
466 self._remove_domain(info, domid)
467 finally:
468 self.domains_lock.release()
470 def _remove_domain(self, info, domid = None):
471 """Remove the domain from the list of running domains
473 @requires: Expects to be protected by the domains_lock.
474 @param info: XendDomainInfo of a domain to be removed.
475 @type info: XendDomainInfo
476 """
477 if info:
478 if domid == None:
479 domid = info.getDomid()
481 if info._stateGet() != DOM_STATE_HALTED:
482 info.cleanupDomain()
484 if domid in self.domains:
485 del self.domains[domid]
487 info.destroy_xapi_instances()
488 else:
489 log.warning("Attempted to remove non-existent domain.")
491 def restore_(self, config):
492 """Create a domain as part of the restore process. This is called
493 only from L{XendCheckpoint}.
495 A restore request comes into XendDomain through L{domain_restore}
496 or L{domain_restore_fd}. That request is
497 forwarded immediately to XendCheckpoint which, when it is ready, will
498 call this method. It is necessary to come through here rather than go
499 directly to L{XendDomainInfo.restore} because we need to
500 serialise the domain creation process, but cannot lock
501 domain_restore_fd as a whole, otherwise we will deadlock waiting for
502 the old domain to die.
504 @param config: Configuration of domain to restore
505 @type config: SXP Object (eg. list of lists)
506 """
507 self.domains_lock.acquire()
508 try:
509 dominfo = XendDomainInfo.restore(config)
510 return dominfo
511 finally:
512 self.domains_lock.release()
515 def domain_lookup(self, domid):
516 """Look up given I{domid} in the list of managed and running
517 domains.
519 @note: Will cause a refresh before lookup up domains, for
520 a version that does not need to re-read xenstore
521 use L{domain_lookup_nr}.
523 @param domid: Domain ID or Domain Name.
524 @type domid: int or string
525 @return: Found domain.
526 @rtype: XendDomainInfo
527 @raise XendInvalidDomain: If domain is not found.
528 """
529 self.domains_lock.acquire()
530 try:
531 self._refresh(refresh_shutdown = False)
532 dom = self.domain_lookup_nr(domid)
533 if not dom:
534 raise XendInvalidDomain(str(domid))
535 return dom
536 finally:
537 self.domains_lock.release()
540 def domain_lookup_nr(self, domid):
541 """Look up given I{domid} in the list of managed and running
542 domains.
544 @param domid: Domain ID or Domain Name.
545 @type domid: int or string
546 @return: Found domain.
547 @rtype: XendDomainInfo or None
548 """
549 self.domains_lock.acquire()
550 try:
551 # lookup by name
552 match = [dom for dom in self.domains.values() \
553 if dom.getName() == domid]
554 if match:
555 return match[0]
557 match = [dom for dom in self.managed_domains.values() \
558 if dom.getName() == domid]
559 if match:
560 return match[0]
562 # lookup by id
563 try:
564 if int(domid) in self.domains:
565 return self.domains[int(domid)]
566 except ValueError:
567 pass
569 # lookup by uuid for running domains
570 match = [dom for dom in self.domains.values() \
571 if dom.get_uuid() == domid]
572 if match:
573 return match[0]
575 # lookup by uuid for inactive managed domains
576 if domid in self.managed_domains:
577 return self.managed_domains[domid]
579 return None
580 finally:
581 self.domains_lock.release()
583 def privilegedDomain(self):
584 """ Get the XendDomainInfo of a dom0
586 @rtype: XendDomainInfo
587 """
588 self.domains_lock.acquire()
589 try:
590 return self.domains[DOM0_ID]
591 finally:
592 self.domains_lock.release()
594 def autostart_domains(self):
595 """ Autostart managed domains that are marked as such. """
597 need_starting = []
599 self.domains_lock.acquire()
600 try:
601 for dom_uuid, dom in self.managed_domains.items():
602 if dom and dom._stateGet() == DOM_STATE_HALTED:
603 on_xend_start = dom.info.get('on_xend_start', 'ignore')
604 auto_power_on = dom.info.get('auto_power_on', False)
605 should_start = (on_xend_start == 'start') or auto_power_on
606 if should_start:
607 need_starting.append(dom_uuid)
608 finally:
609 self.domains_lock.release()
611 for dom_uuid in need_starting:
612 self.domain_start(dom_uuid, False)
614 def cleanup_domains(self):
615 """Clean up domains that are marked as autostop.
616 Should be called when Xend goes down. This is currently
617 called from L{xen.xend.servers.XMLRPCServer}.
619 """
620 log.debug('cleanup_domains')
621 self.domains_lock.acquire()
622 try:
623 for dom in self.domains.values():
624 if dom.getName() == DOM0_NAME:
625 continue
627 try:
628 if dom._stateGet() == DOM_STATE_RUNNING:
629 shutdownAction = dom.info.get('on_xend_stop', 'ignore')
630 if shutdownAction == 'shutdown':
631 log.debug('Shutting down domain: %s' % dom.getName())
632 dom.shutdown("poweroff")
633 elif shutdownAction == 'suspend':
634 self.domain_suspend(dom.getName())
635 else:
636 log.debug('Domain %s continues to run.' % dom.getName())
637 except:
638 log.exception('Domain %s failed to %s.' % \
639 (dom.getName(), shutdownAction))
640 finally:
641 self.domains_lock.release()
645 # ----------------------------------------------------------------
646 # Xen API
649 def set_allow_new_domains(self, allow_new_domains):
650 self._allow_new_domains = allow_new_domains
652 def allow_new_domains(self):
653 return self._allow_new_domains
655 def get_domain_refs(self):
656 result = []
657 try:
658 self.domains_lock.acquire()
659 result = [d.get_uuid() for d in self.domains.values()]
660 for d in self.managed_domains.keys():
661 if d not in result:
662 result.append(d)
663 return result
664 finally:
665 self.domains_lock.release()
667 def get_all_vms(self):
668 self.domains_lock.acquire()
669 try:
670 result = self.domains.values()
671 result += [x for x in self.managed_domains.values() if
672 x not in result]
673 return result
674 finally:
675 self.domains_lock.release()
677 def get_vm_by_uuid(self, vm_uuid):
678 self.domains_lock.acquire()
679 try:
680 for dom in self.domains.values():
681 if dom.get_uuid() == vm_uuid:
682 return dom
684 if vm_uuid in self.managed_domains:
685 return self.managed_domains[vm_uuid]
687 return None
688 finally:
689 self.domains_lock.release()
691 def get_vm_with_dev_uuid(self, klass, dev_uuid):
692 self.domains_lock.acquire()
693 try:
694 for dom in self.domains.values() + self.managed_domains.values():
695 if dom.has_device(klass, dev_uuid):
696 return dom
697 return None
698 finally:
699 self.domains_lock.release()
701 def get_dev_property_by_uuid(self, klass, dev_uuid, field):
702 value = None
703 self.domains_lock.acquire()
705 try:
706 try:
707 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
708 if dom:
709 value = dom.get_dev_property(klass, dev_uuid, field)
710 except ValueError, e:
711 pass
712 finally:
713 self.domains_lock.release()
715 return value
717 def set_dev_property_by_uuid(self, klass, dev_uuid, field, value,
718 old_val = None):
719 rc = True
720 self.domains_lock.acquire()
722 try:
723 try:
724 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
725 if dom:
726 o_val = dom.get_dev_property(klass, dev_uuid, field)
727 log.info("o_val=%s, old_val=%s" % (o_val, old_val))
728 if old_val and old_val != o_val:
729 return False
731 dom.set_dev_property(klass, dev_uuid, field, value)
732 self.managed_config_save(dom)
733 except ValueError, e:
734 pass
735 finally:
736 self.domains_lock.release()
738 return rc
740 def is_valid_vm(self, vm_ref):
741 return (self.get_vm_by_uuid(vm_ref) != None)
743 def is_valid_dev(self, klass, dev_uuid):
744 return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None)
746 def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs):
747 dom = self.uuid_to_dom(vm_uuid)
748 fn(dom, *args, **kwargs)
750 def uuid_to_dom(self, vm_uuid):
751 self.domains_lock.acquire()
752 try:
753 for domid, dom in self.domains.items():
754 if dom.get_uuid() == vm_uuid:
755 return domid
757 if vm_uuid in self.managed_domains:
758 domid = self.managed_domains[vm_uuid].getDomid()
759 if domid is None:
760 return self.managed_domains[vm_uuid].getName()
761 else:
762 return domid
764 raise XendInvalidDomain(vm_uuid)
765 finally:
766 self.domains_lock.release()
769 def create_domain(self, xenapi_vm):
770 self.domains_lock.acquire()
771 try:
772 try:
773 xeninfo = XendConfig.XendConfig(xapi = xenapi_vm)
774 dominfo = XendDomainInfo.createDormant(xeninfo)
775 log.debug("Creating new managed domain: %s: %s" %
776 (dominfo.getName(), dominfo.get_uuid()))
777 self._managed_domain_register(dominfo)
778 self.managed_config_save(dominfo)
779 return dominfo.get_uuid()
780 except XendError, e:
781 raise
782 except Exception, e:
783 raise XendError(str(e))
784 finally:
785 self.domains_lock.release()
787 def rename_domain(self, dom, new_name):
788 self.domains_lock.acquire()
789 try:
790 old_name = dom.getName()
791 dom.setName(new_name)
793 finally:
794 self.domains_lock.release()
797 #
798 # End of Xen API
799 # ----------------------------------------------------------------
801 # ------------------------------------------------------------
802 # Xen Legacy API
804 def list(self, state = DOM_STATE_RUNNING):
805 """Get list of domain objects.
807 @param: the state in which the VMs should be -- one of the
808 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
809 @return: domains
810 @rtype: list of XendDomainInfo
811 """
812 if type(state) == int:
813 state = POWER_STATE_NAMES[state]
814 state = state.lower()
816 self.domains_lock.acquire()
817 try:
818 self._refresh(refresh_shutdown = False)
820 # active domains
821 active_domains = self.domains.values()
822 active_uuids = [d.get_uuid() for d in active_domains]
824 # inactive domains
825 inactive_domains = []
826 for dom_uuid, dom in self.managed_domains.items():
827 if dom_uuid not in active_uuids:
828 inactive_domains.append(dom)
830 if state == POWER_STATE_ALL:
831 return active_domains + inactive_domains
832 else:
833 return filter(lambda x:
834 POWER_STATE_NAMES[x._stateGet()].lower() == state,
835 active_domains + inactive_domains)
836 finally:
837 self.domains_lock.release()
840 def list_sorted(self, state = DOM_STATE_RUNNING):
841 """Get list of domain objects, sorted by name.
843 @param: the state in which the VMs should be -- one of the
844 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
845 @return: domain objects
846 @rtype: list of XendDomainInfo
847 """
848 doms = self.list(state)
849 doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
850 return doms
852 def list_names(self, state = DOM_STATE_RUNNING):
853 """Get list of domain names.
855 @param: the state in which the VMs should be -- one of the
856 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
857 @return: domain names
858 @rtype: list of strings.
859 """
860 return [d.getName() for d in self.list_sorted(state)]
862 def domain_suspend(self, domname):
863 """Suspends a domain that is persistently managed by Xend
865 @param domname: Domain Name
866 @type domname: string
867 @rtype: None
868 @raise XendError: Failure during checkpointing.
869 """
871 try:
872 dominfo = self.domain_lookup_nr(domname)
873 if not dominfo:
874 raise XendInvalidDomain(domname)
876 if dominfo.getDomid() == DOM0_ID:
877 raise XendError("Cannot suspend privileged domain %s" % domname)
879 if dominfo._stateGet() != DOM_STATE_RUNNING:
880 raise VMBadState("Domain is not running",
881 POWER_STATE_NAMES[DOM_STATE_RUNNING],
882 POWER_STATE_NAMES[dominfo._stateGet()])
884 dom_uuid = dominfo.get_uuid()
886 if not os.path.exists(self._managed_config_path(dom_uuid)):
887 raise XendError("Domain is not managed by Xend lifecycle " +
888 "support.")
890 path = self._managed_check_point_path(dom_uuid)
891 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
892 if hasattr(os, "O_LARGEFILE"):
893 oflags |= os.O_LARGEFILE
894 fd = os.open(path, oflags)
895 try:
896 # For now we don't support 'live checkpoint'
897 XendCheckpoint.save(fd, dominfo, False, False, path)
898 finally:
899 os.close(fd)
900 except OSError, ex:
901 raise XendError("can't write guest state file %s: %s" %
902 (path, ex[1]))
904 def domain_resume(self, domname, start_paused = False):
905 """Resumes a domain that is persistently managed by Xend.
907 @param domname: Domain Name
908 @type domname: string
909 @rtype: None
910 @raise XendError: If failed to restore.
911 """
912 self.domains_lock.acquire()
913 try:
914 try:
915 fd = None
916 dominfo = self.domain_lookup_nr(domname)
918 if not dominfo:
919 raise XendInvalidDomain(domname)
921 if dominfo.getDomid() == DOM0_ID:
922 raise XendError("Cannot resume privileged domain %s" % domname)
924 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_SUSPENDED:
925 raise XendError("Cannot resume domain that is not suspended.")
927 dominfo.setResume(True)
929 dom_uuid = dominfo.get_uuid()
930 chkpath = self._managed_check_point_path(dom_uuid)
931 if not os.path.exists(chkpath):
932 raise XendError("Domain was not suspended by Xend")
934 # Restore that replaces the existing XendDomainInfo
935 try:
936 log.debug('Current DomainInfo state: %d' % dominfo._stateGet())
937 oflags = os.O_RDONLY
938 if hasattr(os, "O_LARGEFILE"):
939 oflags |= os.O_LARGEFILE
940 fd = os.open(chkpath, oflags)
941 XendCheckpoint.restore(self,
942 fd,
943 dominfo,
944 paused = start_paused)
945 os.unlink(chkpath)
946 except OSError, ex:
947 raise XendError("Failed to read stored checkpoint file")
948 except IOError, ex:
949 raise XendError("Failed to delete checkpoint file")
950 except Exception, ex:
951 log.exception("Exception occurred when resuming")
952 raise XendError("Error occurred when resuming: %s" % str(ex))
953 finally:
954 if fd is not None:
955 os.close(fd)
956 self.domains_lock.release()
959 def domain_create(self, config):
960 """Create a domain from a configuration.
962 @param config: configuration
963 @type config: SXP Object (list of lists)
964 @rtype: XendDomainInfo
965 """
966 self.domains_lock.acquire()
967 try:
968 self._refresh()
970 dominfo = XendDomainInfo.create(config)
971 return dominfo
972 finally:
973 self.domains_lock.release()
976 def domain_create_from_dict(self, config_dict):
977 """Create a domain from a configuration dictionary.
979 @param config_dict: configuration
980 @rtype: XendDomainInfo
981 """
982 self.domains_lock.acquire()
983 try:
984 self._refresh()
986 dominfo = XendDomainInfo.create_from_dict(config_dict)
987 return dominfo
988 finally:
989 self.domains_lock.release()
992 def domain_new(self, config):
993 """Create a domain from a configuration but do not start it.
995 @param config: configuration
996 @type config: SXP Object (list of lists)
997 @rtype: XendDomainInfo
998 """
999 self.domains_lock.acquire()
1000 try:
1001 try:
1002 domconfig = XendConfig.XendConfig(sxp_obj = config)
1003 dominfo = XendDomainInfo.createDormant(domconfig)
1004 log.debug("Creating new managed domain: %s" %
1005 dominfo.getName())
1006 self._managed_domain_register(dominfo)
1007 self.managed_config_save(dominfo)
1008 # no return value because it isn't meaningful for client
1009 except XendError, e:
1010 raise
1011 except Exception, e:
1012 raise XendError(str(e))
1013 finally:
1014 self.domains_lock.release()
1016 def domain_start(self, domid, start_paused = True):
1017 """Start a managed domain
1019 @require: Domain must not be running.
1020 @param domid: Domain name or domain ID.
1021 @type domid: string or int
1022 @rtype: None
1023 @raise XendError: If domain is still running
1024 @rtype: None
1025 """
1026 self.domains_lock.acquire()
1027 try:
1028 self._refresh()
1030 dominfo = self.domain_lookup_nr(domid)
1031 if not dominfo:
1032 raise XendInvalidDomain(str(domid))
1034 if dominfo._stateGet() != DOM_STATE_HALTED:
1035 raise VMBadState("Domain is already running",
1036 POWER_STATE_NAMES[DOM_STATE_HALTED],
1037 POWER_STATE_NAMES[dominfo._stateGet()])
1039 dominfo.start(is_managed = True)
1040 finally:
1041 self.domains_lock.release()
1043 try:
1044 dominfo.waitForDevices()
1045 except Exception, ex:
1046 log.warn("Failed to setup devices for " + str(dominfo) + ": " + str(ex))
1047 dominfo.destroy()
1048 raise
1050 if not start_paused:
1051 dominfo.unpause()
1053 def domain_delete(self, domid):
1054 """Remove a managed domain from database
1056 @require: Domain must not be running.
1057 @param domid: Domain name or domain ID.
1058 @type domid: string or int
1059 @rtype: None
1060 @raise XendError: If domain is still running
1061 """
1062 self.domains_lock.acquire()
1063 try:
1064 try:
1065 dominfo = self.domain_lookup_nr(domid)
1066 if not dominfo:
1067 raise XendInvalidDomain(str(domid))
1069 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED:
1070 raise VMBadState("Domain is not halted.",
1071 POWER_STATE_NAMES[DOM_STATE_HALTED],
1072 POWER_STATE_NAMES[dominfo._stateGet()])
1074 self._domain_delete_by_info(dominfo)
1075 except Exception, ex:
1076 raise XendError(str(ex))
1077 finally:
1078 self.domains_lock.release()
1081 def domain_delete_by_dominfo(self, dominfo):
1082 """Only for use by XendDomainInfo.
1083 """
1084 self.domains_lock.acquire()
1085 try:
1086 self._domain_delete_by_info(dominfo)
1087 finally:
1088 self.domains_lock.release()
1091 def _domain_delete_by_info(self, dominfo):
1092 """Expects to be protected by domains_lock.
1093 """
1094 log.info("Domain %s (%s) deleted." %
1095 (dominfo.getName(), dominfo.info.get('uuid')))
1097 self._managed_domain_unregister(dominfo)
1098 self._remove_domain(dominfo)
1099 XendDevices.destroy_device_state(dominfo)
1102 def domain_configure(self, config):
1103 """Configure an existing domain.
1105 @param vmconfig: vm configuration
1106 @type vmconfig: SXP Object (list of lists)
1107 @todo: Not implemented
1108 """
1109 # !!!
1110 raise XendError("Unsupported")
1112 def domain_restore(self, src, paused=False):
1113 """Restore a domain from file.
1115 @param src: filename of checkpoint file to restore from
1116 @type src: string
1117 @return: Restored domain
1118 @rtype: XendDomainInfo
1119 @raise XendError: Failure to restore domain
1120 """
1121 try:
1122 oflags = os.O_RDONLY
1123 if hasattr(os, "O_LARGEFILE"):
1124 oflags |= os.O_LARGEFILE
1125 fd = os.open(src, oflags)
1126 try:
1127 return self.domain_restore_fd(fd, paused=paused)
1128 finally:
1129 os.close(fd)
1130 except OSError, ex:
1131 raise XendError("can't read guest state file %s: %s" %
1132 (src, ex[1]))
1134 def domain_restore_fd(self, fd, paused=False, relocating=False):
1135 """Restore a domain from the given file descriptor.
1137 @param fd: file descriptor of the checkpoint file
1138 @type fd: File object
1139 @rtype: XendDomainInfo
1140 @raise XendError: if failed to restore
1141 """
1143 try:
1144 self.policy_lock.acquire_reader()
1146 try:
1147 return XendCheckpoint.restore(self, fd, paused=paused, relocating=relocating)
1148 except XendError, e:
1149 log.exception("Restore failed")
1150 raise
1151 except:
1152 # I don't really want to log this exception here, but the error
1153 # handling in the relocation-socket handling code (relocate.py) is
1154 # poor, so we need to log this for debugging.
1155 log.exception("Restore failed")
1156 raise XendError("Restore failed")
1157 finally:
1158 self.policy_lock.release()
1160 def domain_unpause(self, domid):
1161 """Unpause domain execution.
1163 @param domid: Domain ID or Name
1164 @type domid: int or string.
1165 @rtype: None
1166 @raise XendError: Failed to unpause
1167 @raise XendInvalidDomain: Domain is not valid
1168 """
1169 try:
1170 dominfo = self.domain_lookup_nr(domid)
1171 if not dominfo:
1172 raise XendInvalidDomain(str(domid))
1173 if dominfo.getDomid() == DOM0_ID:
1174 raise XendError("Cannot unpause privileged domain %s" % domid)
1175 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
1176 raise VMBadState("Domain '%s' is not started" % domid,
1177 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1178 POWER_STATE_NAMES[dominfo._stateGet()])
1179 log.info("Domain %s (%d) unpaused.", dominfo.getName(),
1180 int(dominfo.getDomid()))
1181 dominfo.unpause()
1182 except XendInvalidDomain:
1183 log.exception("domain_unpause")
1184 raise
1185 except Exception, ex:
1186 log.exception("domain_unpause")
1187 raise XendError(str(ex))
1189 def domain_pause(self, domid, state=False):
1190 """Pause domain execution.
1192 @param domid: Domain ID or Name
1193 @type domid: int or string.
1194 @keyword state: If True, will return the domain state before pause
1195 @type state: bool
1196 @rtype: int if state is True
1197 @return: Domain state (DOM_STATE_*)
1198 @rtype: None if state is False
1199 @raise XendError: Failed to pause
1200 @raise XendInvalidDomain: Domain is not valid
1201 """
1202 try:
1203 dominfo = self.domain_lookup_nr(domid)
1204 if not dominfo:
1205 raise XendInvalidDomain(str(domid))
1206 if dominfo.getDomid() == DOM0_ID:
1207 raise XendError("Cannot pause privileged domain %s" % domid)
1208 ds = dominfo._stateGet()
1209 if ds not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED, DOM_STATE_CRASHED):
1210 raise VMBadState("Domain '%s' is not started" % domid,
1211 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1212 POWER_STATE_NAMES[ds])
1213 log.info("Domain %s (%d) paused.", dominfo.getName(),
1214 int(dominfo.getDomid()))
1215 if ds == DOM_STATE_RUNNING:
1216 dominfo.pause()
1217 if state:
1218 return ds
1219 except XendInvalidDomain:
1220 log.exception("domain_pause")
1221 raise
1222 except Exception, ex:
1223 log.exception("domain_pause")
1224 raise XendError(str(ex))
1226 def domain_dump(self, domid, filename=None, live=False, crash=False, reset=False):
1227 """Dump domain core."""
1229 dominfo = self.domain_lookup_nr(domid)
1230 if not dominfo:
1231 raise XendInvalidDomain(str(domid))
1233 if dominfo.getDomid() == DOM0_ID:
1234 raise XendError("Cannot dump core for privileged domain %s" % domid)
1235 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING, DOM_STATE_CRASHED):
1236 raise VMBadState("Domain '%s' is not started" % domid,
1237 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1238 POWER_STATE_NAMES[dominfo._stateGet()])
1240 dopause = (not live and dominfo._stateGet() == DOM_STATE_RUNNING)
1241 if dopause:
1242 dominfo.pause()
1244 try:
1245 try:
1246 log.info("Domain core dump requested for domain %s (%d) "
1247 "live=%d crash=%d reset=%d.",
1248 dominfo.getName(), dominfo.getDomid(), live, crash, reset)
1249 dominfo.dumpCore(filename)
1250 if crash:
1251 self.domain_destroy(domid)
1252 elif reset:
1253 self.domain_reset(domid)
1254 except Exception, ex:
1255 raise XendError(str(ex))
1256 finally:
1257 if dopause and not crash and not reset:
1258 dominfo.unpause()
1260 def domain_destroy(self, domid):
1261 """Terminate domain immediately.
1263 @param domid: Domain ID or Name
1264 @type domid: int or string.
1265 @rtype: None
1266 @raise XendError: Failed to destroy
1267 @raise XendInvalidDomain: Domain is not valid
1268 """
1270 dominfo = self.domain_lookup_nr(domid)
1271 if dominfo and dominfo.getDomid() == DOM0_ID:
1272 raise XendError("Cannot destroy privileged domain %s" % domid)
1274 if dominfo:
1275 val = dominfo.destroy()
1276 else:
1277 try:
1278 xc.domain_pause(int(domid))
1279 XendDomainInfo.do_FLR(int(domid))
1280 val = xc.domain_destroy(int(domid))
1281 except ValueError:
1282 raise XendInvalidDomain(domid)
1283 except Exception, e:
1284 raise XendError(str(e))
1286 return val
1288 def domain_migrate(self, domid, dst, live=False, port=0, node=-1, ssl=None):
1289 """Start domain migration.
1291 @param domid: Domain ID or Name
1292 @type domid: int or string.
1293 @param dst: Destination IP address
1294 @type dst: string
1295 @keyword live: Live migration
1296 @type live: bool
1297 @keyword port: relocation port on destination
1298 @type port: int
1299 @keyword node: use node number for target
1300 @type node: int
1301 @keyword ssl: use ssl connection
1302 @type ssl: bool
1303 @rtype: None
1304 @raise XendError: Failed to migrate
1305 @raise XendInvalidDomain: Domain is not valid
1306 """
1308 dominfo = self.domain_lookup_nr(domid)
1309 if not dominfo:
1310 raise XendInvalidDomain(str(domid))
1312 if dominfo.getDomid() == DOM0_ID:
1313 raise XendError("Cannot migrate privileged domain %s" % domid)
1314 if dominfo._stateGet() != DOM_STATE_RUNNING:
1315 raise VMBadState("Domain is not running",
1316 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1317 POWER_STATE_NAMES[dominfo._stateGet()])
1319 """ The following call may raise a XendError exception """
1320 dominfo.testMigrateDevices(True, dst)
1322 if live:
1323 """ Make sure there's memory free for enabling shadow mode """
1324 dominfo.checkLiveMigrateMemory()
1326 if ssl is None:
1327 ssl = xoptions.get_xend_relocation_ssl()
1329 if ssl:
1330 from OpenSSL import SSL
1331 from xen.web import connection
1332 if port == 0:
1333 port = xoptions.get_xend_relocation_ssl_port()
1334 try:
1335 ctx = SSL.Context(SSL.SSLv23_METHOD)
1336 sock = SSL.Connection(ctx,
1337 socket.socket(socket.AF_INET, socket.SOCK_STREAM))
1338 sock.set_connect_state()
1339 sock.connect((dst, port))
1340 sock.send("sslreceive\n")
1341 sock.recv(80)
1342 except SSL.Error, err:
1343 raise XendError("SSL error: %s" % err)
1344 except socket.error, err:
1345 raise XendError("can't connect: %s" % err)
1347 p2cread, p2cwrite = os.pipe()
1348 threading.Thread(target=connection.SSLSocketServerConnection.fd2send,
1349 args=(sock, p2cread)).start()
1351 try:
1352 XendCheckpoint.save(p2cwrite, dominfo, True, live, dst,
1353 node=node)
1354 finally:
1355 sock.shutdown()
1356 sock.close()
1358 os.close(p2cread)
1359 os.close(p2cwrite)
1360 else:
1361 if port == 0:
1362 port = xoptions.get_xend_relocation_port()
1363 try:
1364 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1365 # When connecting to our ssl enabled relocation server using a
1366 # plain socket, send will success but recv will block. Add a
1367 # 30 seconds timeout to raise a socket.timeout exception to
1368 # inform the client.
1369 sock.settimeout(30.0)
1370 sock.connect((dst, port))
1371 sock.send("receive\n")
1372 sock.recv(80)
1373 sock.settimeout(None)
1374 except socket.error, err:
1375 raise XendError("can't connect: %s" % err)
1377 try:
1378 XendCheckpoint.save(sock.fileno(), dominfo, True, live,
1379 dst, node=node)
1380 finally:
1381 sock.close()
1383 def domain_save(self, domid, dst, checkpoint=False):
1384 """Start saving a domain to file.
1386 @param domid: Domain ID or Name
1387 @type domid: int or string.
1388 @param dst: Destination filename
1389 @type dst: string
1390 @rtype: None
1391 @raise XendError: Failed to save domain
1392 @raise XendInvalidDomain: Domain is not valid
1393 """
1394 try:
1395 dominfo = self.domain_lookup_nr(domid)
1396 if not dominfo:
1397 raise XendInvalidDomain(str(domid))
1399 if dominfo.getDomid() == DOM0_ID:
1400 raise XendError("Cannot save privileged domain %s" % str(domid))
1401 if dominfo._stateGet() != DOM_STATE_RUNNING:
1402 raise VMBadState("Domain is not running",
1403 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1404 POWER_STATE_NAMES[dominfo._stateGet()])
1406 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
1407 if hasattr(os, "O_LARGEFILE"):
1408 oflags |= os.O_LARGEFILE
1409 fd = os.open(dst, oflags)
1410 try:
1411 XendCheckpoint.save(fd, dominfo, False, False, dst,
1412 checkpoint=checkpoint)
1413 except Exception, e:
1414 os.close(fd)
1415 raise e
1416 os.close(fd)
1417 except OSError, ex:
1418 raise XendError("can't write guest state file %s: %s" %
1419 (dst, ex[1]))
1421 def domain_pincpu(self, domid, vcpu, cpumap):
1422 """Set which cpus vcpu can use
1424 @param domid: Domain ID or Name
1425 @type domid: int or string.
1426 @param vcpu: vcpu to pin to
1427 @type vcpu: int
1428 @param cpumap: string repr of usable cpus
1429 @type cpumap: string
1430 @rtype: 0
1431 """
1432 dominfo = self.domain_lookup_nr(domid)
1433 if not dominfo:
1434 raise XendInvalidDomain(str(domid))
1436 # if vcpu is keyword 'all', apply the cpumap to all vcpus
1437 if str(vcpu).lower() == "all":
1438 vcpus = range(0, int(dominfo.getVCpuCount()))
1439 else:
1440 vcpus = [ int(vcpu) ]
1442 # set the same cpumask for all vcpus
1443 rc = 0
1444 cpus = dominfo.getCpus()
1445 cpumap = map(int, cpumap.split(","))
1446 for v in vcpus:
1447 try:
1448 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1449 rc = xc.vcpu_setaffinity(dominfo.getDomid(), v, cpumap)
1450 cpus[v] = cpumap
1451 except Exception, ex:
1452 log.exception(ex)
1453 raise XendError("Cannot pin vcpu: %d to cpu: %s - %s" % \
1454 (v, cpumap, str(ex)))
1455 dominfo.setCpus(cpus)
1456 self.managed_config_save(dominfo)
1458 return rc
1460 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
1461 weight):
1462 """Set Simple EDF scheduler parameters for a domain.
1464 @param domid: Domain ID or Name
1465 @type domid: int or string.
1466 @rtype: 0
1467 """
1468 dominfo = self.domain_lookup_nr(domid)
1469 if not dominfo:
1470 raise XendInvalidDomain(str(domid))
1471 try:
1472 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
1473 latency, extratime, weight)
1474 except Exception, ex:
1475 raise XendError(str(ex))
1477 def domain_cpu_sedf_get(self, domid):
1478 """Get Simple EDF scheduler parameters for a domain.
1480 @param domid: Domain ID or Name
1481 @type domid: int or string.
1482 @rtype: SXP object
1483 @return: The parameters for Simple EDF schedule for a domain.
1484 """
1485 dominfo = self.domain_lookup_nr(domid)
1486 if not dominfo:
1487 raise XendInvalidDomain(str(domid))
1488 try:
1489 sedf_info = xc.sedf_domain_get(dominfo.getDomid())
1490 # return sxpr
1491 return ['sedf',
1492 ['domid', sedf_info['domid']],
1493 ['period', sedf_info['period']],
1494 ['slice', sedf_info['slice']],
1495 ['latency', sedf_info['latency']],
1496 ['extratime', sedf_info['extratime']],
1497 ['weight', sedf_info['weight']]]
1499 except Exception, ex:
1500 raise XendError(str(ex))
1502 def domain_shadow_control(self, domid, op):
1503 """Shadow page control.
1505 @param domid: Domain ID or Name
1506 @type domid: int or string.
1507 @param op: operation
1508 @type op: int
1509 @rtype: 0
1510 """
1511 dominfo = self.domain_lookup(domid)
1512 try:
1513 return xc.shadow_control(dominfo.getDomid(), op)
1514 except Exception, ex:
1515 raise XendError(str(ex))
1517 def domain_shadow_mem_get(self, domid):
1518 """Get shadow pagetable memory allocation.
1520 @param domid: Domain ID or Name
1521 @type domid: int or string.
1522 @rtype: int
1523 @return: shadow memory in MB
1524 """
1525 dominfo = self.domain_lookup(domid)
1526 try:
1527 return xc.shadow_mem_control(dominfo.getDomid())
1528 except Exception, ex:
1529 raise XendError(str(ex))
1531 def domain_shadow_mem_set(self, domid, mb):
1532 """Set shadow pagetable memory allocation.
1534 @param domid: Domain ID or Name
1535 @type domid: int or string.
1536 @param mb: shadow memory to set in MB
1537 @type: mb: int
1538 @rtype: int
1539 @return: shadow memory in MB
1540 """
1541 dominfo = self.domain_lookup(domid)
1542 try:
1543 return xc.shadow_mem_control(dominfo.getDomid(), mb=mb)
1544 except Exception, ex:
1545 raise XendError(str(ex))
1547 def domain_sched_credit_get(self, domid):
1548 """Get credit scheduler parameters for a domain.
1550 @param domid: Domain ID or Name
1551 @type domid: int or string.
1552 @rtype: dict with keys 'weight' and 'cap'
1553 @return: credit scheduler parameters
1554 """
1555 dominfo = self.domain_lookup_nr(domid)
1556 if not dominfo:
1557 raise XendInvalidDomain(str(domid))
1559 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1560 try:
1561 return xc.sched_credit_domain_get(dominfo.getDomid())
1562 except Exception, ex:
1563 raise XendError(str(ex))
1564 else:
1565 return {'weight' : dominfo.getWeight(),
1566 'cap' : dominfo.getCap()}
1568 def domain_sched_credit_set(self, domid, weight = None, cap = None):
1569 """Set credit scheduler parameters for a domain.
1571 @param domid: Domain ID or Name
1572 @type domid: int or string.
1573 @type weight: int
1574 @type cap: int
1575 @rtype: 0
1576 """
1577 set_weight = False
1578 set_cap = False
1579 dominfo = self.domain_lookup_nr(domid)
1580 if not dominfo:
1581 raise XendInvalidDomain(str(domid))
1582 try:
1583 if weight is None:
1584 weight = int(0)
1585 elif weight < 1 or weight > 65535:
1586 raise XendError("weight is out of range")
1587 else:
1588 set_weight = True
1590 if cap is None:
1591 cap = int(~0)
1592 elif cap < 0 or cap > dominfo.getVCpuCount() * 100:
1593 raise XendError("cap is out of range")
1594 else:
1595 set_cap = True
1597 assert type(weight) == int
1598 assert type(cap) == int
1600 rc = 0
1601 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1602 rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap)
1603 if rc == 0:
1604 if set_weight:
1605 dominfo.setWeight(weight)
1606 if set_cap:
1607 dominfo.setCap(cap)
1608 self.managed_config_save(dominfo)
1609 return rc
1610 except Exception, ex:
1611 log.exception(ex)
1612 raise XendError(str(ex))
1614 def domain_maxmem_set(self, domid, mem):
1615 """Set the memory limit for a domain.
1617 @param domid: Domain ID or Name
1618 @type domid: int or string.
1619 @param mem: memory limit (in MiB)
1620 @type mem: int
1621 @raise XendError: fail to set memory
1622 @rtype: 0
1623 """
1624 dominfo = self.domain_lookup_nr(domid)
1625 if not dominfo:
1626 raise XendInvalidDomain(str(domid))
1627 dominfo.setMemoryMaximum(mem)
1629 def domain_ioport_range_enable(self, domid, first, last):
1630 """Enable access to a range of IO ports for a domain
1632 @param first: first IO port
1633 @param last: last IO port
1634 @raise XendError: failed to set range
1635 @rtype: 0
1636 """
1637 dominfo = self.domain_lookup_nr(domid)
1638 if not dominfo:
1639 raise XendInvalidDomain(str(domid))
1640 nr_ports = last - first + 1
1641 try:
1642 return xc.domain_ioport_permission(dominfo.getDomid(),
1643 first_port = first,
1644 nr_ports = nr_ports,
1645 allow_access = 1)
1646 except Exception, ex:
1647 raise XendError(str(ex))
1649 def domain_ioport_range_disable(self, domid, first, last):
1650 """Disable access to a range of IO ports for a domain
1652 @param first: first IO port
1653 @param last: last IO port
1654 @raise XendError: failed to set range
1655 @rtype: 0
1656 """
1657 dominfo = self.domain_lookup_nr(domid)
1658 if not dominfo:
1659 raise XendInvalidDomain(str(domid))
1660 nr_ports = last - first + 1
1661 try:
1662 return xc.domain_ioport_permission(dominfo.getDomid(),
1663 first_port = first,
1664 nr_ports = nr_ports,
1665 allow_access = 0)
1666 except Exception, ex:
1667 raise XendError(str(ex))
1669 def domain_send_trigger(self, domid, trigger_name, vcpu = 0):
1670 """Send trigger to a domain.
1672 @param domid: Domain ID or Name
1673 @type domid: int or string.
1674 @param trigger_name: trigger type name
1675 @type trigger_name: string
1676 @param vcpu: VCPU to send trigger (default is 0)
1677 @type vcpu: int
1678 @raise XendError: failed to send trigger
1679 @raise XendInvalidDomain: Domain is not valid
1680 @rtype: 0
1681 """
1682 dominfo = self.domain_lookup_nr(domid)
1683 if not dominfo:
1684 raise XendInvalidDomain(str(domid))
1685 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1686 raise VMBadState("Domain '%s' is not started" % domid,
1687 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1688 POWER_STATE_NAMES[dominfo._stateGet()])
1689 if trigger_name.lower() in TRIGGER_TYPE.keys():
1690 trigger = TRIGGER_TYPE[trigger_name.lower()]
1691 else:
1692 raise XendError("Invalid trigger: %s" % trigger_name)
1693 if trigger == TRIGGER_S3RESUME:
1694 xc.hvm_set_param(dominfo.getDomid(), HVM_PARAM_ACPI_S_STATE, 0)
1695 return None
1696 try:
1697 return xc.domain_send_trigger(dominfo.getDomid(),
1698 trigger,
1699 vcpu)
1700 except Exception, ex:
1701 raise XendError(str(ex))
1703 def domain_reset(self, domid):
1704 """Terminate domain immediately, and then create domain.
1706 @param domid: Domain ID or Name
1707 @type domid: int or string.
1708 @rtype: None
1709 @raise XendError: Failed to destroy or create
1710 @raise XendInvalidDomain: Domain is not valid
1711 """
1713 dominfo = self.domain_lookup_nr(domid)
1714 if not dominfo:
1715 raise XendInvalidDomain(str(domid))
1716 if dominfo and dominfo.getDomid() == DOM0_ID:
1717 raise XendError("Cannot reset privileged domain %s" % domid)
1718 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1719 raise VMBadState("Domain '%s' is not started" % domid,
1720 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1721 POWER_STATE_NAMES[dominfo._stateGet()])
1722 try:
1723 dominfo.resetDomain()
1724 except Exception, ex:
1725 raise XendError(str(ex))
1728 def instance():
1729 """Singleton constructor. Use this instead of the class constructor.
1730 """
1731 global inst
1732 try:
1733 inst
1734 except:
1735 inst = XendDomain()
1736 inst.init()
1737 return inst