ia64/xen-unstable

view tools/python/xen/xend/XendDomain.py @ 17712:91a9e28aed46

Make ssl relocation server listen on different port

This patch makes ssl relocation server listen on 8003 if enabled.

Whether to start ssl relocation server now controlled by
xend-relocation-ssl-server. So ssl and non-ssl relocation server can
run simultaneously. You can also only start ssl server or only start
non-ssl relocation server.

When mix deploy xen 3.2 server (has no ssl support) and 3.3 servers,
start ssl and non-ssl relocation server simultaneously can keep
backward compatibility.

It's also more reasonable to have separate ports for ssl and non-ssl.

In this patch, also renames xend-relocation-tls to xend-relocation-ssl.

Signed-off-by: Zhigang Wang <zhigang.x.wang@oracle.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri May 23 10:41:44 2008 +0100 (2008-05-23)
parents 672c09aad49d
children 33a6590ba948
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
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
47 from xen.xend.XendConstants import TRIGGER_TYPE
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
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 # xen api instance vars
97 # TODO: nothing uses this at the moment
98 self._allow_new_domains = True
100 # This must be called only the once, by instance() below. It is separate
101 # from the constructor because XendDomainInfo calls back into this class
102 # in order to check the uniqueness of domain names. This means that
103 # instance() must be able to return a valid instance of this class even
104 # during this initialisation.
105 def init(self):
106 """Singleton initialisation function."""
108 dom_path = self._managed_path()
109 mkdir.parents(dom_path, stat.S_IRWXU)
111 xstransact.Mkdir(XS_VMROOT)
112 xstransact.SetPermissions(XS_VMROOT, {'dom': DOM0_ID})
114 self.domains_lock.acquire()
115 try:
116 try:
117 dom0info = [d for d in self._running_domains() \
118 if d.get('domid') == DOM0_ID][0]
120 dom0info['name'] = DOM0_NAME
121 dom0 = XendDomainInfo.recreate(dom0info, True)
122 except IndexError:
123 raise XendError('Unable to find Domain 0')
125 self._setDom0CPUCount()
127 # This watch registration needs to be before the refresh call, so
128 # that we're sure that we haven't missed any releases, but inside
129 # the domains_lock, as we don't want the watch to fire until after
130 # the refresh call has completed.
131 xswatch("@introduceDomain", self._on_domains_changed)
132 xswatch("@releaseDomain", self._on_domains_changed)
134 self._init_domains()
135 finally:
136 self.domains_lock.release()
139 def _on_domains_changed(self, _):
140 """ Callback method when xenstore changes.
142 Calls refresh which will keep the local cache of domains
143 in sync.
145 @rtype: int
146 @return: 1
147 """
148 self.domains_lock.acquire()
149 try:
150 self._refresh()
151 finally:
152 self.domains_lock.release()
153 return 1
155 def _init_domains(self):
156 """Does the initial scan of managed and active domains to
157 populate self.domains.
159 Note: L{XendDomainInfo._checkName} will call back into XendDomain
160 to make sure domain name is not a duplicate.
162 """
163 self.domains_lock.acquire()
164 try:
165 running = self._running_domains()
166 managed = self._managed_domains()
168 # add all active domains
169 for dom in running:
170 if dom['dying'] == 1:
171 log.warn('Ignoring dying domain %d from now on' %
172 dom['domid'])
173 continue
175 if dom['domid'] != DOM0_ID:
176 try:
177 new_dom = XendDomainInfo.recreate(dom, False)
178 except Exception:
179 log.exception("Failed to create reference to running "
180 "domain id: %d" % dom['domid'])
182 # add all managed domains as dormant domains.
183 for dom in managed:
184 dom_uuid = dom.get('uuid')
185 if not dom_uuid:
186 continue
188 dom_name = dom.get('name_label', 'Domain-%s' % dom_uuid)
189 try:
190 running_dom = self.domain_lookup_nr(dom_name)
191 if not running_dom:
192 # instantiate domain if not started.
193 new_dom = XendDomainInfo.createDormant(dom)
194 self._managed_domain_register(new_dom)
195 else:
196 self._managed_domain_register(running_dom)
197 for key in XendConfig.XENAPI_CFG_TYPES.keys():
198 if key not in XendConfig.LEGACY_XENSTORE_VM_PARAMS and \
199 key in dom:
200 running_dom.info[key] = dom[key]
201 except Exception:
202 log.exception("Failed to create reference to managed "
203 "domain: %s" % dom_name)
205 finally:
206 self.domains_lock.release()
209 # -----------------------------------------------------------------
210 # Getting managed domains storage path names
212 def _managed_path(self, domuuid = None):
213 """Returns the path of the directory where managed domain
214 information is stored.
216 @keyword domuuid: If not None, will return the path to the domain
217 otherwise, will return the path containing
218 the directories which represent each domain.
219 @type: None or String.
220 @rtype: String
221 @return: Path.
222 """
223 dom_path = xoptions.get_xend_domains_path()
224 if domuuid:
225 dom_path = os.path.join(dom_path, domuuid)
226 return dom_path
228 def _managed_config_path(self, domuuid):
229 """Returns the path to the configuration file of a managed domain.
231 @param domname: Domain uuid
232 @type domname: String
233 @rtype: String
234 @return: path to config file.
235 """
236 return os.path.join(self._managed_path(domuuid), CACHED_CONFIG_FILE)
238 def _managed_check_point_path(self, domuuid):
239 """Returns absolute path to check point file for managed domain.
241 @param domuuid: Name of managed domain
242 @type domname: String
243 @rtype: String
244 @return: Path
245 """
246 return os.path.join(self._managed_path(domuuid), CHECK_POINT_FILE)
248 def _managed_config_remove(self, domuuid):
249 """Removes a domain configuration from managed list
251 @param domuuid: Name of managed domain
252 @type domname: String
253 @raise XendError: fails to remove the domain.
254 """
255 config_path = self._managed_path(domuuid)
256 try:
257 if os.path.exists(config_path) and os.path.isdir(config_path):
258 shutil.rmtree(config_path)
259 except IOError:
260 log.exception('managed_config_remove failed removing conf')
261 raise XendError("Unable to remove managed configuration"
262 " for domain: %s" % domuuid)
264 def managed_config_save(self, dominfo):
265 """Save a domain's configuration to disk
267 @param domninfo: Managed domain to save.
268 @type dominfo: XendDomainInfo
269 @raise XendError: fails to save configuration.
270 @rtype: None
271 """
272 if not self.is_domain_managed(dominfo):
273 return # refuse to save configuration this domain isn't managed
275 if dominfo:
276 domains_dir = self._managed_path()
277 dom_uuid = dominfo.get_uuid()
278 domain_config_dir = self._managed_path(dom_uuid)
280 def make_or_raise(path):
281 try:
282 mkdir.parents(path, stat.S_IRWXU)
283 except:
284 log.exception("%s could not be created." % path)
285 raise XendError("%s could not be created." % path)
287 make_or_raise(domains_dir)
288 make_or_raise(domain_config_dir)
290 try:
291 fd, fn = tempfile.mkstemp()
292 f = os.fdopen(fd, 'w+b')
293 try:
294 prettyprint(dominfo.sxpr(legacy_only = False), f,
295 width = 78)
296 finally:
297 f.close()
299 try:
300 shutil.move(fn, self._managed_config_path(dom_uuid))
301 except:
302 log.exception("Renaming %s to %s", fn,
303 self._managed_config_path(dom_uuid))
304 os.remove(fn)
305 except:
306 log.exception("Error occurred saving configuration file " +
307 "to %s" % domain_config_dir)
308 raise XendError("Failed to save configuration file to: %s" %
309 domain_config_dir)
310 else:
311 log.warn("Trying to save configuration for invalid domain")
314 def _managed_domains(self):
315 """ Returns list of domains that are managed.
317 Expects to be protected by domains_lock.
319 @rtype: list of XendConfig
320 @return: List of domain configurations that are managed.
321 """
322 dom_path = self._managed_path()
323 dom_uuids = os.listdir(dom_path)
324 doms = []
325 for dom_uuid in dom_uuids:
326 try:
327 cfg_file = self._managed_config_path(dom_uuid)
328 cfg = XendConfig.XendConfig(filename = cfg_file)
329 if cfg.get('uuid') != dom_uuid:
330 # something is wrong with the SXP
331 log.error("UUID mismatch in stored configuration: %s" %
332 cfg_file)
333 continue
334 doms.append(cfg)
335 except Exception:
336 log.exception('Unable to open or parse config.sxp: %s' % \
337 cfg_file)
338 return doms
340 def _managed_domain_unregister(self, dom):
341 try:
342 if self.is_domain_managed(dom):
343 self._managed_config_remove(dom.get_uuid())
344 del self.managed_domains[dom.get_uuid()]
345 except ValueError:
346 log.warn("Domain is not registered: %s" % dom.get_uuid())
348 def _managed_domain_register(self, dom):
349 self.managed_domains[dom.get_uuid()] = dom
351 def is_domain_managed(self, dom = None):
352 return (dom.get_uuid() in self.managed_domains)
354 # End of Managed Domain Access
355 # --------------------------------------------------------------------
357 def _running_domains(self):
358 """Get table of domains indexed by id from xc.
360 @requires: Expects to be protected by domains_lock.
361 @rtype: list of dicts
362 @return: A list of dicts representing the running domains.
363 """
364 try:
365 return xc.domain_getinfo()
366 except RuntimeError, e:
367 log.exception("Unable to get domain information.")
368 return {}
370 def _setDom0CPUCount(self):
371 """Sets the number of VCPUs dom0 has. Retreived from the
372 Xend configuration, L{XendOptions}.
374 @requires: Expects to be protected by domains_lock.
375 @rtype: None
376 """
377 dom0 = self.privilegedDomain()
379 # get max number of vcpus to use for dom0 from config
380 target = int(xoptions.get_dom0_vcpus())
381 log.debug("number of vcpus to use is %d", target)
383 # target == 0 means use all processors
384 if target > 0:
385 dom0.setVCpuCount(target)
388 def _refresh(self, refresh_shutdown = True):
389 """Refresh the domain list. Needs to be called when
390 either xenstore has changed or when a method requires
391 up to date information (like uptime, cputime stats).
393 Expects to be protected by the domains_lock.
395 @rtype: None
396 """
398 txn = xstransact()
399 try:
400 self._refreshTxn(txn, refresh_shutdown)
401 txn.commit()
402 except:
403 txn.abort()
404 raise
406 def _refreshTxn(self, transaction, refresh_shutdown):
407 running = self._running_domains()
408 # Add domains that are not already tracked but running in Xen,
409 # and update domain state for those that are running and tracked.
410 for dom in running:
411 domid = dom['domid']
412 if domid in self.domains:
413 self.domains[domid].update(dom, refresh_shutdown, transaction)
414 elif domid not in self.domains and dom['dying'] != 1:
415 try:
416 new_dom = XendDomainInfo.recreate(dom, False)
417 except VmError:
418 log.exception("Unable to recreate domain")
419 try:
420 xc.domain_destroy(domid)
421 except:
422 log.exception("Hard destruction of domain failed: %d" %
423 domid)
425 # update information for all running domains
426 # - like cpu_time, status, dying, etc.
427 # remove domains that are not running from active domain list.
428 # The list might have changed by now, because the update call may
429 # cause new domains to be added, if the domain has rebooted. We get
430 # the list again.
431 running = self._running_domains()
432 running_domids = [d['domid'] for d in running if d['dying'] != 1]
433 for domid, dom in self.domains.items():
434 if domid not in running_domids and domid != DOM0_ID:
435 self._remove_domain(dom, domid)
438 def add_domain(self, info):
439 """Add a domain to the list of running domains
441 @requires: Expects to be protected by the domains_lock.
442 @param info: XendDomainInfo of a domain to be added.
443 @type info: XendDomainInfo
444 """
445 log.debug("Adding Domain: %s" % info.getDomid())
446 self.domains[info.getDomid()] = info
448 # update the managed domains with a new XendDomainInfo object
449 # if we are keeping track of it.
450 if info.get_uuid() in self.managed_domains:
451 self._managed_domain_register(info)
453 def remove_domain(self, info, domid = None):
454 """Remove the domain from the list of running domains, taking the
455 domains_lock first.
456 """
457 self.domains_lock.acquire()
458 try:
459 self._remove_domain(info, domid)
460 finally:
461 self.domains_lock.release()
463 def _remove_domain(self, info, domid = None):
464 """Remove the domain from the list of running domains
466 @requires: Expects to be protected by the domains_lock.
467 @param info: XendDomainInfo of a domain to be removed.
468 @type info: XendDomainInfo
469 """
470 if info:
471 if domid == None:
472 domid = info.getDomid()
474 if info._stateGet() != DOM_STATE_HALTED:
475 info.cleanupDomain()
477 if domid in self.domains:
478 del self.domains[domid]
479 else:
480 log.warning("Attempted to remove non-existent domain.")
482 def restore_(self, config):
483 """Create a domain as part of the restore process. This is called
484 only from L{XendCheckpoint}.
486 A restore request comes into XendDomain through L{domain_restore}
487 or L{domain_restore_fd}. That request is
488 forwarded immediately to XendCheckpoint which, when it is ready, will
489 call this method. It is necessary to come through here rather than go
490 directly to L{XendDomainInfo.restore} because we need to
491 serialise the domain creation process, but cannot lock
492 domain_restore_fd as a whole, otherwise we will deadlock waiting for
493 the old domain to die.
495 @param config: Configuration of domain to restore
496 @type config: SXP Object (eg. list of lists)
497 """
498 self.domains_lock.acquire()
499 try:
500 dominfo = XendDomainInfo.restore(config)
501 return dominfo
502 finally:
503 self.domains_lock.release()
506 def domain_lookup(self, domid):
507 """Look up given I{domid} in the list of managed and running
508 domains.
510 @note: Will cause a refresh before lookup up domains, for
511 a version that does not need to re-read xenstore
512 use L{domain_lookup_nr}.
514 @param domid: Domain ID or Domain Name.
515 @type domid: int or string
516 @return: Found domain.
517 @rtype: XendDomainInfo
518 @raise XendInvalidDomain: If domain is not found.
519 """
520 self.domains_lock.acquire()
521 try:
522 self._refresh(refresh_shutdown = False)
523 dom = self.domain_lookup_nr(domid)
524 if not dom:
525 raise XendInvalidDomain(str(domid))
526 return dom
527 finally:
528 self.domains_lock.release()
531 def domain_lookup_nr(self, domid):
532 """Look up given I{domid} in the list of managed and running
533 domains.
535 @param domid: Domain ID or Domain Name.
536 @type domid: int or string
537 @return: Found domain.
538 @rtype: XendDomainInfo or None
539 """
540 self.domains_lock.acquire()
541 try:
542 # lookup by name
543 match = [dom for dom in self.domains.values() \
544 if dom.getName() == domid]
545 if match:
546 return match[0]
548 match = [dom for dom in self.managed_domains.values() \
549 if dom.getName() == domid]
550 if match:
551 return match[0]
553 # lookup by id
554 try:
555 if int(domid) in self.domains:
556 return self.domains[int(domid)]
557 except ValueError:
558 pass
560 # lookup by uuid for running domains
561 match = [dom for dom in self.domains.values() \
562 if dom.get_uuid() == domid]
563 if match:
564 return match[0]
566 # lookup by uuid for inactive managed domains
567 if domid in self.managed_domains:
568 return self.managed_domains[domid]
570 return None
571 finally:
572 self.domains_lock.release()
574 def privilegedDomain(self):
575 """ Get the XendDomainInfo of a dom0
577 @rtype: XendDomainInfo
578 """
579 self.domains_lock.acquire()
580 try:
581 return self.domains[DOM0_ID]
582 finally:
583 self.domains_lock.release()
585 def autostart_domains(self):
586 """ Autostart managed domains that are marked as such. """
588 need_starting = []
590 self.domains_lock.acquire()
591 try:
592 for dom_uuid, dom in self.managed_domains.items():
593 if dom and dom._stateGet() == DOM_STATE_HALTED:
594 on_xend_start = dom.info.get('on_xend_start', 'ignore')
595 auto_power_on = dom.info.get('auto_power_on', False)
596 should_start = (on_xend_start == 'start') or auto_power_on
597 if should_start:
598 need_starting.append(dom_uuid)
599 finally:
600 self.domains_lock.release()
602 for dom_uuid in need_starting:
603 self.domain_start(dom_uuid, False)
605 def cleanup_domains(self):
606 """Clean up domains that are marked as autostop.
607 Should be called when Xend goes down. This is currently
608 called from L{xen.xend.servers.XMLRPCServer}.
610 """
611 log.debug('cleanup_domains')
612 self.domains_lock.acquire()
613 try:
614 for dom in self.domains.values():
615 if dom.getName() == DOM0_NAME:
616 continue
618 try:
619 if dom._stateGet() == DOM_STATE_RUNNING:
620 shutdownAction = dom.info.get('on_xend_stop', 'ignore')
621 if shutdownAction == 'shutdown':
622 log.debug('Shutting down domain: %s' % dom.getName())
623 dom.shutdown("poweroff")
624 elif shutdownAction == 'suspend':
625 self.domain_suspend(dom.getName())
626 else:
627 log.debug('Domain %s continues to run.' % dom.getName())
628 except:
629 log.exception('Domain %s failed to %s.' % \
630 (dom.getName(), shutdownAction))
631 finally:
632 self.domains_lock.release()
636 # ----------------------------------------------------------------
637 # Xen API
640 def set_allow_new_domains(self, allow_new_domains):
641 self._allow_new_domains = allow_new_domains
643 def allow_new_domains(self):
644 return self._allow_new_domains
646 def get_domain_refs(self):
647 result = []
648 try:
649 self.domains_lock.acquire()
650 result = [d.get_uuid() for d in self.domains.values()]
651 for d in self.managed_domains.keys():
652 if d not in result:
653 result.append(d)
654 return result
655 finally:
656 self.domains_lock.release()
658 def get_all_vms(self):
659 self.domains_lock.acquire()
660 try:
661 result = self.domains.values()
662 result += [x for x in self.managed_domains.values() if
663 x not in result]
664 return result
665 finally:
666 self.domains_lock.release()
668 def get_vm_by_uuid(self, vm_uuid):
669 self.domains_lock.acquire()
670 try:
671 for dom in self.domains.values():
672 if dom.get_uuid() == vm_uuid:
673 return dom
675 if vm_uuid in self.managed_domains:
676 return self.managed_domains[vm_uuid]
678 return None
679 finally:
680 self.domains_lock.release()
682 def get_vm_with_dev_uuid(self, klass, dev_uuid):
683 self.domains_lock.acquire()
684 try:
685 for dom in self.domains.values() + self.managed_domains.values():
686 if dom.has_device(klass, dev_uuid):
687 return dom
688 return None
689 finally:
690 self.domains_lock.release()
692 def get_dev_property_by_uuid(self, klass, dev_uuid, field):
693 value = None
694 self.domains_lock.acquire()
696 try:
697 try:
698 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
699 if dom:
700 value = dom.get_dev_property(klass, dev_uuid, field)
701 except ValueError, e:
702 pass
703 finally:
704 self.domains_lock.release()
706 return value
708 def set_dev_property_by_uuid(self, klass, dev_uuid, field, value,
709 old_val = None):
710 rc = True
711 self.domains_lock.acquire()
713 try:
714 try:
715 dom = self.get_vm_with_dev_uuid(klass, dev_uuid)
716 if dom:
717 o_val = dom.get_dev_property(klass, dev_uuid, field)
718 log.info("o_val=%s, old_val=%s" % (o_val, old_val))
719 if old_val and old_val != o_val:
720 return False
722 dom.set_dev_property(klass, dev_uuid, field, value)
723 self.managed_config_save(dom)
724 except ValueError, e:
725 pass
726 finally:
727 self.domains_lock.release()
729 return rc
731 def is_valid_vm(self, vm_ref):
732 return (self.get_vm_by_uuid(vm_ref) != None)
734 def is_valid_dev(self, klass, dev_uuid):
735 return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None)
737 def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs):
738 dom = self.uuid_to_dom(vm_uuid)
739 fn(dom, *args, **kwargs)
741 def uuid_to_dom(self, vm_uuid):
742 self.domains_lock.acquire()
743 try:
744 for domid, dom in self.domains.items():
745 if dom.get_uuid() == vm_uuid:
746 return domid
748 if vm_uuid in self.managed_domains:
749 domid = self.managed_domains[vm_uuid].getDomid()
750 if domid is None:
751 return self.managed_domains[vm_uuid].getName()
752 else:
753 return domid
755 raise XendInvalidDomain(vm_uuid)
756 finally:
757 self.domains_lock.release()
760 def create_domain(self, xenapi_vm):
761 self.domains_lock.acquire()
762 try:
763 try:
764 xeninfo = XendConfig.XendConfig(xapi = xenapi_vm)
765 dominfo = XendDomainInfo.createDormant(xeninfo)
766 log.debug("Creating new managed domain: %s: %s" %
767 (dominfo.getName(), dominfo.get_uuid()))
768 self._managed_domain_register(dominfo)
769 self.managed_config_save(dominfo)
770 return dominfo.get_uuid()
771 except XendError, e:
772 raise
773 except Exception, e:
774 raise XendError(str(e))
775 finally:
776 self.domains_lock.release()
778 def rename_domain(self, dom, new_name):
779 self.domains_lock.acquire()
780 try:
781 old_name = dom.getName()
782 dom.setName(new_name)
784 finally:
785 self.domains_lock.release()
788 #
789 # End of Xen API
790 # ----------------------------------------------------------------
792 # ------------------------------------------------------------
793 # Xen Legacy API
795 def list(self, state = DOM_STATE_RUNNING):
796 """Get list of domain objects.
798 @param: the state in which the VMs should be -- one of the
799 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
800 @return: domains
801 @rtype: list of XendDomainInfo
802 """
803 if type(state) == int:
804 state = POWER_STATE_NAMES[state]
805 state = state.lower()
807 self.domains_lock.acquire()
808 try:
809 self._refresh(refresh_shutdown = False)
811 # active domains
812 active_domains = self.domains.values()
813 active_uuids = [d.get_uuid() for d in active_domains]
815 # inactive domains
816 inactive_domains = []
817 for dom_uuid, dom in self.managed_domains.items():
818 if dom_uuid not in active_uuids:
819 inactive_domains.append(dom)
821 if state == POWER_STATE_ALL:
822 return active_domains + inactive_domains
823 else:
824 return filter(lambda x:
825 POWER_STATE_NAMES[x._stateGet()].lower() == state,
826 active_domains + inactive_domains)
827 finally:
828 self.domains_lock.release()
831 def list_sorted(self, state = DOM_STATE_RUNNING):
832 """Get list of domain objects, sorted by name.
834 @param: the state in which the VMs should be -- one of the
835 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
836 @return: domain objects
837 @rtype: list of XendDomainInfo
838 """
839 doms = self.list(state)
840 doms.sort(lambda x, y: cmp(x.getName(), y.getName()))
841 return doms
843 def list_names(self, state = DOM_STATE_RUNNING):
844 """Get list of domain names.
846 @param: the state in which the VMs should be -- one of the
847 DOM_STATE_XYZ constants, or the corresponding name, or 'all'.
848 @return: domain names
849 @rtype: list of strings.
850 """
851 return [d.getName() for d in self.list_sorted(state)]
853 def domain_suspend(self, domname):
854 """Suspends a domain that is persistently managed by Xend
856 @param domname: Domain Name
857 @type domname: string
858 @rtype: None
859 @raise XendError: Failure during checkpointing.
860 """
862 try:
863 dominfo = self.domain_lookup_nr(domname)
864 if not dominfo:
865 raise XendInvalidDomain(domname)
867 if dominfo.getDomid() == DOM0_ID:
868 raise XendError("Cannot suspend privileged domain %s" % domname)
870 if dominfo._stateGet() != DOM_STATE_RUNNING:
871 raise VMBadState("Domain is not running",
872 POWER_STATE_NAMES[DOM_STATE_RUNNING],
873 POWER_STATE_NAMES[dominfo._stateGet()])
875 dom_uuid = dominfo.get_uuid()
877 if not os.path.exists(self._managed_config_path(dom_uuid)):
878 raise XendError("Domain is not managed by Xend lifecycle " +
879 "support.")
881 path = self._managed_check_point_path(dom_uuid)
882 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
883 if hasattr(os, "O_LARGEFILE"):
884 oflags |= os.O_LARGEFILE
885 fd = os.open(path, oflags)
886 try:
887 # For now we don't support 'live checkpoint'
888 XendCheckpoint.save(fd, dominfo, False, False, path)
889 finally:
890 os.close(fd)
891 except OSError, ex:
892 raise XendError("can't write guest state file %s: %s" %
893 (path, ex[1]))
895 def domain_resume(self, domname, start_paused = False):
896 """Resumes a domain that is persistently managed by Xend.
898 @param domname: Domain Name
899 @type domname: string
900 @rtype: None
901 @raise XendError: If failed to restore.
902 """
903 self.domains_lock.acquire()
904 try:
905 try:
906 fd = None
907 dominfo = self.domain_lookup_nr(domname)
909 if not dominfo:
910 raise XendInvalidDomain(domname)
912 if dominfo.getDomid() == DOM0_ID:
913 raise XendError("Cannot resume privileged domain %s" % domname)
915 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_SUSPENDED:
916 raise XendError("Cannot resume domain that is not suspended.")
918 dominfo.setResume(True)
920 dom_uuid = dominfo.get_uuid()
921 chkpath = self._managed_check_point_path(dom_uuid)
922 if not os.path.exists(chkpath):
923 raise XendError("Domain was not suspended by Xend")
925 # Restore that replaces the existing XendDomainInfo
926 try:
927 log.debug('Current DomainInfo state: %d' % dominfo._stateGet())
928 oflags = os.O_RDONLY
929 if hasattr(os, "O_LARGEFILE"):
930 oflags |= os.O_LARGEFILE
931 fd = os.open(chkpath, oflags)
932 XendCheckpoint.restore(self,
933 fd,
934 dominfo,
935 paused = start_paused)
936 os.unlink(chkpath)
937 except OSError, ex:
938 raise XendError("Failed to read stored checkpoint file")
939 except IOError, ex:
940 raise XendError("Failed to delete checkpoint file")
941 except Exception, ex:
942 log.exception("Exception occurred when resuming")
943 raise XendError("Error occurred when resuming: %s" % str(ex))
944 finally:
945 if fd is not None:
946 os.close(fd)
947 self.domains_lock.release()
950 def domain_create(self, config):
951 """Create a domain from a configuration.
953 @param config: configuration
954 @type config: SXP Object (list of lists)
955 @rtype: XendDomainInfo
956 """
957 self.domains_lock.acquire()
958 try:
959 self._refresh()
961 dominfo = XendDomainInfo.create(config)
962 return dominfo
963 finally:
964 self.domains_lock.release()
967 def domain_create_from_dict(self, config_dict):
968 """Create a domain from a configuration dictionary.
970 @param config_dict: configuration
971 @rtype: XendDomainInfo
972 """
973 self.domains_lock.acquire()
974 try:
975 self._refresh()
977 dominfo = XendDomainInfo.create_from_dict(config_dict)
978 return dominfo
979 finally:
980 self.domains_lock.release()
983 def domain_new(self, config):
984 """Create a domain from a configuration but do not start it.
986 @param config: configuration
987 @type config: SXP Object (list of lists)
988 @rtype: XendDomainInfo
989 """
990 self.domains_lock.acquire()
991 try:
992 try:
993 domconfig = XendConfig.XendConfig(sxp_obj = config)
994 dominfo = XendDomainInfo.createDormant(domconfig)
995 log.debug("Creating new managed domain: %s" %
996 dominfo.getName())
997 self._managed_domain_register(dominfo)
998 self.managed_config_save(dominfo)
999 # no return value because it isn't meaningful for client
1000 except XendError, e:
1001 raise
1002 except Exception, e:
1003 raise XendError(str(e))
1004 finally:
1005 self.domains_lock.release()
1007 def domain_start(self, domid, start_paused = True):
1008 """Start a managed domain
1010 @require: Domain must not be running.
1011 @param domid: Domain name or domain ID.
1012 @type domid: string or int
1013 @rtype: None
1014 @raise XendError: If domain is still running
1015 @rtype: None
1016 """
1017 self.domains_lock.acquire()
1018 try:
1019 self._refresh()
1021 dominfo = self.domain_lookup_nr(domid)
1022 if not dominfo:
1023 raise XendInvalidDomain(str(domid))
1025 if dominfo._stateGet() != DOM_STATE_HALTED:
1026 raise VMBadState("Domain is already running",
1027 POWER_STATE_NAMES[DOM_STATE_HALTED],
1028 POWER_STATE_NAMES[dominfo._stateGet()])
1030 dominfo.start(is_managed = True)
1031 finally:
1032 self.domains_lock.release()
1034 try:
1035 dominfo.waitForDevices()
1036 except Exception, ex:
1037 log.warn("Failed to setup devices for " + str(dominfo) + ": " + str(ex))
1038 dominfo.destroy()
1039 raise
1041 if not start_paused:
1042 dominfo.unpause()
1044 def domain_delete(self, domid):
1045 """Remove a managed domain from database
1047 @require: Domain must not be running.
1048 @param domid: Domain name or domain ID.
1049 @type domid: string or int
1050 @rtype: None
1051 @raise XendError: If domain is still running
1052 """
1053 self.domains_lock.acquire()
1054 try:
1055 try:
1056 dominfo = self.domain_lookup_nr(domid)
1057 if not dominfo:
1058 raise XendInvalidDomain(str(domid))
1060 if dominfo._stateGet() != XEN_API_VM_POWER_STATE_HALTED:
1061 raise VMBadState("Domain is not halted.",
1062 POWER_STATE_NAMES[DOM_STATE_HALTED],
1063 POWER_STATE_NAMES[dominfo._stateGet()])
1065 self._domain_delete_by_info(dominfo)
1066 except Exception, ex:
1067 raise XendError(str(ex))
1068 finally:
1069 self.domains_lock.release()
1072 def domain_delete_by_dominfo(self, dominfo):
1073 """Only for use by XendDomainInfo.
1074 """
1075 self.domains_lock.acquire()
1076 try:
1077 self._domain_delete_by_info(dominfo)
1078 finally:
1079 self.domains_lock.release()
1082 def _domain_delete_by_info(self, dominfo):
1083 """Expects to be protected by domains_lock.
1084 """
1085 log.info("Domain %s (%s) deleted." %
1086 (dominfo.getName(), dominfo.info.get('uuid')))
1088 dominfo.metrics.destroy()
1089 self._managed_domain_unregister(dominfo)
1090 self._remove_domain(dominfo)
1091 XendDevices.destroy_device_state(dominfo)
1094 def domain_configure(self, config):
1095 """Configure an existing domain.
1097 @param vmconfig: vm configuration
1098 @type vmconfig: SXP Object (list of lists)
1099 @todo: Not implemented
1100 """
1101 # !!!
1102 raise XendError("Unsupported")
1104 def domain_restore(self, src, paused=False):
1105 """Restore a domain from file.
1107 @param src: filename of checkpoint file to restore from
1108 @type src: string
1109 @return: Restored domain
1110 @rtype: XendDomainInfo
1111 @raise XendError: Failure to restore domain
1112 """
1113 try:
1114 oflags = os.O_RDONLY
1115 if hasattr(os, "O_LARGEFILE"):
1116 oflags |= os.O_LARGEFILE
1117 fd = os.open(src, oflags)
1118 try:
1119 return self.domain_restore_fd(fd, paused=paused)
1120 finally:
1121 os.close(fd)
1122 except OSError, ex:
1123 raise XendError("can't read guest state file %s: %s" %
1124 (src, ex[1]))
1126 def domain_restore_fd(self, fd, paused=False, relocating=False):
1127 """Restore a domain from the given file descriptor.
1129 @param fd: file descriptor of the checkpoint file
1130 @type fd: File object
1131 @rtype: XendDomainInfo
1132 @raise XendError: if failed to restore
1133 """
1135 try:
1136 return XendCheckpoint.restore(self, fd, paused=paused, relocating=relocating)
1137 except XendError, e:
1138 log.exception("Restore failed")
1139 raise
1140 except:
1141 # I don't really want to log this exception here, but the error
1142 # handling in the relocation-socket handling code (relocate.py) is
1143 # poor, so we need to log this for debugging.
1144 log.exception("Restore failed")
1145 raise XendError("Restore failed")
1147 def domain_unpause(self, domid):
1148 """Unpause domain execution.
1150 @param domid: Domain ID or Name
1151 @type domid: int or string.
1152 @rtype: None
1153 @raise XendError: Failed to unpause
1154 @raise XendInvalidDomain: Domain is not valid
1155 """
1156 try:
1157 dominfo = self.domain_lookup_nr(domid)
1158 if not dominfo:
1159 raise XendInvalidDomain(str(domid))
1160 if dominfo.getDomid() == DOM0_ID:
1161 raise XendError("Cannot unpause privileged domain %s" % domid)
1162 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
1163 raise VMBadState("Domain '%s' is not started" % domid,
1164 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1165 POWER_STATE_NAMES[dominfo._stateGet()])
1166 log.info("Domain %s (%d) unpaused.", dominfo.getName(),
1167 int(dominfo.getDomid()))
1168 dominfo.unpause()
1169 except XendInvalidDomain:
1170 log.exception("domain_unpause")
1171 raise
1172 except Exception, ex:
1173 log.exception("domain_unpause")
1174 raise XendError(str(ex))
1176 def domain_pause(self, domid, state=False):
1177 """Pause domain execution.
1179 @param domid: Domain ID or Name
1180 @type domid: int or string.
1181 @keyword state: If True, will return the domain state before pause
1182 @type state: bool
1183 @rtype: int if state is True
1184 @return: Domain state (DOM_STATE_*)
1185 @rtype: None if state is False
1186 @raise XendError: Failed to pause
1187 @raise XendInvalidDomain: Domain is not valid
1188 """
1189 try:
1190 dominfo = self.domain_lookup_nr(domid)
1191 if not dominfo:
1192 raise XendInvalidDomain(str(domid))
1193 if dominfo.getDomid() == DOM0_ID:
1194 raise XendError("Cannot pause privileged domain %s" % domid)
1195 ds = dominfo._stateGet()
1196 if ds not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED, DOM_STATE_CRASHED):
1197 raise VMBadState("Domain '%s' is not started" % domid,
1198 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1199 POWER_STATE_NAMES[ds])
1200 log.info("Domain %s (%d) paused.", dominfo.getName(),
1201 int(dominfo.getDomid()))
1202 if ds == DOM_STATE_RUNNING:
1203 dominfo.pause()
1204 if state:
1205 return ds
1206 except XendInvalidDomain:
1207 log.exception("domain_pause")
1208 raise
1209 except Exception, ex:
1210 log.exception("domain_pause")
1211 raise XendError(str(ex))
1213 def domain_dump(self, domid, filename, live, crash):
1214 """Dump domain core."""
1216 dominfo = self.domain_lookup_nr(domid)
1217 if not dominfo:
1218 raise XendInvalidDomain(str(domid))
1220 if dominfo.getDomid() == DOM0_ID:
1221 raise XendError("Cannot dump core for privileged domain %s" % domid)
1222 if dominfo._stateGet() not in (DOM_STATE_PAUSED, DOM_STATE_RUNNING, DOM_STATE_CRASHED):
1223 raise VMBadState("Domain '%s' is not started" % domid,
1224 POWER_STATE_NAMES[DOM_STATE_PAUSED],
1225 POWER_STATE_NAMES[dominfo._stateGet()])
1227 try:
1228 log.info("Domain core dump requested for domain %s (%d) "
1229 "live=%d crash=%d.",
1230 dominfo.getName(), dominfo.getDomid(), live, crash)
1231 return dominfo.dumpCore(filename)
1232 except Exception, ex:
1233 raise XendError(str(ex))
1235 def domain_destroy(self, domid):
1236 """Terminate domain immediately.
1238 @param domid: Domain ID or Name
1239 @type domid: int or string.
1240 @rtype: None
1241 @raise XendError: Failed to destroy
1242 @raise XendInvalidDomain: Domain is not valid
1243 """
1245 dominfo = self.domain_lookup_nr(domid)
1246 if dominfo and dominfo.getDomid() == DOM0_ID:
1247 raise XendError("Cannot destroy privileged domain %s" % domid)
1249 if dominfo:
1250 val = dominfo.destroy()
1251 else:
1252 try:
1253 val = xc.domain_destroy(int(domid))
1254 except ValueError:
1255 raise XendInvalidDomain(domid)
1256 except Exception, e:
1257 raise XendError(str(e))
1259 return val
1261 def domain_migrate(self, domid, dst, live=False, port=0, node=-1):
1262 """Start domain migration.
1264 @param domid: Domain ID or Name
1265 @type domid: int or string.
1266 @param dst: Destination IP address
1267 @type dst: string
1268 @keyword port: relocation port on destination
1269 @type port: int
1270 @keyword live: Live migration
1271 @type live: bool
1272 @rtype: None
1273 @keyword node: use node number for target
1274 @rtype: int
1275 @raise XendError: Failed to migrate
1276 @raise XendInvalidDomain: Domain is not valid
1277 """
1279 dominfo = self.domain_lookup_nr(domid)
1280 if not dominfo:
1281 raise XendInvalidDomain(str(domid))
1283 if dominfo.getDomid() == DOM0_ID:
1284 raise XendError("Cannot migrate privileged domain %s" % domid)
1285 if dominfo._stateGet() != DOM_STATE_RUNNING:
1286 raise VMBadState("Domain is not running",
1287 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1288 POWER_STATE_NAMES[dominfo._stateGet()])
1290 """ The following call may raise a XendError exception """
1291 dominfo.testMigrateDevices(True, dst)
1293 if live:
1294 """ Make sure there's memory free for enabling shadow mode """
1295 dominfo.checkLiveMigrateMemory()
1297 ssl = xoptions.get_xend_relocation_ssl()
1298 if ssl:
1299 from OpenSSL import SSL
1300 from xen.web import connection
1301 if port == 0:
1302 port = xoptions.get_xend_relocation_ssl_port()
1303 try:
1304 ctx = SSL.Context(SSL.SSLv23_METHOD)
1305 sock = SSL.Connection(ctx,
1306 socket.socket(socket.AF_INET, socket.SOCK_STREAM))
1307 sock.set_connect_state()
1308 sock.connect((dst, port))
1309 sock.send("sslreceive\n")
1310 sock.recv(80)
1311 except SSL.Error, err:
1312 raise XendError("SSL error: %s" % err)
1313 except socket.error, err:
1314 raise XendError("can't connect: %s" % err)
1316 p2cread, p2cwrite = os.pipe()
1317 threading.Thread(target=connection.SSLSocketServerConnection.fd2send,
1318 args=(sock, p2cread)).start()
1320 try:
1321 XendCheckpoint.save(p2cwrite, dominfo, True, live, dst,
1322 node=node)
1323 finally:
1324 sock.shutdown()
1325 sock.close()
1327 os.close(p2cread)
1328 os.close(p2cwrite)
1329 else:
1330 if port == 0:
1331 port = xoptions.get_xend_relocation_port()
1332 try:
1333 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1334 # When connecting to our ssl enabled relocation server using a
1335 # plain socket, send will success but recv will block. Add a
1336 # 30 seconds timeout to raise a socket.timeout exception to
1337 # inform the client.
1338 sock.settimeout(30.0)
1339 sock.connect((dst, port))
1340 sock.send("receive\n")
1341 sock.recv(80)
1342 sock.settimeout(None)
1343 except socket.error, err:
1344 raise XendError("can't connect: %s" % err)
1346 try:
1347 XendCheckpoint.save(sock.fileno(), dominfo, True, live,
1348 dst, node=node)
1349 finally:
1350 sock.close()
1352 def domain_save(self, domid, dst, checkpoint=False):
1353 """Start saving a domain to file.
1355 @param domid: Domain ID or Name
1356 @type domid: int or string.
1357 @param dst: Destination filename
1358 @type dst: string
1359 @rtype: None
1360 @raise XendError: Failed to save domain
1361 @raise XendInvalidDomain: Domain is not valid
1362 """
1363 try:
1364 dominfo = self.domain_lookup_nr(domid)
1365 if not dominfo:
1366 raise XendInvalidDomain(str(domid))
1368 if dominfo.getDomid() == DOM0_ID:
1369 raise XendError("Cannot save privileged domain %s" % str(domid))
1370 if dominfo._stateGet() != DOM_STATE_RUNNING:
1371 raise VMBadState("Domain is not running",
1372 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1373 POWER_STATE_NAMES[dominfo._stateGet()])
1375 oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
1376 if hasattr(os, "O_LARGEFILE"):
1377 oflags |= os.O_LARGEFILE
1378 fd = os.open(dst, oflags)
1379 try:
1380 XendCheckpoint.save(fd, dominfo, False, False, dst,
1381 checkpoint=checkpoint)
1382 except Exception, e:
1383 os.close(fd)
1384 raise e
1385 os.close(fd)
1386 except OSError, ex:
1387 raise XendError("can't write guest state file %s: %s" %
1388 (dst, ex[1]))
1390 def domain_pincpu(self, domid, vcpu, cpumap):
1391 """Set which cpus vcpu can use
1393 @param domid: Domain ID or Name
1394 @type domid: int or string.
1395 @param vcpu: vcpu to pin to
1396 @type vcpu: int
1397 @param cpumap: string repr of usable cpus
1398 @type cpumap: string
1399 @rtype: 0
1400 """
1401 dominfo = self.domain_lookup_nr(domid)
1402 if not dominfo:
1403 raise XendInvalidDomain(str(domid))
1405 # if vcpu is keyword 'all', apply the cpumap to all vcpus
1406 if str(vcpu).lower() == "all":
1407 vcpus = range(0, int(dominfo.getVCpuCount()))
1408 else:
1409 vcpus = [ int(vcpu) ]
1411 # set the same cpumask for all vcpus
1412 rc = 0
1413 cpus = dominfo.getCpus()
1414 for v in vcpus:
1415 try:
1416 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1417 rc = xc.vcpu_setaffinity(dominfo.getDomid(), v, cpumap)
1418 cpus[v] = cpumap
1419 except Exception, ex:
1420 log.exception(ex)
1421 raise XendError("Cannot pin vcpu: %d to cpu: %s - %s" % \
1422 (v, cpumap, str(ex)))
1423 dominfo.setCpus(cpus)
1424 self.managed_config_save(dominfo)
1426 return rc
1428 def domain_cpu_sedf_set(self, domid, period, slice_, latency, extratime,
1429 weight):
1430 """Set Simple EDF scheduler parameters for a domain.
1432 @param domid: Domain ID or Name
1433 @type domid: int or string.
1434 @rtype: 0
1435 """
1436 dominfo = self.domain_lookup_nr(domid)
1437 if not dominfo:
1438 raise XendInvalidDomain(str(domid))
1439 try:
1440 return xc.sedf_domain_set(dominfo.getDomid(), period, slice_,
1441 latency, extratime, weight)
1442 except Exception, ex:
1443 raise XendError(str(ex))
1445 def domain_cpu_sedf_get(self, domid):
1446 """Get Simple EDF scheduler parameters for a domain.
1448 @param domid: Domain ID or Name
1449 @type domid: int or string.
1450 @rtype: SXP object
1451 @return: The parameters for Simple EDF schedule for a domain.
1452 """
1453 dominfo = self.domain_lookup_nr(domid)
1454 if not dominfo:
1455 raise XendInvalidDomain(str(domid))
1456 try:
1457 sedf_info = xc.sedf_domain_get(dominfo.getDomid())
1458 # return sxpr
1459 return ['sedf',
1460 ['domid', sedf_info['domid']],
1461 ['period', sedf_info['period']],
1462 ['slice', sedf_info['slice']],
1463 ['latency', sedf_info['latency']],
1464 ['extratime', sedf_info['extratime']],
1465 ['weight', sedf_info['weight']]]
1467 except Exception, ex:
1468 raise XendError(str(ex))
1470 def domain_shadow_control(self, domid, op):
1471 """Shadow page control.
1473 @param domid: Domain ID or Name
1474 @type domid: int or string.
1475 @param op: operation
1476 @type op: int
1477 @rtype: 0
1478 """
1479 dominfo = self.domain_lookup(domid)
1480 try:
1481 return xc.shadow_control(dominfo.getDomid(), op)
1482 except Exception, ex:
1483 raise XendError(str(ex))
1485 def domain_shadow_mem_get(self, domid):
1486 """Get shadow pagetable memory allocation.
1488 @param domid: Domain ID or Name
1489 @type domid: int or string.
1490 @rtype: int
1491 @return: shadow memory in MB
1492 """
1493 dominfo = self.domain_lookup(domid)
1494 try:
1495 return xc.shadow_mem_control(dominfo.getDomid())
1496 except Exception, ex:
1497 raise XendError(str(ex))
1499 def domain_shadow_mem_set(self, domid, mb):
1500 """Set shadow pagetable memory allocation.
1502 @param domid: Domain ID or Name
1503 @type domid: int or string.
1504 @param mb: shadow memory to set in MB
1505 @type: mb: int
1506 @rtype: int
1507 @return: shadow memory in MB
1508 """
1509 dominfo = self.domain_lookup(domid)
1510 try:
1511 return xc.shadow_mem_control(dominfo.getDomid(), mb=mb)
1512 except Exception, ex:
1513 raise XendError(str(ex))
1515 def domain_sched_credit_get(self, domid):
1516 """Get credit scheduler parameters for a domain.
1518 @param domid: Domain ID or Name
1519 @type domid: int or string.
1520 @rtype: dict with keys 'weight' and 'cap'
1521 @return: credit scheduler parameters
1522 """
1523 dominfo = self.domain_lookup_nr(domid)
1524 if not dominfo:
1525 raise XendInvalidDomain(str(domid))
1527 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1528 try:
1529 return xc.sched_credit_domain_get(dominfo.getDomid())
1530 except Exception, ex:
1531 raise XendError(str(ex))
1532 else:
1533 return {'weight' : dominfo.getWeight(),
1534 'cap' : dominfo.getCap()}
1536 def domain_sched_credit_set(self, domid, weight = None, cap = None):
1537 """Set credit scheduler parameters for a domain.
1539 @param domid: Domain ID or Name
1540 @type domid: int or string.
1541 @type weight: int
1542 @type cap: int
1543 @rtype: 0
1544 """
1545 set_weight = False
1546 set_cap = False
1547 dominfo = self.domain_lookup_nr(domid)
1548 if not dominfo:
1549 raise XendInvalidDomain(str(domid))
1550 try:
1551 if weight is None:
1552 weight = int(0)
1553 elif weight < 1 or weight > 65535:
1554 raise XendError("weight is out of range")
1555 else:
1556 set_weight = True
1558 if cap is None:
1559 cap = int(~0)
1560 elif cap < 0 or cap > dominfo.getVCpuCount() * 100:
1561 raise XendError("cap is out of range")
1562 else:
1563 set_cap = True
1565 assert type(weight) == int
1566 assert type(cap) == int
1568 rc = 0
1569 if dominfo._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1570 rc = xc.sched_credit_domain_set(dominfo.getDomid(), weight, cap)
1571 if rc == 0:
1572 if set_weight:
1573 dominfo.setWeight(weight)
1574 if set_cap:
1575 dominfo.setCap(cap)
1576 self.managed_config_save(dominfo)
1577 return rc
1578 except Exception, ex:
1579 log.exception(ex)
1580 raise XendError(str(ex))
1582 def domain_maxmem_set(self, domid, mem):
1583 """Set the memory limit for a domain.
1585 @param domid: Domain ID or Name
1586 @type domid: int or string.
1587 @param mem: memory limit (in MiB)
1588 @type mem: int
1589 @raise XendError: fail to set memory
1590 @rtype: 0
1591 """
1592 dominfo = self.domain_lookup_nr(domid)
1593 if not dominfo:
1594 raise XendInvalidDomain(str(domid))
1595 dominfo.setMemoryMaximum(mem)
1597 def domain_ioport_range_enable(self, domid, first, last):
1598 """Enable access to a range of IO ports for a domain
1600 @param first: first IO port
1601 @param last: last IO port
1602 @raise XendError: failed to set range
1603 @rtype: 0
1604 """
1605 dominfo = self.domain_lookup_nr(domid)
1606 if not dominfo:
1607 raise XendInvalidDomain(str(domid))
1608 nr_ports = last - first + 1
1609 try:
1610 return xc.domain_ioport_permission(dominfo.getDomid(),
1611 first_port = first,
1612 nr_ports = nr_ports,
1613 allow_access = 1)
1614 except Exception, ex:
1615 raise XendError(str(ex))
1617 def domain_ioport_range_disable(self, domid, first, last):
1618 """Disable access to a range of IO ports for a domain
1620 @param first: first IO port
1621 @param last: last IO port
1622 @raise XendError: failed to set range
1623 @rtype: 0
1624 """
1625 dominfo = self.domain_lookup_nr(domid)
1626 if not dominfo:
1627 raise XendInvalidDomain(str(domid))
1628 nr_ports = last - first + 1
1629 try:
1630 return xc.domain_ioport_permission(dominfo.getDomid(),
1631 first_port = first,
1632 nr_ports = nr_ports,
1633 allow_access = 0)
1634 except Exception, ex:
1635 raise XendError(str(ex))
1637 def domain_send_trigger(self, domid, trigger_name, vcpu = 0):
1638 """Send trigger to a domain.
1640 @param domid: Domain ID or Name
1641 @type domid: int or string.
1642 @param trigger_name: trigger type name
1643 @type trigger_name: string
1644 @param vcpu: VCPU to send trigger (default is 0)
1645 @type vcpu: int
1646 @raise XendError: failed to send trigger
1647 @raise XendInvalidDomain: Domain is not valid
1648 @rtype: 0
1649 """
1650 dominfo = self.domain_lookup_nr(domid)
1651 if not dominfo:
1652 raise XendInvalidDomain(str(domid))
1653 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1654 raise VMBadState("Domain '%s' is not started" % domid,
1655 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1656 POWER_STATE_NAMES[dominfo._stateGet()])
1657 if trigger_name.lower() in TRIGGER_TYPE.keys():
1658 trigger = TRIGGER_TYPE[trigger_name.lower()]
1659 else:
1660 raise XendError("Invalid trigger: %s" % trigger_name)
1661 if trigger == TRIGGER_S3RESUME:
1662 xc.hvm_set_param(dominfo.getDomid(), HVM_PARAM_ACPI_S_STATE, 0)
1663 return None
1664 try:
1665 return xc.domain_send_trigger(dominfo.getDomid(),
1666 trigger,
1667 vcpu)
1668 except Exception, ex:
1669 raise XendError(str(ex))
1671 def domain_reset(self, domid):
1672 """Terminate domain immediately, and then create domain.
1674 @param domid: Domain ID or Name
1675 @type domid: int or string.
1676 @rtype: None
1677 @raise XendError: Failed to destroy or create
1678 @raise XendInvalidDomain: Domain is not valid
1679 """
1681 dominfo = self.domain_lookup_nr(domid)
1682 if not dominfo:
1683 raise XendInvalidDomain(str(domid))
1684 if dominfo and dominfo.getDomid() == DOM0_ID:
1685 raise XendError("Cannot reset privileged domain %s" % domid)
1686 if dominfo._stateGet() not in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
1687 raise VMBadState("Domain '%s' is not started" % domid,
1688 POWER_STATE_NAMES[DOM_STATE_RUNNING],
1689 POWER_STATE_NAMES[dominfo._stateGet()])
1690 try:
1691 dominfo.resetDomain()
1692 except Exception, ex:
1693 raise XendError(str(ex))
1696 def instance():
1697 """Singleton constructor. Use this instead of the class constructor.
1698 """
1699 global inst
1700 try:
1701 inst
1702 except:
1703 inst = XendDomain()
1704 inst.init()
1705 return inst