ia64/xen-unstable

view tools/python/xen/xend/XendAPI.py @ 15352:b643179d7452

xenapi: Implement VM.set_VCPUs_at_startup and VM.set_VCPUs_max XenAPI
methods in xend.

Signed-off-by: Jim Fehlig <jfehlig@novell.com>
author kfraser@localhost.localdomain
date Wed Jun 13 11:28:13 2007 +0100 (2007-06-13)
parents ffdbe8aebde2
children aa640601575f
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) 2006-2007 XenSource Ltd.
16 #============================================================================
18 import inspect
19 import os
20 import Queue
21 import sets
22 import string
23 import sys
24 import traceback
25 import threading
26 import time
27 import xmlrpclib
29 import XendDomain, XendDomainInfo, XendNode, XendDmesg
30 import XendLogging, XendTaskManager, XendAPIStore
32 from XendAPIVersion import *
33 from XendAuthSessions import instance as auth_manager
34 from XendError import *
35 from XendClient import ERROR_INVALID_DOMAIN
36 from XendLogging import log
37 from XendNetwork import XendNetwork
38 from XendTask import XendTask
39 from XendPIFMetrics import XendPIFMetrics
40 from XendVMMetrics import XendVMMetrics
41 from XendPIF import XendPIF
42 from XendPBD import XendPBD
44 from XendAPIConstants import *
45 from xen.util.xmlrpclib2 import stringify
47 from xen.util.blkif import blkdev_name_to_number
50 AUTH_NONE = 'none'
51 AUTH_PAM = 'pam'
53 argcounts = {}
55 # ------------------------------------------
56 # Utility Methods for Xen API Implementation
57 # ------------------------------------------
59 def xen_api_success(value):
60 """Wraps a return value in XenAPI format."""
61 if value is None:
62 s = ''
63 else:
64 s = stringify(value)
65 return {"Status": "Success", "Value": s}
67 def xen_api_success_void():
68 """Return success, but caller expects no return value."""
69 return xen_api_success("")
71 def xen_api_error(error):
72 """Wraps an error value in XenAPI format."""
73 if type(error) == tuple:
74 error = list(error)
75 if type(error) != list:
76 error = [error]
77 if len(error) == 0:
78 error = ['INTERNAL_ERROR', 'Empty list given to xen_api_error']
80 return { "Status": "Failure",
81 "ErrorDescription": [str(x) for x in error] }
84 def xen_api_todo():
85 """Temporary method to make sure we track down all the TODOs"""
86 return {"Status": "Error", "ErrorDescription": XEND_ERROR_TODO}
89 def now():
90 return datetime()
93 def datetime(when = None):
94 """Marshall the given time as a Xen-API DateTime.
96 @param when The time in question, given as seconds since the epoch, UTC.
97 May be None, in which case the current time is used.
98 """
99 if when is None:
100 return xmlrpclib.DateTime(time.gmtime())
101 else:
102 return xmlrpclib.DateTime(time.gmtime(when))
105 # ---------------------------------------------------
106 # Event dispatch
107 # ---------------------------------------------------
109 EVENT_QUEUE_LENGTH = 50
110 event_registrations = {}
112 def event_register(session, reg_classes):
113 if session not in event_registrations:
114 event_registrations[session] = {
115 'classes' : sets.Set(),
116 'queue' : Queue.Queue(EVENT_QUEUE_LENGTH),
117 'next-id' : 1
118 }
119 if not reg_classes:
120 reg_classes = classes
121 event_registrations[session]['classes'].union_update(reg_classes)
124 def event_unregister(session, unreg_classes):
125 if session not in event_registrations:
126 return
128 if unreg_classes:
129 event_registrations[session]['classes'].intersection_update(
130 unreg_classes)
131 if len(event_registrations[session]['classes']) == 0:
132 del event_registrations[session]
133 else:
134 del event_registrations[session]
137 def event_next(session):
138 if session not in event_registrations:
139 return xen_api_error(['SESSION_NOT_REGISTERED', session])
140 queue = event_registrations[session]['queue']
141 events = [queue.get()]
142 try:
143 while True:
144 events.append(queue.get(False))
145 except Queue.Empty:
146 pass
148 return xen_api_success(events)
151 def _ctor_event_dispatch(xenapi, ctor, api_cls, session, args):
152 result = ctor(xenapi, session, *args)
153 if result['Status'] == 'Success':
154 ref = result['Value']
155 event_dispatch('add', api_cls, ref, '')
156 return result
159 def _dtor_event_dispatch(xenapi, dtor, api_cls, session, ref, args):
160 result = dtor(xenapi, session, ref, *args)
161 if result['Status'] == 'Success':
162 event_dispatch('del', api_cls, ref, '')
163 return result
166 def _setter_event_dispatch(xenapi, setter, api_cls, attr_name, session, ref,
167 args):
168 result = setter(xenapi, session, ref, *args)
169 if result['Status'] == 'Success':
170 event_dispatch('mod', api_cls, ref, attr_name)
171 return result
174 def event_dispatch(operation, api_cls, ref, attr_name):
175 assert operation in ['add', 'del', 'mod']
176 event = {
177 'timestamp' : now(),
178 'class' : api_cls,
179 'operation' : operation,
180 'ref' : ref,
181 'obj_uuid' : ref,
182 'field' : attr_name,
183 }
184 for reg in event_registrations.values():
185 if api_cls in reg['classes']:
186 event['id'] = reg['next-id']
187 reg['next-id'] += 1
188 reg['queue'].put(event)
191 # ---------------------------------------------------
192 # Python Method Decorators for input value validation
193 # ---------------------------------------------------
195 def trace(func, api_name = ''):
196 """Decorator to trace XMLRPC Xen API methods.
198 @param func: function with any parameters
199 @param api_name: name of the api call for debugging.
200 """
201 if hasattr(func, 'api'):
202 api_name = func.api
203 def trace_func(self, *args, **kwargs):
204 log.debug('%s: %s' % (api_name, args))
205 return func(self, *args, **kwargs)
206 trace_func.api = api_name
207 return trace_func
210 def catch_typeerror(func):
211 """Decorator to catch any TypeErrors and translate them into Xen-API
212 errors.
214 @param func: function with params: (self, ...)
215 @rtype: callable object
216 """
217 def f(self, *args, **kwargs):
218 try:
219 return func(self, *args, **kwargs)
220 except TypeError, exn:
221 #log.exception('catch_typeerror')
222 if hasattr(func, 'api') and func.api in argcounts:
223 # Assume that if the argument count was wrong and if the
224 # exception was thrown inside this file, then it is due to an
225 # invalid call from the client, otherwise it's an internal
226 # error (which will be handled further up).
227 expected = argcounts[func.api]
228 actual = len(args) + len(kwargs)
229 if expected != actual:
230 tb = sys.exc_info()[2]
231 try:
232 sourcefile = traceback.extract_tb(tb)[-1][0]
233 if sourcefile == inspect.getsourcefile(XendAPI):
234 return xen_api_error(
235 ['MESSAGE_PARAMETER_COUNT_MISMATCH',
236 func.api, expected, actual])
237 finally:
238 del tb
239 raise
240 except XendAPIError, exn:
241 return xen_api_error(exn.get_api_error())
243 return f
246 def session_required(func):
247 """Decorator to verify if session is valid before calling method.
249 @param func: function with params: (self, session, ...)
250 @rtype: callable object
251 """
252 def check_session(self, session, *args, **kwargs):
253 if auth_manager().is_session_valid(session):
254 return func(self, session, *args, **kwargs)
255 else:
256 return xen_api_error(['SESSION_INVALID', session])
258 return check_session
261 def _is_valid_ref(ref, validator):
262 return type(ref) == str and validator(ref)
264 def _check_ref(validator, clas, func, api, session, ref, *args, **kwargs):
265 if _is_valid_ref(ref, validator):
266 return func(api, session, ref, *args, **kwargs)
267 else:
268 return xen_api_error(['HANDLE_INVALID', clas, ref])
271 def valid_host(func):
272 """Decorator to verify if host_ref is valid before calling method.
274 @param func: function with params: (self, session, host_ref, ...)
275 @rtype: callable object
276 """
277 return lambda *args, **kwargs: \
278 _check_ref(XendNode.instance().is_valid_host,
279 'host', func, *args, **kwargs)
281 def valid_host_metrics(func):
282 """Decorator to verify if host_metrics_ref is valid before calling
283 method.
285 @param func: function with params: (self, session, host_metrics_ref)
286 @rtype: callable object
287 """
288 return lambda *args, **kwargs: \
289 _check_ref(lambda r: r == XendNode.instance().host_metrics_uuid,
290 'host_metrics', func, *args, **kwargs)
292 def valid_host_cpu(func):
293 """Decorator to verify if host_cpu_ref is valid before calling method.
295 @param func: function with params: (self, session, host_cpu_ref, ...)
296 @rtype: callable object
297 """
298 return lambda *args, **kwargs: \
299 _check_ref(XendNode.instance().is_valid_cpu,
300 'host_cpu', func, *args, **kwargs)
302 def valid_vm(func):
303 """Decorator to verify if vm_ref is valid before calling method.
305 @param func: function with params: (self, session, vm_ref, ...)
306 @rtype: callable object
307 """
308 return lambda *args, **kwargs: \
309 _check_ref(XendDomain.instance().is_valid_vm,
310 'VM', func, *args, **kwargs)
312 def valid_vbd(func):
313 """Decorator to verify if vbd_ref is valid before calling method.
315 @param func: function with params: (self, session, vbd_ref, ...)
316 @rtype: callable object
317 """
318 return lambda *args, **kwargs: \
319 _check_ref(lambda r: XendDomain.instance().is_valid_dev('vbd', r),
320 'VBD', func, *args, **kwargs)
322 def valid_vbd_metrics(func):
323 """Decorator to verify if ref is valid before calling method.
325 @param func: function with params: (self, session, ref, ...)
326 @rtype: callable object
327 """
328 return lambda *args, **kwargs: \
329 _check_ref(lambda r: XendDomain.instance().is_valid_dev('vbd', r),
330 'VBD_metrics', func, *args, **kwargs)
332 def valid_vif(func):
333 """Decorator to verify if vif_ref is valid before calling method.
335 @param func: function with params: (self, session, vif_ref, ...)
336 @rtype: callable object
337 """
338 return lambda *args, **kwargs: \
339 _check_ref(lambda r: XendDomain.instance().is_valid_dev('vif', r),
340 'VIF', func, *args, **kwargs)
342 def valid_vif_metrics(func):
343 """Decorator to verify if ref is valid before calling method.
345 @param func: function with params: (self, session, ref, ...)
346 @rtype: callable object
347 """
348 return lambda *args, **kwargs: \
349 _check_ref(lambda r: XendDomain.instance().is_valid_dev('vif', r),
350 'VIF_metrics', func, *args, **kwargs)
352 def valid_vdi(func):
353 """Decorator to verify if vdi_ref is valid before calling method.
355 @param func: function with params: (self, session, vdi_ref, ...)
356 @rtype: callable object
357 """
358 return lambda *args, **kwargs: \
359 _check_ref(XendNode.instance().is_valid_vdi,
360 'VDI', func, *args, **kwargs)
362 def valid_vtpm(func):
363 """Decorator to verify if vtpm_ref is valid before calling method.
365 @param func: function with params: (self, session, vtpm_ref, ...)
366 @rtype: callable object
367 """
368 return lambda *args, **kwargs: \
369 _check_ref(lambda r: XendDomain.instance().is_valid_dev('vtpm', r),
370 'VTPM', func, *args, **kwargs)
373 def valid_console(func):
374 """Decorator to verify if console_ref is valid before calling method.
376 @param func: function with params: (self, session, console_ref, ...)
377 @rtype: callable object
378 """
379 return lambda *args, **kwargs: \
380 _check_ref(lambda r: XendDomain.instance().is_valid_dev('console',
381 r),
382 'console', func, *args, **kwargs)
384 def valid_sr(func):
385 """Decorator to verify if sr_ref is valid before calling method.
387 @param func: function with params: (self, session, sr_ref, ...)
388 @rtype: callable object
389 """
390 return lambda *args, **kwargs: \
391 _check_ref(lambda r: XendNode.instance().is_valid_sr,
392 'SR', func, *args, **kwargs)
394 def valid_task(func):
395 """Decorator to verify if task_ref is valid before calling
396 method.
398 @param func: function with params: (self, session, task_ref)
399 @rtype: callable object
400 """
401 return lambda *args, **kwargs: \
402 _check_ref(XendTaskManager.get_task,
403 'task', func, *args, **kwargs)
405 def valid_debug(func):
406 """Decorator to verify if task_ref is valid before calling
407 method.
409 @param func: function with params: (self, session, task_ref)
410 @rtype: callable object
411 """
412 return lambda *args, **kwargs: \
413 _check_ref(lambda r: r in XendAPI._debug,
414 'debug', func, *args, **kwargs)
417 def valid_object(class_name):
418 """Decorator to verify if object is valid before calling
419 method.
421 @param func: function with params: (self, session, pif_ref)
422 @rtype: callable object
423 """
424 return lambda func: \
425 lambda *args, **kwargs: \
426 _check_ref(lambda r: \
427 XendAPIStore.get(r, class_name) is not None,
428 'PIF', func, *args, **kwargs)
430 # -----------------------------
431 # Bridge to Legacy XM API calls
432 # -----------------------------
434 def do_vm_func(fn_name, vm_ref, *args, **kwargs):
435 """Helper wrapper func to abstract away from repetitive code.
437 @param fn_name: function name for XendDomain instance
438 @type fn_name: string
439 @param vm_ref: vm_ref
440 @type vm_ref: string
441 @param *args: more arguments
442 @type *args: tuple
443 """
444 try:
445 xendom = XendDomain.instance()
446 fn = getattr(xendom, fn_name)
447 xendom.do_legacy_api_with_uuid(fn, vm_ref, *args, **kwargs)
448 return xen_api_success_void()
449 except VMBadState, exn:
450 return xen_api_error(['VM_BAD_POWER_STATE', vm_ref, exn.expected,
451 exn.actual])
454 classes = {
455 'session' : None,
456 'event' : None,
457 'host' : valid_host,
458 'host_cpu' : valid_host_cpu,
459 'host_metrics' : valid_host_metrics,
460 'VM' : valid_vm,
461 'VBD' : valid_vbd,
462 'VBD_metrics' : valid_vbd_metrics,
463 'VIF' : valid_vif,
464 'VIF_metrics' : valid_vif_metrics,
465 'VDI' : valid_vdi,
466 'VTPM' : valid_vtpm,
467 'console' : valid_console,
468 'SR' : valid_sr,
469 'task' : valid_task,
470 'debug' : valid_debug,
471 'network' : valid_object("network"),
472 'PIF' : valid_object("PIF"),
473 'VM_metrics' : valid_object("VM_metrics"),
474 'PBD' : valid_object("PBD"),
475 'PIF_metrics' : valid_object("PIF_metrics")
476 }
478 autoplug_classes = {
479 'network' : XendNetwork,
480 'PIF' : XendPIF,
481 'VM_metrics' : XendVMMetrics,
482 'PBD' : XendPBD,
483 'PIF_metrics' : XendPIFMetrics,
484 }
486 class XendAPI(object):
487 """Implementation of the Xen-API in Xend. Expects to be
488 used via XMLRPCServer.
490 All methods that need a valid session are marked with
491 a L{session_required} decorator that will
492 transparently perform the required session authentication.
494 We need to support Python <2.4, so we use the old decorator syntax.
496 All XMLRPC accessible methods require an 'api' attribute and
497 is set to the XMLRPC function name which the method implements.
498 """
500 __decorated__ = False
501 __init_lock__ = threading.Lock()
502 _debug = {}
504 def __new__(cls, *args, **kwds):
505 """ Override __new__ to decorate the class only once.
507 Lock to make sure the classes are not decorated twice.
508 """
509 cls.__init_lock__.acquire()
510 try:
511 if not cls.__decorated__:
512 cls._decorate()
513 cls.__decorated__ = True
515 return object.__new__(cls, *args, **kwds)
516 finally:
517 cls.__init_lock__.release()
519 def _decorate(cls):
520 """ Decorate all the object methods to have validators
521 and appropriate function attributes.
523 This should only be executed once for the duration of the
524 server.
525 """
526 global_validators = [session_required, catch_typeerror]
529 # Cheat methods
530 # -------------
531 # Methods that have a trivial implementation for all classes.
532 # 1. get_by_uuid == getting by ref, so just return uuid for
533 # all get_by_uuid() methods.
535 for api_cls in classes.keys():
536 # We'll let the autoplug classes implement these functions
537 # themselves - its much cleaner to do it in the base class
538 if api_cls == 'session' or api_cls in autoplug_classes.keys():
539 continue
541 get_by_uuid = '%s_get_by_uuid' % api_cls
542 get_uuid = '%s_get_uuid' % api_cls
543 get_all_records = '%s_get_all_records' % api_cls
545 def _get_by_uuid(_1, _2, ref):
546 return xen_api_success(ref)
548 def _get_uuid(_1, _2, ref):
549 return xen_api_success(ref)
551 def unpack(v):
552 return v['Value']
554 def _get_all_records(_api_cls):
555 return lambda s, session: \
556 xen_api_success(dict([(ref, unpack(getattr(cls, '%s_get_record' % _api_cls)(s, session, ref)))\
557 for ref in unpack(getattr(cls, '%s_get_all' % _api_cls)(s, session))]))
559 setattr(cls, get_by_uuid, _get_by_uuid)
560 setattr(cls, get_uuid, _get_uuid)
561 setattr(cls, get_all_records, _get_all_records(api_cls))
563 # Autoplugging classes
564 # --------------------
565 # These have all of their methods grabbed out from the implementation
566 # class, and wrapped up to be compatible with the Xen-API.
568 def getter(ref, type):
569 return XendAPIStore.get(ref, type)
571 for api_cls, impl_cls in autoplug_classes.items():
572 def doit(n):
573 dot_n = '%s.%s' % (api_cls, n)
574 full_n = '%s_%s' % (api_cls, n)
575 if not hasattr(cls, full_n):
576 f = getattr(impl_cls, n)
577 argcounts[dot_n] = f.func_code.co_argcount + 1
578 g = lambda api_cls: \
579 setattr(cls, full_n, \
580 lambda s, session, ref, *args: \
581 xen_api_success( \
582 f(getter(ref, api_cls), *args)))
583 g(api_cls) # Force api_cls to be captured
585 def doit_func(n):
586 dot_n = '%s.%s' % (api_cls, n)
587 full_n = '%s_%s' % (api_cls, n)
588 if not hasattr(cls, full_n):
589 f = getattr(impl_cls, n)
590 argcounts[dot_n] = f.func_code.co_argcount
591 setattr(cls, full_n, \
592 lambda s, session, *args: \
593 xen_api_success( \
594 f(*args)))
596 ro_attrs = impl_cls.getAttrRO()
597 rw_attrs = impl_cls.getAttrRW()
598 methods = impl_cls.getMethods()
599 funcs = impl_cls.getFuncs()
601 for attr_name in ro_attrs + rw_attrs:
602 doit('get_%s' % attr_name)
603 for attr_name in rw_attrs:
604 doit('set_%s' % attr_name)
605 for method in methods:
606 doit('%s' % method)
607 for func in funcs:
608 doit_func('%s' % func)
610 def wrap_method(name, new_f):
611 try:
612 f = getattr(cls, name)
613 wrapped_f = (lambda *args: new_f(f, *args))
614 wrapped_f.api = f.api
615 wrapped_f.async = f.async
616 setattr(cls, name, wrapped_f)
617 except AttributeError:
618 # Logged below (API call: %s not found)
619 pass
622 def setter_event_wrapper(api_cls, attr_name):
623 setter_name = '%s_set_%s' % (api_cls, attr_name)
624 wrap_method(
625 setter_name,
626 lambda setter, s, session, ref, *args:
627 _setter_event_dispatch(s, setter, api_cls, attr_name,
628 session, ref, args))
631 def ctor_event_wrapper(api_cls):
632 ctor_name = '%s_create' % api_cls
633 wrap_method(
634 ctor_name,
635 lambda ctor, s, session, *args:
636 _ctor_event_dispatch(s, ctor, api_cls, session, args))
639 def dtor_event_wrapper(api_cls):
640 dtor_name = '%s_destroy' % api_cls
641 wrap_method(
642 dtor_name,
643 lambda dtor, s, session, ref, *args:
644 _dtor_event_dispatch(s, dtor, api_cls, session, ref, args))
647 # Wrapping validators around XMLRPC calls
648 # ---------------------------------------
650 for api_cls, validator in classes.items():
651 def doit(n, takes_instance, async_support = False,
652 return_type = None):
653 n_ = n.replace('.', '_')
654 try:
655 f = getattr(cls, n_)
656 if n not in argcounts:
657 argcounts[n] = f.func_code.co_argcount - 1
659 validators = takes_instance and validator and \
660 [validator] or []
662 validators += global_validators
663 for v in validators:
664 f = v(f)
665 f.api = n
666 f.async = async_support
667 if return_type:
668 f.return_type = return_type
670 setattr(cls, n_, f)
671 except AttributeError:
672 log.warn("API call: %s not found" % n)
674 if api_cls in autoplug_classes.keys():
675 impl_cls = autoplug_classes[api_cls]
676 ro_attrs = impl_cls.getAttrRO()
677 rw_attrs = impl_cls.getAttrRW()
678 methods = map(lambda x: (x, ""), impl_cls.getMethods())
679 funcs = map(lambda x: (x, ""), impl_cls.getFuncs())
680 else:
681 ro_attrs = getattr(cls, '%s_attr_ro' % api_cls, []) \
682 + cls.Base_attr_ro
683 rw_attrs = getattr(cls, '%s_attr_rw' % api_cls, []) \
684 + cls.Base_attr_rw
685 methods = getattr(cls, '%s_methods' % api_cls, []) \
686 + cls.Base_methods
687 funcs = getattr(cls, '%s_funcs' % api_cls, []) \
688 + cls.Base_funcs
690 # wrap validators around readable class attributes
691 for attr_name in ro_attrs + rw_attrs:
692 doit('%s.get_%s' % (api_cls, attr_name), True,
693 async_support = False)
695 # wrap validators around writable class attrributes
696 for attr_name in rw_attrs:
697 doit('%s.set_%s' % (api_cls, attr_name), True,
698 async_support = False)
699 setter_event_wrapper(api_cls, attr_name)
701 # wrap validators around methods
702 for method_name, return_type in methods:
703 doit('%s.%s' % (api_cls, method_name), True,
704 async_support = True)
706 # wrap validators around class functions
707 for func_name, return_type in funcs:
708 doit('%s.%s' % (api_cls, func_name), False,
709 async_support = True,
710 return_type = return_type)
712 ctor_event_wrapper(api_cls)
713 dtor_event_wrapper(api_cls)
716 _decorate = classmethod(_decorate)
718 def __init__(self, auth):
719 self.auth = auth
721 Base_attr_ro = ['uuid']
722 Base_attr_rw = []
723 Base_methods = [('get_record', 'Struct')]
724 Base_funcs = [('get_all', 'Set'), ('get_by_uuid', None), ('get_all_records', 'Set')]
726 # Xen API: Class Session
727 # ----------------------------------------------------------------
728 # NOTE: Left unwrapped by __init__
730 session_attr_ro = ['this_host', 'this_user', 'last_active']
731 session_methods = [('logout', None)]
733 def session_get_all(self, session):
734 return xen_api_success([session])
736 def session_login_with_password(self, *args):
737 if len(args) != 2:
738 return xen_api_error(
739 ['MESSAGE_PARAMETER_COUNT_MISMATCH',
740 'session.login_with_password', 2, len(args)])
741 username = args[0]
742 password = args[1]
743 try:
744 session = ((self.auth == AUTH_NONE and
745 auth_manager().login_unconditionally(username)) or
746 auth_manager().login_with_password(username, password))
747 return xen_api_success(session)
748 except XendError, e:
749 return xen_api_error(['SESSION_AUTHENTICATION_FAILED'])
750 session_login_with_password.api = 'session.login_with_password'
752 # object methods
753 def session_logout(self, session):
754 auth_manager().logout(session)
755 return xen_api_success_void()
757 def session_get_record(self, session, self_session):
758 if self_session != session:
759 return xen_api_error(['PERMISSION_DENIED'])
760 record = {'uuid' : session,
761 'this_host' : XendNode.instance().uuid,
762 'this_user' : auth_manager().get_user(session),
763 'last_active': now()}
764 return xen_api_success(record)
766 def session_get_uuid(self, session, self_session):
767 return xen_api_success(self_session)
769 def session_get_by_uuid(self, session, self_session):
770 return xen_api_success(self_session)
772 # attributes (ro)
773 def session_get_this_host(self, session, self_session):
774 if self_session != session:
775 return xen_api_error(['PERMISSION_DENIED'])
776 return xen_api_success(XendNode.instance().uuid)
778 def session_get_this_user(self, session, self_session):
779 if self_session != session:
780 return xen_api_error(['PERMISSION_DENIED'])
781 user = auth_manager().get_user(session)
782 if user is not None:
783 return xen_api_success(user)
784 return xen_api_error(['SESSION_INVALID', session])
786 def session_get_last_active(self, session, self_session):
787 if self_session != session:
788 return xen_api_error(['PERMISSION_DENIED'])
789 return xen_api_success(now())
792 # Xen API: Class User
793 # ----------------------------------------------------------------
794 # TODO: NOT IMPLEMENTED YET
796 # Xen API: Class Tasks
797 # ----------------------------------------------------------------
799 task_attr_ro = ['name_label',
800 'name_description',
801 'status',
802 'progress',
803 'type',
804 'result',
805 'error_info',
806 'allowed_operations',
807 'session'
808 ]
810 task_attr_rw = []
812 task_funcs = [('get_by_name_label', 'Set(task)'),
813 ('cancel', None)]
815 def task_get_name_label(self, session, task_ref):
816 task = XendTaskManager.get_task(task_ref)
817 return xen_api_success(task.name_label)
819 def task_get_name_description(self, session, task_ref):
820 task = XendTaskManager.get_task(task_ref)
821 return xen_api_success(task.name_description)
823 def task_get_status(self, session, task_ref):
824 task = XendTaskManager.get_task(task_ref)
825 return xen_api_success(task.get_status())
827 def task_get_progress(self, session, task_ref):
828 task = XendTaskManager.get_task(task_ref)
829 return xen_api_success(task.progress)
831 def task_get_type(self, session, task_ref):
832 task = XendTaskManager.get_task(task_ref)
833 return xen_api_success(task.type)
835 def task_get_result(self, session, task_ref):
836 task = XendTaskManager.get_task(task_ref)
837 return xen_api_success(task.result)
839 def task_get_error_info(self, session, task_ref):
840 task = XendTaskManager.get_task(task_ref)
841 return xen_api_success(task.error_info)
843 def task_get_allowed_operations(self, session, task_ref):
844 return xen_api_success({})
846 def task_get_session(self, session, task_ref):
847 task = XendTaskManager.get_task(task_ref)
848 return xen_api_success(task.session)
850 def task_get_all(self, session):
851 tasks = XendTaskManager.get_all_tasks()
852 return xen_api_success(tasks)
854 def task_get_record(self, session, task_ref):
855 task = XendTaskManager.get_task(task_ref)
856 return xen_api_success(task.get_record())
858 def task_cancel(self, session, task_ref):
859 return xen_api_error('OPERATION_NOT_ALLOWED')
861 def task_get_by_name_label(self, session, name):
862 return xen_api_success(XendTaskManager.get_task_by_name(name))
864 # Xen API: Class host
865 # ----------------------------------------------------------------
867 host_attr_ro = ['software_version',
868 'resident_VMs',
869 'PBDs',
870 'PIFs',
871 'host_CPUs',
872 'cpu_configuration',
873 'metrics',
874 'capabilities',
875 'supported_bootloaders',
876 'sched_policy',
877 'API_version_major',
878 'API_version_minor',
879 'API_version_vendor',
880 'API_version_vendor_implementation',
881 'enabled']
883 host_attr_rw = ['name_label',
884 'name_description',
885 'other_config',
886 'logging']
888 host_methods = [('disable', None),
889 ('enable', None),
890 ('reboot', None),
891 ('shutdown', None),
892 ('add_to_other_config', None),
893 ('remove_from_other_config', None),
894 ('dmesg', 'String'),
895 ('dmesg_clear', 'String'),
896 ('get_log', 'String'),
897 ('send_debug_keys', None)]
899 host_funcs = [('get_by_name_label', None),
900 ('list_methods', None)]
902 # attributes
903 def host_get_name_label(self, session, host_ref):
904 return xen_api_success(XendNode.instance().name)
905 def host_set_name_label(self, session, host_ref, new_name):
906 XendNode.instance().set_name(new_name)
907 return xen_api_success_void()
908 def host_get_name_description(self, session, host_ref):
909 return xen_api_success(XendNode.instance().get_description())
910 def host_set_name_description(self, session, host_ref, new_desc):
911 XendNode.instance().set_description(new_desc)
912 return xen_api_success_void()
913 def host_get_other_config(self, session, host_ref):
914 return xen_api_success(XendNode.instance().other_config)
915 def host_set_other_config(self, session, host_ref, other_config):
916 node = XendNode.instance()
917 node.other_config = dict(other_config)
918 node.save()
919 return xen_api_success_void()
920 def host_add_to_other_config(self, session, host_ref, key, value):
921 node = XendNode.instance()
922 node.other_config[key] = value
923 node.save()
924 return xen_api_success_void()
925 def host_remove_from_other_config(self, session, host_ref, key):
926 node = XendNode.instance()
927 if key in node.other_config:
928 del node.other_config[key]
929 node.save()
930 return xen_api_success_void()
931 def host_get_API_version_major(self, _, ref):
932 return xen_api_success(XEN_API_VERSION_MAJOR)
933 def host_get_API_version_minor(self, _, ref):
934 return xen_api_success(XEN_API_VERSION_MINOR)
935 def host_get_API_version_vendor(self, _, ref):
936 return xen_api_success(XEN_API_VERSION_VENDOR)
937 def host_get_API_version_vendor_implementation(self, _, ref):
938 return xen_api_success(XEN_API_VERSION_VENDOR_IMPLEMENTATION)
939 def host_get_software_version(self, session, host_ref):
940 return xen_api_success(XendNode.instance().xen_version())
941 def host_get_enabled(self, _1, _2):
942 return xen_api_success(XendDomain.instance().allow_new_domains())
943 def host_get_resident_VMs(self, session, host_ref):
944 return xen_api_success(XendDomain.instance().get_domain_refs())
945 def host_get_PBDs(self, _, ref):
946 return xen_api_success(XendPBD.get_all())
947 def host_get_PIFs(self, session, ref):
948 return xen_api_success(XendNode.instance().get_PIF_refs())
949 def host_get_host_CPUs(self, session, host_ref):
950 return xen_api_success(XendNode.instance().get_host_cpu_refs())
951 def host_get_metrics(self, _, ref):
952 return xen_api_success(XendNode.instance().host_metrics_uuid)
953 def host_get_capabilities(self, session, host_ref):
954 return xen_api_success(XendNode.instance().get_capabilities())
955 def host_get_supported_bootloaders(self, session, host_ref):
956 return xen_api_success(['pygrub'])
957 def host_get_sched_policy(self, _, host_ref):
958 return xen_api_success(XendNode.instance().get_vcpus_policy())
959 def host_get_cpu_configuration(self, _, host_ref):
960 return xen_api_success(XendNode.instance().get_cpu_configuration())
961 def host_set_logging(self, _, host_ref, logging):
962 return xen_api_todo()
963 def host_get_logging(self, _, host_ref):
964 return xen_api_todo()
966 # object methods
967 def host_disable(self, session, host_ref):
968 XendDomain.instance().set_allow_new_domains(False)
969 return xen_api_success_void()
970 def host_enable(self, session, host_ref):
971 XendDomain.instance().set_allow_new_domains(True)
972 return xen_api_success_void()
973 def host_reboot(self, session, host_ref):
974 if not XendDomain.instance().allow_new_domains():
975 return xen_api_error(XEND_ERROR_HOST_RUNNING)
976 return xen_api_error(XEND_ERROR_UNSUPPORTED)
977 def host_shutdown(self, session, host_ref):
978 if not XendDomain.instance().allow_new_domains():
979 return xen_api_error(XEND_ERROR_HOST_RUNNING)
980 return xen_api_error(XEND_ERROR_UNSUPPORTED)
982 def host_dmesg(self, session, host_ref):
983 return xen_api_success(XendDmesg.instance().info())
985 def host_dmesg_clear(self, session, host_ref):
986 return xen_api_success(XendDmesg.instance().clear())
988 def host_get_log(self, session, host_ref):
989 log_file = open(XendLogging.getLogFilename())
990 log_buffer = log_file.read()
991 return xen_api_success(log_buffer)
993 def host_send_debug_keys(self, _, host_ref, keys):
994 node = XendNode.instance()
995 node.send_debug_keys(keys)
996 return xen_api_success_void()
998 def host_get_record(self, session, host_ref):
999 node = XendNode.instance()
1000 dom = XendDomain.instance()
1001 record = {'uuid': node.uuid,
1002 'name_label': node.name,
1003 'name_description': '',
1004 'API_version_major': XEN_API_VERSION_MAJOR,
1005 'API_version_minor': XEN_API_VERSION_MINOR,
1006 'API_version_vendor': XEN_API_VERSION_VENDOR,
1007 'API_version_vendor_implementation':
1008 XEN_API_VERSION_VENDOR_IMPLEMENTATION,
1009 'software_version': node.xen_version(),
1010 'enabled': XendDomain.instance().allow_new_domains(),
1011 'other_config': node.other_config,
1012 'resident_VMs': dom.get_domain_refs(),
1013 'host_CPUs': node.get_host_cpu_refs(),
1014 'cpu_configuration': node.get_cpu_configuration(),
1015 'metrics': node.host_metrics_uuid,
1016 'capabilities': node.get_capabilities(),
1017 'supported_bootloaders': ['pygrub'],
1018 'sched_policy': node.get_vcpus_policy(),
1019 'logging': {},
1020 'PIFs': XendPIF.get_all(),
1021 'PBDs': XendPBD.get_all()}
1022 return xen_api_success(record)
1024 # class methods
1025 def host_get_all(self, session):
1026 return xen_api_success((XendNode.instance().uuid,))
1027 def host_get_by_name_label(self, session, name):
1028 if XendNode.instance().name == name:
1029 return xen_api_success((XendNode.instance().uuid,))
1030 return xen_api_success([])
1032 def host_list_methods(self, _):
1033 def _funcs():
1034 return [getattr(XendAPI, x) for x in XendAPI.__dict__]
1036 return xen_api_success([x.api for x in _funcs()
1037 if hasattr(x, 'api')])
1039 # Xen API: Class host_CPU
1040 # ----------------------------------------------------------------
1042 host_cpu_attr_ro = ['host',
1043 'number',
1044 'vendor',
1045 'speed',
1046 'modelname',
1047 'stepping',
1048 'flags',
1049 'utilisation',
1050 'features']
1052 # attributes
1053 def _host_cpu_get(self, ref, field):
1054 return xen_api_success(
1055 XendNode.instance().get_host_cpu_field(ref, field))
1057 def host_cpu_get_host(self, _, ref):
1058 return xen_api_success(XendNode.instance().uuid)
1059 def host_cpu_get_features(self, _, ref):
1060 return self._host_cpu_get(ref, 'features')
1061 def host_cpu_get_number(self, _, ref):
1062 return self._host_cpu_get(ref, 'number')
1063 def host_cpu_get_vendor(self, _, ref):
1064 return self._host_cpu_get(ref, 'vendor')
1065 def host_cpu_get_speed(self, _, ref):
1066 return self._host_cpu_get(ref, 'speed')
1067 def host_cpu_get_modelname(self, _, ref):
1068 return self._host_cpu_get(ref, 'modelname')
1069 def host_cpu_get_stepping(self, _, ref):
1070 return self._host_cpu_get(ref, 'stepping')
1071 def host_cpu_get_flags(self, _, ref):
1072 return self._host_cpu_get(ref, 'flags')
1073 def host_cpu_get_utilisation(self, _, ref):
1074 return xen_api_success(XendNode.instance().get_host_cpu_load(ref))
1076 # object methods
1077 def host_cpu_get_record(self, _, ref):
1078 node = XendNode.instance()
1079 record = dict([(f, node.get_host_cpu_field(ref, f))
1080 for f in self.host_cpu_attr_ro
1081 if f not in ['uuid', 'host', 'utilisation']])
1082 record['uuid'] = ref
1083 record['host'] = node.uuid
1084 record['utilisation'] = node.get_host_cpu_load(ref)
1085 return xen_api_success(record)
1087 # class methods
1088 def host_cpu_get_all(self, session):
1089 return xen_api_success(XendNode.instance().get_host_cpu_refs())
1092 # Xen API: Class host_metrics
1093 # ----------------------------------------------------------------
1095 host_metrics_attr_ro = ['memory_total',
1096 'memory_free',
1097 'last_updated']
1098 host_metrics_attr_rw = []
1099 host_metrics_methods = []
1101 def host_metrics_get_all(self, _):
1102 return xen_api_success([XendNode.instance().host_metrics_uuid])
1104 def _host_metrics_get(self, ref, f):
1105 return xen_api_success(getattr(node, f)())
1107 def host_metrics_get_record(self, _, ref):
1108 return xen_api_success({
1109 'uuid' : ref,
1110 'memory_total' : self._host_metrics_get_memory_total(),
1111 'memory_free' : self._host_metrics_get_memory_free(),
1112 'last_updated' : now(),
1113 })
1115 def host_metrics_get_memory_total(self, _1, _2):
1116 return xen_api_success(self._host_metrics_get_memory_total())
1118 def host_metrics_get_memory_free(self, _1, _2):
1119 return xen_api_success(self._host_metrics_get_memory_free())
1121 def host_metrics_get_last_updated(self, _1, _2):
1122 return xen_api_success(now())
1124 def _host_metrics_get_memory_total(self):
1125 node = XendNode.instance()
1126 return node.xc.physinfo()['total_memory'] * 1024
1128 def _host_metrics_get_memory_free(self):
1129 node = XendNode.instance()
1130 return node.xc.physinfo()['free_memory'] * 1024
1132 # Xen API: Class VM
1133 # ----------------------------------------------------------------
1135 VM_attr_ro = ['power_state',
1136 'resident_on',
1137 'consoles',
1138 'VIFs',
1139 'VBDs',
1140 'VTPMs',
1141 'tools_version',
1142 'domid',
1143 'is_control_domain',
1144 'metrics',
1145 'crash_dumps',
1148 VM_attr_rw = ['name_label',
1149 'name_description',
1150 'user_version',
1151 'is_a_template',
1152 'auto_power_on',
1153 'memory_dynamic_max',
1154 'memory_dynamic_min',
1155 'memory_static_max',
1156 'memory_static_min',
1157 'VCPUs_max',
1158 'VCPUs_at_startup',
1159 'VCPUs_params',
1160 'actions_after_shutdown',
1161 'actions_after_reboot',
1162 'actions_after_suspend',
1163 'actions_after_crash',
1164 'PV_bootloader',
1165 'PV_kernel',
1166 'PV_ramdisk',
1167 'PV_args',
1168 'PV_bootloader_args',
1169 'HVM_boot_policy',
1170 'HVM_boot_params',
1171 'platform',
1172 'PCI_bus',
1173 'other_config']
1175 VM_methods = [('clone', 'VM'),
1176 ('start', None),
1177 ('pause', None),
1178 ('unpause', None),
1179 ('clean_shutdown', None),
1180 ('clean_reboot', None),
1181 ('hard_shutdown', None),
1182 ('hard_reboot', None),
1183 ('suspend', None),
1184 ('resume', None),
1185 ('send_sysrq', None),
1186 ('set_VCPUs_number_live', None),
1187 ('add_to_HVM_boot_params', None),
1188 ('remove_from_HVM_boot_params', None),
1189 ('add_to_VCPUs_params', None),
1190 ('add_to_VCPUs_params_live', None),
1191 ('remove_from_VCPUs_params', None),
1192 ('add_to_platform', None),
1193 ('remove_from_platform', None),
1194 ('add_to_other_config', None),
1195 ('remove_from_other_config', None),
1196 ('save', None),
1197 ('set_memory_dynamic_max_live', None),
1198 ('set_memory_dynamic_min_live', None),
1199 ('send_trigger', None),
1200 ('migrate', None),
1201 ('destroy', None)]
1203 VM_funcs = [('create', 'VM'),
1204 ('restore', None),
1205 ('get_by_name_label', 'Set(VM)')]
1207 # parameters required for _create()
1208 VM_attr_inst = [
1209 'name_label',
1210 'name_description',
1211 'user_version',
1212 'is_a_template',
1213 'memory_static_max',
1214 'memory_dynamic_max',
1215 'memory_dynamic_min',
1216 'memory_static_min',
1217 'VCPUs_max',
1218 'VCPUs_at_startup',
1219 'VCPUs_params',
1220 'actions_after_shutdown',
1221 'actions_after_reboot',
1222 'actions_after_suspend',
1223 'actions_after_crash',
1224 'PV_bootloader',
1225 'PV_kernel',
1226 'PV_ramdisk',
1227 'PV_args',
1228 'PV_bootloader_args',
1229 'HVM_boot_policy',
1230 'HVM_boot_params',
1231 'platform',
1232 'PCI_bus',
1233 'other_config']
1235 def VM_get(self, name, session, vm_ref):
1236 return xen_api_success(
1237 XendDomain.instance().get_vm_by_uuid(vm_ref).info[name])
1239 def VM_set(self, name, session, vm_ref, value):
1240 xd = XendDomain.instance()
1241 dominfo = xd.get_vm_by_uuid(vm_ref)
1242 dominfo.info[name] = value
1243 return self._VM_save(dominfo)
1245 def _VM_save(self, dominfo):
1246 XendDomain.instance().managed_config_save(dominfo)
1247 return xen_api_success_void()
1249 # attributes (ro)
1250 def VM_get_power_state(self, session, vm_ref):
1251 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1252 return xen_api_success(dom.get_power_state())
1254 def VM_get_resident_on(self, session, vm_ref):
1255 return xen_api_success(XendNode.instance().uuid)
1257 def VM_get_memory_static_max(self, session, vm_ref):
1258 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1259 return xen_api_success(dom.get_memory_static_max())
1261 def VM_get_memory_static_min(self, session, vm_ref):
1262 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1263 return xen_api_success(dom.get_memory_static_min())
1265 def VM_get_VIFs(self, session, vm_ref):
1266 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1267 return xen_api_success(dom.get_vifs())
1269 def VM_get_VBDs(self, session, vm_ref):
1270 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1271 return xen_api_success(dom.get_vbds())
1273 def VM_get_VTPMs(self, session, vm_ref):
1274 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1275 return xen_api_success(dom.get_vtpms())
1277 def VM_get_consoles(self, session, vm_ref):
1278 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1279 return xen_api_success(dom.get_consoles())
1281 def VM_get_tools_version(self, session, vm_ref):
1282 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1283 return dom.get_tools_version()
1285 def VM_get_metrics(self, _, vm_ref):
1286 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1287 return xen_api_success(dom.get_metrics())
1289 def VM_get_VCPUs_max(self, _, vm_ref):
1290 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1291 return xen_api_todo()
1293 def VM_get_VCPUs_at_startup(self, _, vm_ref):
1294 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1295 return xen_api_todo()
1297 # attributes (rw)
1298 def VM_get_name_label(self, session, vm_ref):
1299 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1300 return xen_api_success(dom.getName())
1302 def VM_get_name_description(self, session, vm_ref):
1303 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1304 return xen_api_todo()
1306 def VM_get_user_version(self, session, vm_ref):
1307 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1308 return xen_api_todo()
1310 def VM_get_is_a_template(self, session, ref):
1311 return self.VM_get('is_a_template', session, ref)
1313 def VM_get_memory_dynamic_max(self, session, vm_ref):
1314 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1315 return xen_api_success(dom.get_memory_dynamic_max())
1317 def VM_get_memory_dynamic_min(self, session, vm_ref):
1318 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1319 return xen_api_success(dom.get_memory_dynamic_min())
1321 def VM_get_VCPUs_params(self, session, vm_ref):
1322 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1323 return xen_api_success(dom.get_vcpus_params())
1325 def VM_get_actions_after_shutdown(self, session, vm_ref):
1326 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1327 return xen_api_success(dom.get_on_shutdown())
1329 def VM_get_actions_after_reboot(self, session, vm_ref):
1330 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1331 return xen_api_success(dom.get_on_reboot())
1333 def VM_get_actions_after_suspend(self, session, vm_ref):
1334 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1335 return xen_api_success(dom.get_on_suspend())
1337 def VM_get_actions_after_crash(self, session, vm_ref):
1338 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1339 return xen_api_success(dom.get_on_crash())
1341 def VM_get_PV_bootloader(self, session, vm_ref):
1342 return self.VM_get('PV_bootloader', session, vm_ref)
1344 def VM_get_PV_kernel(self, session, vm_ref):
1345 return self.VM_get('PV_kernel', session, vm_ref)
1347 def VM_get_PV_ramdisk(self, session, vm_ref):
1348 return self.VM_get('PV_ramdisk', session, vm_ref)
1350 def VM_get_PV_args(self, session, vm_ref):
1351 return self.VM_get('PV_args', session, vm_ref)
1353 def VM_get_PV_bootloader_args(self, session, vm_ref):
1354 return self.VM_get('PV_bootloader_args', session, vm_ref)
1356 def VM_get_HVM_boot_policy(self, session, vm_ref):
1357 return self.VM_get('HVM_boot_policy', session, vm_ref)
1359 def VM_get_HVM_boot_params(self, session, vm_ref):
1360 return self.VM_get('HVM_boot_params', session, vm_ref)
1362 def VM_get_platform(self, session, vm_ref):
1363 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1364 return xen_api_success(dom.get_platform())
1366 def VM_get_PCI_bus(self, session, vm_ref):
1367 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1368 return dom.get_pci_bus()
1370 def VM_set_PCI_bus(self, session, vm_ref, val):
1371 return self.VM_set('PCI_bus', session, vm_ref, val)
1373 def VM_get_other_config(self, session, vm_ref):
1374 return self.VM_get('other_config', session, vm_ref)
1376 def VM_get_domid(self, _, ref):
1377 domid = XendDomain.instance().get_vm_by_uuid(ref).getDomid()
1378 return xen_api_success(domid is None and -1 or domid)
1380 def VM_get_is_control_domain(self, session, vm_ref):
1381 xd = XendDomain.instance()
1382 return xen_api_success(
1383 xd.get_vm_by_uuid(vm_ref) == xd.privilegedDomain())
1385 def VM_set_name_label(self, session, vm_ref, label):
1386 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1387 dom.setName(label)
1388 return self._VM_save(dom)
1390 def VM_set_name_description(self, session, vm_ref, desc):
1391 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1392 return xen_api_todo()
1394 def VM_set_user_version(self, session, vm_ref, ver):
1395 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1396 return xen_api_todo()
1398 def VM_set_is_a_template(self, session, vm_ref, is_template):
1399 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1400 return xen_api_todo()
1402 def VM_set_memory_dynamic_max(self, session, vm_ref, mem):
1403 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1404 dom.set_memory_dynamic_max(int(mem))
1405 return xen_api_success_void()
1407 def VM_set_memory_dynamic_min(self, session, vm_ref, mem):
1408 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1409 dom.set_memory_dynamic_min(int(mem))
1410 return xen_api_success_void()
1412 def VM_set_memory_static_max(self, session, vm_ref, mem):
1413 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1414 dom.set_memory_static_max(int(mem))
1415 return xen_api_success_void()
1417 def VM_set_memory_static_min(self, session, vm_ref, mem):
1418 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1419 dom.set_memory_static_min(int(mem))
1420 return xen_api_success_void()
1422 def VM_set_memory_dynamic_max_live(self, session, vm_ref, mem):
1423 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1424 dom.set_memory_dynamic_max(int(mem))
1425 # need to pass target as MiB
1426 dom.setMemoryTarget(int(mem)/1024/1024)
1427 return xen_api_success_void()
1429 def VM_set_memory_dynamic_min_live(self, session, vm_ref, mem):
1430 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1431 dom.set_memory_dynamic_min(int(mem))
1432 # need to pass target as MiB
1433 dom.setMemoryTarget(int(mem)/1024/1024)
1434 return xen_api_success_void()
1436 def VM_set_VCPUs_params(self, session, vm_ref, value):
1437 return self.VM_set('vcpus_params', session, vm_ref, value)
1439 def VM_add_to_VCPUs_params(self, session, vm_ref, key, value):
1440 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1441 if 'vcpus_params' not in dom.info:
1442 dom.info['vcpus_params'] = {}
1443 dom.info['vcpus_params'][key] = value
1444 return self._VM_save(dom)
1446 def VM_add_to_VCPUs_params_live(self, session, vm_ref, key, value):
1447 self.VM_add_to_VCPUs_params(session, vm_ref, key, value)
1448 self._VM_VCPUs_params_refresh(vm_ref)
1449 return xen_api_success_void()
1451 def _VM_VCPUs_params_refresh(self, vm_ref):
1452 xendom = XendDomain.instance()
1453 xeninfo = xendom.get_vm_by_uuid(vm_ref)
1455 #update the cpumaps
1456 for key, value in xeninfo.info['vcpus_params'].items():
1457 if key.startswith("cpumap"):
1458 vcpu = int(key[6:])
1459 try:
1460 cpus = map(int, value.split(","))
1461 xendom.domain_pincpu(xeninfo.getDomid(), vcpu, cpus)
1462 except Exception, ex:
1463 log.exception(ex)
1465 #need to update sched params aswell
1466 if 'weight' in xeninfo.info['vcpus_params'] \
1467 and 'cap' in xeninfo.info['vcpus_params']:
1468 weight = xeninfo.info['vcpus_params']['weight']
1469 cap = xeninfo.info['vcpus_params']['cap']
1470 xendom.domain_sched_credit_set(xeninfo.getDomid(), weight, cap)
1472 def VM_set_VCPUs_number_live(self, _, vm_ref, num):
1473 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1474 dom.setVCpuCount(int(num))
1475 return xen_api_success_void()
1477 def VM_remove_from_VCPUs_params(self, session, vm_ref, key):
1478 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1479 if 'vcpus_params' in dom.info \
1480 and key in dom.info['vcpus_params']:
1481 del dom.info['vcpus_params'][key]
1482 return self._VM_save(dom)
1483 else:
1484 return xen_api_success_void()
1486 def VM_set_VCPUs_at_startup(self, session, vm_ref, num):
1487 return self.VM_set('VCPUs_at_startup', session, vm_ref, num)
1489 def VM_set_VCPUs_max(self, session, vm_ref, num):
1490 return self.VM_set('VCPUs_max', session, vm_ref, num)
1492 def VM_set_actions_after_shutdown(self, session, vm_ref, action):
1493 if action not in XEN_API_ON_NORMAL_EXIT:
1494 return xen_api_error(['VM_ON_NORMAL_EXIT_INVALID', vm_ref])
1495 return self.VM_set('actions_after_shutdown', session, vm_ref, action)
1497 def VM_set_actions_after_reboot(self, session, vm_ref, action):
1498 if action not in XEN_API_ON_NORMAL_EXIT:
1499 return xen_api_error(['VM_ON_NORMAL_EXIT_INVALID', vm_ref])
1500 return self.VM_set('actions_after_reboot', session, vm_ref, action)
1502 def VM_set_actions_after_suspend(self, session, vm_ref, action):
1503 if action not in XEN_API_ON_NORMAL_EXIT:
1504 return xen_api_error(['VM_ON_NORMAL_EXIT_INVALID', vm_ref])
1505 return self.VM_set('actions_after_suspend', session, vm_ref, action)
1507 def VM_set_actions_after_crash(self, session, vm_ref, action):
1508 if action not in XEN_API_ON_CRASH_BEHAVIOUR:
1509 return xen_api_error(['VM_ON_CRASH_BEHAVIOUR_INVALID', vm_ref])
1510 return self.VM_set('actions_after_crash', session, vm_ref, action)
1512 def VM_set_HVM_boot_policy(self, session, vm_ref, value):
1513 if value != "" and value != "BIOS order":
1514 return xen_api_error(
1515 ['VALUE_NOT_SUPPORTED', 'VM.HVM_boot_policy', value,
1516 'Xend supports only the "BIOS order" boot policy.'])
1517 else:
1518 return self.VM_set('HVM_boot_policy', session, vm_ref, value)
1520 def VM_set_HVM_boot_params(self, session, vm_ref, value):
1521 return self.VM_set('HVM_boot_params', session, vm_ref, value)
1523 def VM_add_to_HVM_boot_params(self, session, vm_ref, key, value):
1524 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1525 if 'HVM_boot_params' not in dom.info:
1526 dom.info['HVM_boot_params'] = {}
1527 dom.info['HVM_boot_params'][key] = value
1528 return self._VM_save(dom)
1530 def VM_remove_from_HVM_boot_params(self, session, vm_ref, key):
1531 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1532 if 'HVM_boot_params' in dom.info \
1533 and key in dom.info['HVM_boot_params']:
1534 del dom.info['HVM_boot_params'][key]
1535 return self._VM_save(dom)
1536 else:
1537 return xen_api_success_void()
1539 def VM_set_PV_bootloader(self, session, vm_ref, value):
1540 return self.VM_set('PV_bootloader', session, vm_ref, value)
1542 def VM_set_PV_kernel(self, session, vm_ref, value):
1543 return self.VM_set('PV_kernel', session, vm_ref, value)
1545 def VM_set_PV_ramdisk(self, session, vm_ref, value):
1546 return self.VM_set('PV_ramdisk', session, vm_ref, value)
1548 def VM_set_PV_args(self, session, vm_ref, value):
1549 return self.VM_set('PV_args', session, vm_ref, value)
1551 def VM_set_PV_bootloader_args(self, session, vm_ref, value):
1552 return self.VM_set('PV_bootloader_args', session, vm_ref, value)
1554 def VM_set_platform(self, session, vm_ref, value):
1555 return self.VM_set('platform', session, vm_ref, value)
1557 def VM_add_to_platform(self, session, vm_ref, key, value):
1558 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1559 plat = dom.get_platform()
1560 plat[key] = value
1561 return self.VM_set_platform(session, vm_ref, plat)
1563 def VM_remove_from_platform(self, session, vm_ref, key):
1564 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1565 plat = dom.get_platform()
1566 if key in plat:
1567 del plat[key]
1568 return self.VM_set_platform(session, vm_ref, plat)
1569 else:
1570 return xen_api_success_void()
1572 def VM_set_other_config(self, session, vm_ref, value):
1573 return self.VM_set('other_config', session, vm_ref, value)
1575 def VM_add_to_other_config(self, session, vm_ref, key, value):
1576 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1577 if dom and 'other_config' in dom.info:
1578 dom.info['other_config'][key] = value
1579 return self._VM_save(dom)
1581 def VM_remove_from_other_config(self, session, vm_ref, key):
1582 dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
1583 if dom and 'other_config' in dom.info \
1584 and key in dom.info['other_config']:
1585 del dom.info['other_config'][key]
1586 return self._VM_save(dom)
1587 else:
1588 return xen_api_success_void()
1590 def VM_get_crash_dumps(self, _, vm_ref):
1591 return xen_api_todo()
1593 # class methods
1594 def VM_get_all(self, session):
1595 refs = [d.get_uuid() for d in XendDomain.instance().list('all')]
1596 return xen_api_success(refs)
1598 def VM_get_by_name_label(self, session, label):
1599 xendom = XendDomain.instance()
1600 dom = xendom.domain_lookup_nr(label)
1601 if dom:
1602 return xen_api_success([dom.get_uuid()])
1603 return xen_api_success([])
1605 def VM_create(self, session, vm_struct):
1606 xendom = XendDomain.instance()
1607 domuuid = XendTask.log_progress(0, 100,
1608 xendom.create_domain, vm_struct)
1609 return xen_api_success(domuuid)
1611 # object methods
1612 def VM_get_record(self, session, vm_ref):
1613 xendom = XendDomain.instance()
1614 xeninfo = xendom.get_vm_by_uuid(vm_ref)
1615 if not xeninfo:
1616 return xen_api_error(['HANDLE_INVALID', 'VM', vm_ref])
1618 domid = xeninfo.getDomid()
1620 record = {
1621 'uuid': xeninfo.get_uuid(),
1622 'power_state': xeninfo.get_power_state(),
1623 'name_label': xeninfo.getName(),
1624 'name_description': xeninfo.getName(),
1625 'user_version': 1,
1626 'is_a_template': xeninfo.info['is_a_template'],
1627 'auto_power_on': False,
1628 'resident_on': XendNode.instance().uuid,
1629 'memory_static_min': xeninfo.get_memory_static_min(),
1630 'memory_static_max': xeninfo.get_memory_static_max(),
1631 'memory_dynamic_min': xeninfo.get_memory_dynamic_min(),
1632 'memory_dynamic_max': xeninfo.get_memory_dynamic_max(),
1633 'VCPUs_params': xeninfo.get_vcpus_params(),
1634 'VCPUs_at_startup': xeninfo.getVCpuCount(),
1635 'VCPUs_max': xeninfo.getVCpuCount(),
1636 'actions_after_shutdown': xeninfo.get_on_shutdown(),
1637 'actions_after_reboot': xeninfo.get_on_reboot(),
1638 'actions_after_suspend': xeninfo.get_on_suspend(),
1639 'actions_after_crash': xeninfo.get_on_crash(),
1640 'consoles': xeninfo.get_consoles(),
1641 'VIFs': xeninfo.get_vifs(),
1642 'VBDs': xeninfo.get_vbds(),
1643 'VTPMs': xeninfo.get_vtpms(),
1644 'PV_bootloader': xeninfo.info.get('PV_bootloader'),
1645 'PV_kernel': xeninfo.info.get('PV_kernel'),
1646 'PV_ramdisk': xeninfo.info.get('PV_ramdisk'),
1647 'PV_args': xeninfo.info.get('PV_args'),
1648 'PV_bootloader_args': xeninfo.info.get('PV_bootloader_args'),
1649 'HVM_boot_policy': xeninfo.info.get('HVM_boot_policy'),
1650 'HVM_boot_params': xeninfo.info.get('HVM_boot_params'),
1651 'platform': xeninfo.get_platform(),
1652 'PCI_bus': xeninfo.get_pci_bus(),
1653 'tools_version': xeninfo.get_tools_version(),
1654 'other_config': xeninfo.info.get('other_config', {}),
1655 'domid': domid is None and -1 or domid,
1656 'is_control_domain': xeninfo.info['is_control_domain'],
1657 'metrics': xeninfo.get_metrics(),
1658 'crash_dumps': []
1660 return xen_api_success(record)
1662 def VM_clean_reboot(self, session, vm_ref):
1663 xendom = XendDomain.instance()
1664 xeninfo = xendom.get_vm_by_uuid(vm_ref)
1665 XendTask.log_progress(0, 100, xeninfo.shutdown, "reboot")
1666 return xen_api_success_void()
1668 def VM_clean_shutdown(self, session, vm_ref):
1669 xendom = XendDomain.instance()
1670 xeninfo = xendom.get_vm_by_uuid(vm_ref)
1671 XendTask.log_progress(0, 100, xeninfo.shutdown, "poweroff")
1672 return xen_api_success_void()
1674 def VM_clone(self, session, vm_ref):
1675 return xen_api_error(XEND_ERROR_UNSUPPORTED)
1677 def VM_destroy(self, session, vm_ref):
1678 return XendTask.log_progress(0, 100, do_vm_func,
1679 "domain_delete", vm_ref)
1681 def VM_hard_reboot(self, session, vm_ref):
1682 return xen_api_error(XEND_ERROR_UNSUPPORTED)
1684 def VM_hard_shutdown(self, session, vm_ref):
1685 return XendTask.log_progress(0, 100, do_vm_func,
1686 "domain_destroy", vm_ref)
1687 def VM_pause(self, session, vm_ref):
1688 return XendTask.log_progress(0, 100, do_vm_func,
1689 "domain_pause", vm_ref)
1691 def VM_resume(self, session, vm_ref, start_paused):
1692 return XendTask.log_progress(0, 100, do_vm_func,
1693 "domain_resume", vm_ref,
1694 start_paused = start_paused)
1696 def VM_start(self, session, vm_ref, start_paused):
1697 try:
1698 return XendTask.log_progress(0, 100, do_vm_func,
1699 "domain_start", vm_ref,
1700 start_paused = start_paused)
1701 except HVMRequired, exn:
1702 return xen_api_error(['VM_HVM_REQUIRED', vm_ref])
1704 def VM_suspend(self, session, vm_ref):
1705 return XendTask.log_progress(0, 100, do_vm_func,
1706 "domain_suspend", vm_ref)
1708 def VM_unpause(self, session, vm_ref):
1709 return XendTask.log_progress(0, 100, do_vm_func,
1710 "domain_unpause", vm_ref)
1712 def VM_send_sysrq(self, _, vm_ref, req):
1713 xeninfo = XendDomain.instance().get_vm_by_uuid(vm_ref)
1714 if xeninfo.state == XEN_API_VM_POWER_STATE_RUNNING \
1715 or xeninfo.state == XEN_API_VM_POWER_STATE_PAUSED:
1716 xeninfo.send_sysrq(req)
1717 return xen_api_success_void()
1718 else:
1719 return xen_api_error(
1720 ['VM_BAD_POWER_STATE', vm_ref,
1721 XendDomain.POWER_STATE_NAMES[XEN_API_VM_POWER_STATE_RUNNING],
1722 XendDomain.POWER_STATE_NAMES[xeninfo.state]])
1724 def VM_send_trigger(self, _, vm_ref, trigger, vcpu):
1725 xendom = XendDomain.instance()
1726 xeninfo = xendom.get_vm_by_uuid(vm_ref)
1727 xendom.domain_send_trigger(xeninfo.getDomid(), trigger, vcpu)
1728 return xen_api_success_void()
1730 def VM_migrate(self, _, vm_ref, destination_url, live, other_config):
1731 xendom = XendDomain.instance()
1732 xeninfo = xendom.get_vm_by_uuid(vm_ref)
1734 resource = other_config.get("resource", 0)
1735 port = other_config.get("port", 0)
1737 xendom.domain_migrate(xeninfo.getDomid(), destination_url,
1738 bool(live), resource, port)
1739 return xen_api_success_void()
1741 def VM_save(self, _, vm_ref, dest, checkpoint):
1742 xendom = XendDomain.instance()
1743 xeninfo = xendom.get_vm_by_uuid(vm_ref)
1744 xendom.domain_save(xeninfo.getDomid(), dest, checkpoint)
1745 return xen_api_success_void()
1747 def VM_restore(self, _, src, paused):
1748 xendom = XendDomain.instance()
1749 xendom.domain_restore(src, bool(paused))
1750 return xen_api_success_void()
1753 # Xen API: Class VBD
1754 # ----------------------------------------------------------------
1756 VBD_attr_ro = ['VM',
1757 'VDI',
1758 'metrics',
1759 'runtime_properties']
1760 VBD_attr_rw = ['device',
1761 'bootable',
1762 'mode',
1763 'type']
1765 VBD_attr_inst = VBD_attr_rw
1767 VBD_methods = [('media_change', None), ('destroy', None)]
1768 VBD_funcs = [('create', 'VBD')]
1770 # object methods
1771 def VBD_get_record(self, session, vbd_ref):
1772 xendom = XendDomain.instance()
1773 vm = xendom.get_vm_with_dev_uuid('vbd', vbd_ref)
1774 if not vm:
1775 return xen_api_error(['HANDLE_INVALID', 'VBD', vbd_ref])
1776 cfg = vm.get_dev_xenapi_config('vbd', vbd_ref)
1777 if not cfg:
1778 return xen_api_error(['HANDLE_INVALID', 'VBD', vbd_ref])
1780 valid_vbd_keys = self.VBD_attr_ro + self.VBD_attr_rw + \
1781 self.Base_attr_ro + self.Base_attr_rw
1783 return_cfg = {}
1784 for k in cfg.keys():
1785 if k in valid_vbd_keys:
1786 return_cfg[k] = cfg[k]
1788 return_cfg['metrics'] = vbd_ref
1789 return_cfg['runtime_properties'] = {} #todo
1791 return xen_api_success(return_cfg)
1793 def VBD_media_change(self, session, vbd_ref, vdi_ref):
1794 return xen_api_error(XEND_ERROR_UNSUPPORTED)
1796 # class methods
1797 def VBD_create(self, session, vbd_struct):
1798 xendom = XendDomain.instance()
1799 xennode = XendNode.instance()
1801 if not xendom.is_valid_vm(vbd_struct['VM']):
1802 return xen_api_error(['HANDLE_INVALID', 'VM', vbd_struct['VM']])
1804 dom = xendom.get_vm_by_uuid(vbd_struct['VM'])
1805 vdi = xennode.get_vdi_by_uuid(vbd_struct['VDI'])
1806 if not vdi:
1807 return xen_api_error(['HANDLE_INVALID', 'VDI', vdi_ref])
1809 # new VBD via VDI/SR
1810 vdi_image = vdi.get_location()
1812 try:
1813 vbd_ref = XendTask.log_progress(0, 100,
1814 dom.create_vbd,
1815 vbd_struct, vdi_image)
1816 except XendError, e:
1817 log.exception("Error in VBD_create")
1818 return xen_api_error(['INTERNAL_ERROR', str(e)])
1820 vdi.addVBD(vbd_ref)
1822 xendom.managed_config_save(dom)
1823 return xen_api_success(vbd_ref)
1826 def VBD_destroy(self, session, vbd_ref):
1827 xendom = XendDomain.instance()
1828 vm = xendom.get_vm_with_dev_uuid('vbd', vbd_ref)
1829 if not vm:
1830 return xen_api_error(['HANDLE_INVALID', 'VBD', vbd_ref])
1832 vdi_ref = XendDomain.instance()\
1833 .get_dev_property_by_uuid('vbd', vbd_ref, "VDI")
1834 vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
1836 XendTask.log_progress(0, 100, vm.destroy_vbd, vbd_ref)
1838 vdi.removeVBD(vbd_ref)
1840 return xen_api_success_void()
1842 def _VBD_get(self, vbd_ref, prop):
1843 return xen_api_success(
1844 XendDomain.instance().get_dev_property_by_uuid(
1845 'vbd', vbd_ref, prop))
1847 # attributes (ro)
1848 def VBD_get_metrics(self, _, vbd_ref):
1849 return xen_api_success(vbd_ref)
1851 def VBD_get_runtime_properties(self, _, vbd_ref):
1852 xendom = XendDomain.instance()
1853 dominfo = xendom.get_vm_with_dev_uuid('vbd', vbd_ref)
1854 device = dominfo.get_dev_config_by_uuid('vbd', vbd_ref)
1856 try:
1857 devid = int(device['id'])
1858 device_sxps = dominfo.getDeviceSxprs('vbd')
1859 device_dicts = [dict(device_sxp[1][0:]) for device_sxp in device_sxps]
1860 device_dict = [device_dict
1861 for device_dict in device_dicts
1862 if int(device_dict['virtual-device']) == devid][0]
1864 return xen_api_success(device_dict)
1865 except Exception, exn:
1866 log.exception(exn)
1867 return xen_api_success({})
1869 # attributes (rw)
1870 def VBD_get_VM(self, session, vbd_ref):
1871 return self._VBD_get(vbd_ref, 'VM')
1873 def VBD_get_VDI(self, session, vbd_ref):
1874 return self._VBD_get(vbd_ref, 'VDI')
1876 def VBD_get_device(self, session, vbd_ref):
1877 return self._VBD_get(vbd_ref, 'device')
1879 def VBD_get_bootable(self, session, vbd_ref):
1880 return self._VBD_get(vbd_ref, 'bootable')
1882 def VBD_get_mode(self, session, vbd_ref):
1883 return self._VBD_get(vbd_ref, 'mode')
1885 def VBD_get_type(self, session, vbd_ref):
1886 return self._VBD_get(vbd_ref, 'type')
1888 def VBD_set_bootable(self, session, vbd_ref, bootable):
1889 bootable = bool(bootable)
1890 xd = XendDomain.instance()
1891 vm = xd.get_vm_with_dev_uuid('vbd', vbd_ref)
1892 vm.set_dev_property('vbd', vbd_ref, 'bootable', bootable)
1893 xd.managed_config_save(vm)
1894 return xen_api_success_void()
1896 def VBD_set_mode(self, session, vbd_ref, mode):
1897 if mode == 'RW':
1898 mode = 'w'
1899 else:
1900 mode = 'r'
1901 xd = XendDomain.instance()
1902 vm = xd.get_vm_with_dev_uuid('vbd', vbd_ref)
1903 vm.set_dev_property('vbd', vbd_ref, 'mode', mode)
1904 xd.managed_config_save(vm)
1905 return xen_api_success_void()
1907 def VBD_get_all(self, session):
1908 xendom = XendDomain.instance()
1909 vbds = [d.get_vbds() for d in XendDomain.instance().list('all')]
1910 vbds = reduce(lambda x, y: x + y, vbds)
1911 return xen_api_success(vbds)
1914 # Xen API: Class VBD_metrics
1915 # ----------------------------------------------------------------
1917 VBD_metrics_attr_ro = ['io_read_kbs',
1918 'io_write_kbs',
1919 'last_updated']
1920 VBD_metrics_attr_rw = []
1921 VBD_metrics_methods = []
1923 def VBD_metrics_get_all(self, session):
1924 return self.VBD_get_all(session)
1926 def VBD_metrics_get_record(self, _, ref):
1927 vm = XendDomain.instance().get_vm_with_dev_uuid('vbd', ref)
1928 if not vm:
1929 return xen_api_error(['HANDLE_INVALID', 'VBD_metrics', ref])
1930 return xen_api_success(
1931 { 'io_read_kbs' : vm.get_dev_property('vbd', ref, 'io_read_kbs'),
1932 'io_write_kbs' : vm.get_dev_property('vbd', ref, 'io_write_kbs'),
1933 'last_updated' : now()
1934 })
1936 def VBD_metrics_get_io_read_kbs(self, _, ref):
1937 return self._VBD_get(ref, 'io_read_kbs')
1939 def VBD_metrics_get_io_write_kbs(self, session, ref):
1940 return self._VBD_get(ref, 'io_write_kbs')
1942 def VBD_metrics_get_last_updated(self, _1, _2):
1943 return xen_api_success(now())
1946 # Xen API: Class VIF
1947 # ----------------------------------------------------------------
1949 VIF_attr_ro = ['network',
1950 'VM',
1951 'metrics',
1952 'runtime_properties']
1953 VIF_attr_rw = ['device',
1954 'MAC',
1955 'MTU']
1957 VIF_attr_inst = VIF_attr_rw
1959 VIF_methods = [('destroy', None)]
1960 VIF_funcs = [('create', 'VIF')]
1963 # object methods
1964 def VIF_get_record(self, session, vif_ref):
1965 xendom = XendDomain.instance()
1966 vm = xendom.get_vm_with_dev_uuid('vif', vif_ref)
1967 if not vm:
1968 return xen_api_error(['HANDLE_INVALID', 'VIF', vif_ref])
1969 cfg = vm.get_dev_xenapi_config('vif', vif_ref)
1970 if not cfg:
1971 return xen_api_error(['HANDLE_INVALID', 'VIF', vif_ref])
1973 valid_vif_keys = self.VIF_attr_ro + self.VIF_attr_rw + \
1974 self.Base_attr_ro + self.Base_attr_rw
1976 return_cfg = {}
1977 for k in cfg.keys():
1978 if k in valid_vif_keys:
1979 return_cfg[k] = cfg[k]
1981 return_cfg['metrics'] = vif_ref
1983 return xen_api_success(return_cfg)
1985 # class methods
1986 def VIF_create(self, session, vif_struct):
1987 xendom = XendDomain.instance()
1988 if not xendom.is_valid_vm(vif_struct['VM']):
1989 return xen_api_error(['HANDLE_INVALID', 'VM', vif_struct['VM']])
1991 dom = xendom.get_vm_by_uuid(vif_struct['VM'])
1992 try:
1993 vif_ref = dom.create_vif(vif_struct)
1994 xendom.managed_config_save(dom)
1995 return xen_api_success(vif_ref)
1996 except XendError, exn:
1997 return xen_api_error(['INTERNAL_ERROR', str(exn)])
1999 def VIF_destroy(self, session, vif_ref):
2000 xendom = XendDomain.instance()
2001 vm = xendom.get_vm_with_dev_uuid('vif', vif_ref)
2002 if not vm:
2003 return xen_api_error(['HANDLE_INVALID', 'VIF', vif_ref])
2005 vm.destroy_vif(vif_ref)
2006 return xen_api_success_void()
2008 def _VIF_get(self, ref, prop):
2009 return xen_api_success(
2010 XendDomain.instance().get_dev_property_by_uuid('vif', ref, prop))
2012 # getters/setters
2013 def VIF_get_metrics(self, _, vif_ref):
2014 return xen_api_success(vif_ref)
2016 def VIF_get_VM(self, session, vif_ref):
2017 xendom = XendDomain.instance()
2018 vm = xendom.get_vm_with_dev_uuid('vif', vif_ref)
2019 return xen_api_success(vm.get_uuid())
2021 def VIF_get_MTU(self, session, vif_ref):
2022 return self._VIF_get(vif_ref, 'MTU')
2024 def VIF_get_MAC(self, session, vif_ref):
2025 return self._VIF_get(vif_ref, 'MAC')
2027 def VIF_get_device(self, session, vif_ref):
2028 return self._VIF_get(vif_ref, 'device')
2030 def VIF_get_all(self, session):
2031 xendom = XendDomain.instance()
2032 vifs = [d.get_vifs() for d in XendDomain.instance().list('all')]
2033 vifs = reduce(lambda x, y: x + y, vifs)
2034 return xen_api_success(vifs)
2036 def VIF_get_runtime_properties(self, _, vif_ref):
2037 xendom = XendDomain.instance()
2038 dominfo = xendom.get_vm_with_dev_uuid('vif', vif_ref)
2039 device = dominfo.get_dev_config_by_uuid('vif', vif_ref)
2041 try:
2042 devid = int(device['id'])
2044 device_sxps = dominfo.getDeviceSxprs('vif')
2045 device_dicts = [dict(device_sxp[1][1:])
2046 for device_sxp in device_sxps]
2048 device_dict = [device_dict
2049 for device_dict in device_dicts
2050 if int(device_dict['handle']) == devid][0]
2052 return xen_api_success(device_dict)
2054 except Exception, exn:
2055 log.exception(exn)
2056 return xen_api_success({})
2058 # Xen API: Class VIF_metrics
2059 # ----------------------------------------------------------------
2061 VIF_metrics_attr_ro = ['io_read_kbs',
2062 'io_write_kbs',
2063 'last_updated']
2064 VIF_metrics_attr_rw = []
2065 VIF_metrics_methods = []
2067 def VIF_metrics_get_all(self, session):
2068 return self.VIF_get_all(session)
2070 def VIF_metrics_get_record(self, _, ref):
2071 vm = XendDomain.instance().get_vm_with_dev_uuid('vif', ref)
2072 if not vm:
2073 return xen_api_error(['HANDLE_INVALID', 'VIF_metrics', ref])
2074 return xen_api_success(
2075 { 'io_read_kbs' : vm.get_dev_property('vif', ref, 'io_read_kbs'),
2076 'io_write_kbs' : vm.get_dev_property('vif', ref, 'io_write_kbs'),
2077 'last_updated' : now()
2078 })
2080 def VIF_metrics_get_io_read_kbs(self, _, ref):
2081 return self._VIF_get(ref, 'io_read_kbs')
2083 def VIF_metrics_get_io_write_kbs(self, session, ref):
2084 return self._VIF_get(ref, 'io_write_kbs')
2086 def VIF_metrics_get_last_updated(self, _1, _2):
2087 return xen_api_success(now())
2090 # Xen API: Class VDI
2091 # ----------------------------------------------------------------
2092 VDI_attr_ro = ['SR',
2093 'VBDs',
2094 'physical_utilisation',
2095 'type']
2096 VDI_attr_rw = ['name_label',
2097 'name_description',
2098 'virtual_size',
2099 'sharable',
2100 'read_only',
2101 'other_config']
2102 VDI_attr_inst = VDI_attr_ro + VDI_attr_rw
2104 VDI_methods = [('destroy', None)]
2105 VDI_funcs = [('create', 'VDI'),
2106 ('get_by_name_label', 'Set(VDI)')]
2108 def _get_VDI(self, ref):
2109 return XendNode.instance().get_vdi_by_uuid(ref)
2111 def VDI_get_VBDs(self, session, vdi_ref):
2112 vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
2113 return xen_api_success(vdi.getVBDs())
2115 def VDI_get_physical_utilisation(self, session, vdi_ref):
2116 return xen_api_success(self._get_VDI(vdi_ref).
2117 get_physical_utilisation())
2119 def VDI_get_type(self, session, vdi_ref):
2120 return xen_api_success(self._get_VDI(vdi_ref).type)
2122 def VDI_get_name_label(self, session, vdi_ref):
2123 return xen_api_success(self._get_VDI(vdi_ref).name_label)
2125 def VDI_get_name_description(self, session, vdi_ref):
2126 return xen_api_success(self._get_VDI(vdi_ref).name_description)
2128 def VDI_get_SR(self, session, vdi_ref):
2129 return xen_api_success(self._get_VDI(vdi_ref).sr_uuid)
2131 def VDI_get_virtual_size(self, session, vdi_ref):
2132 return xen_api_success(self._get_VDI(vdi_ref).virtual_size)
2134 def VDI_get_sharable(self, session, vdi_ref):
2135 return xen_api_success(self._get_VDI(vdi_ref).sharable)
2137 def VDI_get_read_only(self, session, vdi_ref):
2138 return xen_api_success(self._get_VDI(vdi_ref).read_only)
2140 def VDI_set_name_label(self, session, vdi_ref, value):
2141 self._get_VDI(vdi_ref).name_label = value
2142 return xen_api_success_void()
2144 def VDI_set_name_description(self, session, vdi_ref, value):
2145 self._get_VDI(vdi_ref).name_description = value
2146 return xen_api_success_void()
2148 def VDI_set_virtual_size(self, session, vdi_ref, value):
2149 return xen_api_error(XEND_ERROR_UNSUPPORTED)
2151 def VDI_set_sharable(self, session, vdi_ref, value):
2152 self._get_VDI(vdi_ref).sharable = bool(value)
2153 return xen_api_success_void()
2155 def VDI_set_read_only(self, session, vdi_ref, value):
2156 self._get_VDI(vdi_ref).read_only = bool(value)
2157 return xen_api_success_void()
2159 def VDI_get_other_config(self, session, vdi_ref):
2160 return xen_api_success(
2161 self._get_VDI(vdi_ref).other_config)
2163 def VDI_set_other_config(self, session, vdi_ref, other_config):
2164 self._get_VDI(vdi_ref).other_config = other_config
2165 return xen_api_success_void()
2167 # Object Methods
2169 def VDI_destroy(self, session, vdi_ref):
2170 sr = XendNode.instance().get_sr_containing_vdi(vdi_ref)
2171 sr.destroy_vdi(vdi_ref)
2172 return xen_api_success_void()
2174 def VDI_get_record(self, session, vdi_ref):
2175 image = XendNode.instance().get_vdi_by_uuid(vdi_ref)
2176 return xen_api_success({
2177 'uuid': vdi_ref,
2178 'name_label': image.name_label,
2179 'name_description': image.name_description,
2180 'SR': image.sr_uuid,
2181 'VBDs': image.getVBDs(),
2182 'virtual_size': image.virtual_size,
2183 'physical_utilisation': image.physical_utilisation,
2184 'type': image.type,
2185 'sharable': image.sharable,
2186 'read_only': image.read_only,
2187 'other_config': image.other_config
2188 })
2190 # Class Functions
2191 def VDI_create(self, session, vdi_struct):
2192 sr_ref = vdi_struct.get('SR')
2193 xennode = XendNode.instance()
2194 if not xennode.is_valid_sr(sr_ref):
2195 return xen_api_error(['HANDLE_INVALID', 'SR', sr_ref])
2197 vdi_uuid = xennode.srs[sr_ref].create_vdi(vdi_struct)
2198 return xen_api_success(vdi_uuid)
2200 def VDI_get_all(self, session):
2201 xennode = XendNode.instance()
2202 vdis = [sr.get_vdis() for sr in xennode.srs.values()]
2203 return xen_api_success(reduce(lambda x, y: x + y, vdis))
2205 def VDI_get_by_name_label(self, session, name):
2206 xennode = XendNode.instance()
2207 return xen_api_success(xennode.get_vdi_by_name_label(name))
2210 # Xen API: Class VTPM
2211 # ----------------------------------------------------------------
2213 VTPM_attr_rw = [ ]
2214 VTPM_attr_ro = ['VM',
2215 'backend']
2217 VTPM_attr_inst = VTPM_attr_rw
2219 VTPM_methods = [('destroy', None)]
2220 VTPM_funcs = [('create', 'VTPM')]
2222 # object methods
2223 def VTPM_get_record(self, session, vtpm_ref):
2224 xendom = XendDomain.instance()
2225 vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
2226 if not vm:
2227 return xen_api_error(['HANDLE_INVALID', 'VTPM', vtpm_ref])
2228 cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref)
2229 if not cfg:
2230 return xen_api_error(['HANDLE_INVALID', 'VTPM', vtpm_ref])
2231 valid_vtpm_keys = self.VTPM_attr_ro + self.VTPM_attr_rw + \
2232 self.Base_attr_ro + self.Base_attr_rw
2233 return_cfg = {}
2234 for k in cfg.keys():
2235 if k in valid_vtpm_keys:
2236 return_cfg[k] = cfg[k]
2238 return xen_api_success(return_cfg)
2240 # Class Functions
2241 def VTPM_get_backend(self, session, vtpm_ref):
2242 xendom = XendDomain.instance()
2243 vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
2244 if not vm:
2245 return xen_api_error(['HANDLE_INVALID', 'VTPM', vtpm_ref])
2246 cfg = vm.get_dev_xenapi_config('vtpm', vtpm_ref)
2247 if not cfg:
2248 return xen_api_error(['HANDLE_INVALID', 'VTPM', vtpm_ref])
2249 if not cfg.has_key('backend'):
2250 return xen_api_error(['INTERNAL_ERROR', 'VTPM backend not set'])
2251 return xen_api_success(cfg['backend'])
2253 def VTPM_get_VM(self, session, vtpm_ref):
2254 xendom = XendDomain.instance()
2255 return xen_api_success(xendom.get_dev_property_by_uuid('vtpm',
2256 vtpm_ref, 'VM'))
2258 def VTPM_destroy(self, session, vtpm_ref):
2259 xendom = XendDomain.instance()
2260 dom = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref)
2261 if dom:
2262 if dom.state != XEN_API_VM_POWER_STATE_HALTED:
2263 vm_ref = dom.get_dev_property('vtpm', vtpm_ref, 'VM')
2264 return xen_api_error(['VM_BAD_POWER_STATE', vm_ref,
2265 XendDomain.POWER_STATE_NAMES[XEN_API_VM_POWER_STATE_HALTED],
2266 XendDomain.POWER_STATE_NAMES[dom.state]])
2267 from xen.xend.server import tpmif
2268 tpmif.destroy_vtpmstate(dom.getName())
2269 return xen_api_success_void()
2270 else:
2271 return xen_api_error(['HANDLE_INVALID', 'VM', vtpm_struct['VM']])
2273 # class methods
2274 def VTPM_create(self, session, vtpm_struct):
2275 xendom = XendDomain.instance()
2276 if xendom.is_valid_vm(vtpm_struct['VM']):
2277 dom = xendom.get_vm_by_uuid(vtpm_struct['VM'])
2278 try:
2279 vtpm_ref = dom.create_vtpm(vtpm_struct)
2280 xendom.managed_config_save(dom)
2281 return xen_api_success(vtpm_ref)
2282 except XendError, exn:
2283 return xen_api_error(['INTERNAL_ERROR', str(exn)])
2284 else:
2285 return xen_api_error(['HANDLE_INVALID', 'VM', vtpm_struct['VM']])
2287 def VTPM_get_all(self, session):
2288 xendom = XendDomain.instance()
2289 vtpms = [d.get_vtpms() for d in XendDomain.instance().list('all')]
2290 vtpms = reduce(lambda x, y: x + y, vtpms)
2291 return xen_api_success(vtpms)
2293 # Xen API: Class console
2294 # ----------------------------------------------------------------
2297 console_attr_ro = ['location', 'protocol', 'VM']
2298 console_attr_rw = ['other_config']
2299 console_funcs = [('create', 'console')]
2301 def console_get_all(self, session):
2302 xendom = XendDomain.instance()
2303 cons = [d.get_consoles() for d in XendDomain.instance().list('all')]
2304 cons = reduce(lambda x, y: x + y, cons)
2305 return xen_api_success(cons)
2307 def console_get_location(self, session, console_ref):
2308 return xen_api_success(xendom.get_dev_property_by_uuid('console',
2309 console_ref,
2310 'location'))
2312 def console_get_protocol(self, session, console_ref):
2313 return xen_api_success(xendom.get_dev_property_by_uuid('console',
2314 console_ref,
2315 'protocol'))
2317 def console_get_VM(self, session, console_ref):
2318 xendom = XendDomain.instance()
2319 vm = xendom.get_vm_with_dev_uuid('console', console_ref)
2320 return xen_api_success(vm.get_uuid())
2322 # object methods
2323 def console_get_record(self, session, console_ref):
2324 xendom = XendDomain.instance()
2325 vm = xendom.get_vm_with_dev_uuid('console', console_ref)
2326 if not vm:
2327 return xen_api_error(['HANDLE_INVALID', 'console', console_ref])
2328 cfg = vm.get_dev_xenapi_config('console', console_ref)
2329 if not cfg:
2330 return xen_api_error(['HANDLE_INVALID', 'console', console_ref])
2332 valid_console_keys = self.console_attr_ro + self.console_attr_rw + \
2333 self.Base_attr_ro + self.Base_attr_rw
2335 return_cfg = {}
2336 for k in cfg.keys():
2337 if k in valid_console_keys:
2338 return_cfg[k] = cfg[k]
2340 return xen_api_success(return_cfg)
2342 def console_create(self, session, console_struct):
2343 xendom = XendDomain.instance()
2344 if not xendom.is_valid_vm(console_struct['VM']):
2345 return xen_api_error(['HANDLE_INVALID', 'VM',
2346 console_struct['VM']])
2348 dom = xendom.get_vm_by_uuid(console_struct['VM'])
2349 try:
2350 if 'protocol' not in console_struct:
2351 return xen_api_error(['CONSOLE_PROTOCOL_INVALID',
2352 'No protocol specified'])
2354 console_ref = dom.create_console(console_struct)
2355 xendom.managed_config_save(dom)
2356 return xen_api_success(console_ref)
2357 except XendError, exn:
2358 return xen_api_error(['INTERNAL_ERROR', str(exn)])
2360 # Xen API: Class SR
2361 # ----------------------------------------------------------------
2362 SR_attr_ro = ['VDIs',
2363 'virtual_allocation',
2364 'physical_utilisation',
2365 'physical_size',
2366 'type',
2367 'content_type']
2369 SR_attr_rw = ['name_label',
2370 'name_description']
2372 SR_attr_inst = ['physical_size',
2373 'type',
2374 'name_label',
2375 'name_description']
2377 SR_methods = []
2378 SR_funcs = [('get_by_name_label', 'Set(SR)'),
2379 ('get_by_uuid', 'SR')]
2381 # Class Functions
2382 def SR_get_all(self, session):
2383 return xen_api_success(XendNode.instance().get_all_sr_uuid())
2385 def SR_get_by_name_label(self, session, label):
2386 return xen_api_success(XendNode.instance().get_sr_by_name(label))
2388 def SR_get_supported_types(self, _):
2389 return xen_api_success(['local', 'qcow_file'])
2391 # Class Methods
2393 def SR_get_record(self, session, sr_ref):
2394 sr = XendNode.instance().get_sr(sr_ref)
2395 if sr:
2396 return xen_api_success(sr.get_record())
2397 return xen_api_error(['HANDLE_INVALID', 'SR', sr_ref])
2399 # Attribute acceess
2401 def _get_SR_func(self, sr_ref, func):
2402 return xen_api_success(getattr(XendNode.instance().get_sr(sr_ref),
2403 func)())
2405 def _get_SR_attr(self, sr_ref, attr):
2406 return xen_api_success(getattr(XendNode.instance().get_sr(sr_ref),
2407 attr))
2409 def SR_get_VDIs(self, _, ref):
2410 return self._get_SR_func(ref, 'list_images')
2412 def SR_get_virtual_allocation(self, _, ref):
2413 return self._get_SR_func(ref, 'virtual_allocation')
2415 def SR_get_physical_utilisation(self, _, ref):
2416 return self._get_SR_func(ref, 'physical_utilisation')
2418 def SR_get_physical_size(self, _, ref):
2419 return self._get_SR_func(ref, 'physical_size')
2421 def SR_get_type(self, _, ref):
2422 return self._get_SR_attr(ref, 'type')
2424 def SR_get_content_type(self, _, ref):
2425 return self._get_SR_attr(ref, 'content_type')
2427 def SR_get_name_label(self, _, ref):
2428 return self._get_SR_attr(ref, 'name_label')
2430 def SR_get_name_description(self, _, ref):
2431 return self._get_SR_attr(ref, 'name_description')
2433 def SR_set_name_label(self, session, sr_ref, value):
2434 sr = XendNode.instance.get_sr(sr_ref)
2435 if sr:
2436 sr.name_label = value
2437 XendNode.instance().save()
2438 return xen_api_success_void()
2440 def SR_set_name_description(self, session, sr_ref, value):
2441 sr = XendNode.instance.get_sr(sr_ref)
2442 if sr:
2443 sr.name_description = value
2444 XendNode.instance().save()
2445 return xen_api_success_void()
2448 # Xen API: Class event
2449 # ----------------------------------------------------------------
2451 event_attr_ro = []
2452 event_attr_rw = []
2453 event_funcs = [('register', None),
2454 ('unregister', None),
2455 ('next', None)]
2457 def event_register(self, session, reg_classes):
2458 event_register(session, reg_classes)
2459 return xen_api_success_void()
2461 def event_unregister(self, session, unreg_classes):
2462 event_unregister(session, reg_classes)
2463 return xen_api_success_void()
2465 def event_next(self, session):
2466 return event_next(session)
2468 # Xen API: Class debug
2469 # ----------------------------------------------------------------
2471 debug_methods = [('destroy', None),
2472 ('get_record', 'debug')]
2473 debug_funcs = [('wait', None),
2474 ('return_failure', None)]
2476 def debug_wait(self, session, wait_secs):
2477 import time
2478 prog_units = 100/float(wait_secs)
2479 for i in range(int(wait_secs)):
2480 XendTask.log_progress(prog_units * i, prog_units * (i + 1),
2481 time.sleep, 1)
2482 return xen_api_success_void()
2485 def debug_return_failure(self, session):
2486 return xen_api_error(['DEBUG_FAIL', session])
2488 def debug_create(self, session):
2489 debug_uuid = uuid.createString()
2490 self._debug[debug_uuid] = None
2491 return xen_api_success(debug_uuid)
2493 def debug_destroy(self, session, debug_ref):
2494 del self._debug[debug_ref]
2495 return xen_api_success_void()
2497 def debug_get_record(self, session, debug_ref):
2498 return xen_api_success({'uuid': debug_ref})
2501 class XendAPIAsyncProxy:
2502 """ A redirector for Async.Class.function calls to XendAPI
2503 but wraps the call for use with the XendTaskManager.
2505 @ivar xenapi: Xen API instance
2506 @ivar method_map: Mapping from XMLRPC method name to callable objects.
2507 """
2509 method_prefix = 'Async.'
2511 def __init__(self, xenapi):
2512 """Initialises the Async Proxy by making a map of all
2513 implemented Xen API methods for use with XendTaskManager.
2515 @param xenapi: XendAPI instance
2516 """
2517 self.xenapi = xenapi
2518 self.method_map = {}
2519 for method_name in dir(self.xenapi):
2520 method = getattr(self.xenapi, method_name)
2521 if method_name[0] != '_' and hasattr(method, 'async') \
2522 and method.async == True:
2523 self.method_map[method.api] = method
2525 def _dispatch(self, method, args):
2526 """Overridden method so that SimpleXMLRPCServer will
2527 resolve methods through this method rather than through
2528 inspection.
2530 @param method: marshalled method name from XMLRPC.
2531 @param args: marshalled arguments from XMLRPC.
2532 """
2534 # Only deal with method names that start with "Async."
2535 if not method.startswith(self.method_prefix):
2536 return xen_api_error(['MESSAGE_METHOD_UNKNOWN', method])
2538 # Lookup synchronous version of the method
2539 synchronous_method_name = method[len(self.method_prefix):]
2540 if synchronous_method_name not in self.method_map:
2541 return xen_api_error(['MESSAGE_METHOD_UNKNOWN', method])
2543 method = self.method_map[synchronous_method_name]
2545 # Check that we've got enough arguments before issuing a task ID.
2546 needed = argcounts[method.api]
2547 if len(args) != needed:
2548 return xen_api_error(['MESSAGE_PARAMETER_COUNT_MISMATCH',
2549 self.method_prefix + method.api, needed,
2550 len(args)])
2552 # Validate the session before proceeding
2553 session = args[0]
2554 if not auth_manager().is_session_valid(session):
2555 return xen_api_error(['SESSION_INVALID', session])
2557 # create and execute the task, and return task_uuid
2558 return_type = getattr(method, 'return_type', None)
2559 task_uuid = XendTaskManager.create_task(method, args,
2560 synchronous_method_name,
2561 return_type,
2562 synchronous_method_name,
2563 session)
2564 return xen_api_success(task_uuid)