Fixes bug 942556 and bug 944105

Ensures the calls in the xenhost plugin work when the host is in
a xenserver pool managed by the host aggregates feature.

Change-Id: I51ca6b9f6d0e8d86d53afde5bf46cfabde17a44e
This commit is contained in:
John Garbutt 2012-02-29 15:50:14 +00:00
parent 45146b337b
commit 37a392dc4c
2 changed files with 55 additions and 47 deletions

View File

@ -510,27 +510,40 @@ class XenAPISession(object):
self.XenAPI = self.get_imported_xenapi() self.XenAPI = self.get_imported_xenapi()
self._sessions = queue.Queue() self._sessions = queue.Queue()
self.host_uuid = None self.host_uuid = None
self.is_slave = False
exception = self.XenAPI.Failure(_("Unable to log in to XenAPI " exception = self.XenAPI.Failure(_("Unable to log in to XenAPI "
"(is the Dom0 disk full?)")) "(is the Dom0 disk full?)"))
is_slave = False url = self._create_first_session(url, user, pw, exception)
for i in xrange(FLAGS.xenapi_connection_concurrent): self._populate_session_pool(url, user, pw, exception)
try: self._populate_host_uuid()
session = self._create_session(url)
with timeout.Timeout(FLAGS.xenapi_login_timeout, exception): def _create_first_session(self, url, user, pw, exception):
session.login_with_password(user, pw) try:
except self.XenAPI.Failure, e: session = self._create_session(url)
# if user and pw of the master are different, we're doomed! with timeout.Timeout(FLAGS.xenapi_login_timeout, exception):
if e.details[0] == 'HOST_IS_SLAVE': session.login_with_password(user, pw)
master = e.details[1] except self.XenAPI.Failure, e:
session = self.XenAPI.Session(pool.swap_xapi_host(url, # if user and pw of the master are different, we're doomed!
master)) if e.details[0] == 'HOST_IS_SLAVE':
session.login_with_password(user, pw) master = e.details[1]
is_slave = True url = pool.swap_xapi_host(url, master)
else: session = self.XenAPI.Session(url)
raise session.login_with_password(user, pw)
self.is_slave = True
else:
raise
self._sessions.put(session)
return url
def _populate_session_pool(self, url, user, pw, exception):
for _ in xrange(FLAGS.xenapi_connection_concurrent - 1):
session = self._create_session(url)
with timeout.Timeout(FLAGS.xenapi_login_timeout, exception):
session.login_with_password(user, pw)
self._sessions.put(session) self._sessions.put(session)
if is_slave: def _populate_host_uuid(self):
if self.is_slave:
try: try:
aggr = db.aggregate_get_by_host(context.get_admin_context(), aggr = db.aggregate_get_by_host(context.get_admin_context(),
FLAGS.host) FLAGS.host)
@ -539,6 +552,10 @@ class XenAPISession(object):
LOG.exception(_('Host is member of a pool, but DB ' LOG.exception(_('Host is member of a pool, but DB '
'says otherwise')) 'says otherwise'))
raise raise
else:
with self._get_session() as session:
host_ref = session.xenapi.session.get_this_host(session.handle)
self.host_uuid = session.xenapi.host.get_uuid(host_ref)
def get_product_version(self): def get_product_version(self):
"""Return a tuple of (major, minor, rev) for the host version""" """Return a tuple of (major, minor, rev) for the host version"""
@ -569,10 +586,7 @@ class XenAPISession(object):
def get_xenapi_host(self): def get_xenapi_host(self):
"""Return the xenapi host on which nova-compute runs on.""" """Return the xenapi host on which nova-compute runs on."""
with self._get_session() as session: with self._get_session() as session:
if self.host_uuid: return session.xenapi.host.get_by_uuid(self.host_uuid)
return session.xenapi.host.get_by_uuid(self.host_uuid)
else:
return session.xenapi.session.get_this_host(session.handle)
def call_xenapi(self, method, *args): def call_xenapi(self, method, *args):
"""Call the specified XenAPI method on a background thread.""" """Call the specified XenAPI method on a background thread."""
@ -599,8 +613,7 @@ class XenAPISession(object):
host = self.get_xenapi_host() host = self.get_xenapi_host()
# NOTE(armando): pass the host uuid along with the args so that # NOTE(armando): pass the host uuid along with the args so that
# the plugin gets executed on the right host when using XS pools # the plugin gets executed on the right host when using XS pools
if self.host_uuid: args['host_uuid'] = self.host_uuid
args['host_uuid'] = self.host_uuid
with self._get_session() as session: with self._get_session() as session:
return tpool.execute(self._unwrap_plugin_exceptions, return tpool.execute(self._unwrap_plugin_exceptions,
session.xenapi.Async.host.call_plugin, session.xenapi.Async.host.call_plugin,

View File

@ -18,7 +18,7 @@
# under the License. # under the License.
# #
# XenAPI plugin for reading/writing information to xenstore # XenAPI plugin for host operations
# #
try: try:
@ -122,12 +122,6 @@ def _resume_compute(session, compute_ref, compute_uuid):
% (DEFAULT_SLEEP * (DEFAULT_TRIES + 1))) % (DEFAULT_SLEEP * (DEFAULT_TRIES + 1)))
def _get_host_uuid():
cmd = "xe host-list | grep uuid"
resp = _run_command(cmd)
return resp.split(":")[-1].strip()
@jsonify @jsonify
def set_host_enabled(self, arg_dict): def set_host_enabled(self, arg_dict):
"""Sets this host's ability to accept new instances. """Sets this host's ability to accept new instances.
@ -137,17 +131,18 @@ def set_host_enabled(self, arg_dict):
if enabled is None: if enabled is None:
raise pluginlib.PluginError( raise pluginlib.PluginError(
_("Missing 'enabled' argument to set_host_enabled")) _("Missing 'enabled' argument to set_host_enabled"))
host_uuid = arg_dict['host_uuid']
if enabled == "true": if enabled == "true":
result = _run_command("xe host-enable") result = _run_command("xe host-enable uuid=%s" % host_uuid)
elif enabled == "false": elif enabled == "false":
result = _run_command("xe host-disable") result = _run_command("xe host-disable uuid=%s" % host_uuid)
else: else:
raise pluginlib.PluginError(_("Illegal enabled status: %s") % enabled) raise pluginlib.PluginError(_("Illegal enabled status: %s") % enabled)
# Should be empty string # Should be empty string
if result: if result:
raise pluginlib.PluginError(result) raise pluginlib.PluginError(result)
# Return the current enabled status # Return the current enabled status
host_uuid = _get_host_uuid()
cmd = "xe host-param-list uuid=%s | grep enabled" % host_uuid cmd = "xe host-param-list uuid=%s | grep enabled" % host_uuid
resp = _run_command(cmd) resp = _run_command(cmd)
# Response should be in the format: "enabled ( RO): true" # Response should be in the format: "enabled ( RO): true"
@ -243,20 +238,21 @@ def iptables_config(session, args):
raise pluginlib.PluginError(_("Invalid iptables command")) raise pluginlib.PluginError(_("Invalid iptables command"))
def _power_action(action): def _power_action(action, arg_dict):
host_uuid = _get_host_uuid()
# Host must be disabled first # Host must be disabled first
result = _run_command("xe host-disable") host_uuid = arg_dict['host_uuid']
result = _run_command("xe host-disable uuid=%s" % host_uuid)
if result: if result:
raise pluginlib.PluginError(result) raise pluginlib.PluginError(result)
# All running VMs must be shutdown # All running VMs must be shutdown
result = _run_command("xe vm-shutdown --multiple power-state=running") result = _run_command("xe vm-shutdown --multiple "
"resident-on=%s" % host_uuid)
if result: if result:
raise pluginlib.PluginError(result) raise pluginlib.PluginError(result)
cmds = {"reboot": "xe host-reboot", cmds = {"reboot": "xe host-reboot uuid=%s",
"startup": "xe host-power-on", "startup": "xe host-power-on uuid=%s",
"shutdown": "xe host-shutdown"} "shutdown": "xe host-shutdown uuid=%s"}
result = _run_command(cmds[action]) result = _run_command(cmds[action] % host_uuid)
# Should be empty string # Should be empty string
if result: if result:
raise pluginlib.PluginError(result) raise pluginlib.PluginError(result)
@ -266,13 +262,13 @@ def _power_action(action):
@jsonify @jsonify
def host_reboot(self, arg_dict): def host_reboot(self, arg_dict):
"""Reboots the host.""" """Reboots the host."""
return _power_action("reboot") return _power_action("reboot", arg_dict)
@jsonify @jsonify
def host_shutdown(self, arg_dict): def host_shutdown(self, arg_dict):
"""Reboots the host.""" """Reboots the host."""
return _power_action("shutdown") return _power_action("shutdown", arg_dict)
@jsonify @jsonify
@ -280,7 +276,7 @@ def host_start(self, arg_dict):
"""Starts the host. Currently not feasible, since the host """Starts the host. Currently not feasible, since the host
runs on the same machine as Xen. runs on the same machine as Xen.
""" """
return _power_action("startup") return _power_action("startup", arg_dict)
@jsonify @jsonify
@ -316,9 +312,8 @@ def host_data(self, arg_dict):
"""Runs the commands on the xenstore host to return the current status """Runs the commands on the xenstore host to return the current status
information. information.
""" """
host_uuid = arg_dict.get('host_uuid', _get_host_uuid()) host_uuid = arg_dict['host_uuid']
cmd = "xe host-param-list uuid=%s" % host_uuid resp = _run_command("xe host-param-list uuid=%s" % host_uuid)
resp = _run_command(cmd)
parsed_data = parse_response(resp) parsed_data = parse_response(resp)
# We have the raw dict of values. Extract those that we need, # We have the raw dict of values. Extract those that we need,
# and convert the data types as needed. # and convert the data types as needed.