summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/api/openstack/compute/servers.py6
-rw-r--r--nova/compute/manager.py97
-rw-r--r--nova/tests/compute/test_compute.py13
-rw-r--r--nova/virt/xenapi/agent.py4
4 files changed, 59 insertions, 61 deletions
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index ac4ebd293..88a52001c 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -1180,7 +1180,11 @@ class Controller(wsgi.Controller):
msg = _("Invalid adminPass")
raise exc.HTTPBadRequest(explanation=msg)
server = self._get_server(context, req, id)
- self.compute_api.set_admin_password(context, server, password)
+ try:
+ self.compute_api.set_admin_password(context, server, password)
+ except NotImplementedError:
+ msg = _("Unable to set password on instance")
+ raise exc.HTTPNotImplemented(explanation=msg)
return webob.Response(status_int=202)
def _validate_metadata(self, metadata):
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 17ece99da..0ad5c1dc8 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -1582,68 +1582,57 @@ class ComputeManager(manager.SchedulerDependentManager):
"""
context = context.elevated()
-
if new_pass is None:
# Generate a random password
new_pass = utils.generate_password()
- max_tries = 10
-
- for i in xrange(max_tries):
- current_power_state = self._get_power_state(context, instance)
- expected_state = power_state.RUNNING
+ current_power_state = self._get_power_state(context, instance)
+ expected_state = power_state.RUNNING
- if current_power_state != expected_state:
- self._instance_update(context, instance['uuid'],
+ if current_power_state != expected_state:
+ self._instance_update(context, instance['uuid'],
+ task_state=None,
+ expected_task_state=task_states.
+ UPDATING_PASSWORD)
+ _msg = _('Failed to set admin password. Instance %s is not'
+ ' running') % instance["uuid"]
+ raise exception.InstancePasswordSetFailed(
+ instance=instance['uuid'], reason=_msg)
+ else:
+ try:
+ self.driver.set_admin_password(instance, new_pass)
+ LOG.audit(_("Root password set"), instance=instance)
+ self._instance_update(context,
+ instance['uuid'],
+ task_state=None,
+ expected_task_state=task_states.
+ UPDATING_PASSWORD)
+ except NotImplementedError:
+ _msg = _('set_admin_password is not implemented '
+ 'by this driver or guest instance.')
+ LOG.warn(_msg, instance=instance)
+ self._instance_update(context,
+ instance['uuid'],
task_state=None,
expected_task_state=task_states.
- UPDATING_PASSWORD)
- _msg = _('Failed to set admin password. Instance %s is not'
- ' running') % instance["uuid"]
+ UPDATING_PASSWORD)
+ raise NotImplementedError(_msg)
+ except exception.UnexpectedTaskStateError:
+ # interrupted by another (most likely delete) task
+ # do not retry
+ raise
+ except Exception, e:
+ # Catch all here because this could be anything.
+ LOG.exception(_('set_admin_password failed: %s') % e,
+ instance=instance)
+ self._set_instance_error_state(context,
+ instance['uuid'])
+ # We create a new exception here so that we won't
+ # potentially reveal password information to the
+ # API caller. The real exception is logged above
+ _msg = _('error setting admin password')
raise exception.InstancePasswordSetFailed(
- instance=instance['uuid'], reason=_msg)
- else:
- try:
- self.driver.set_admin_password(instance, new_pass)
- LOG.audit(_("Root password set"), instance=instance)
- self._instance_update(context,
- instance['uuid'],
- task_state=None,
- expected_task_state=task_states.
- UPDATING_PASSWORD)
- break
- except NotImplementedError:
- # NOTE(dprince): if the driver doesn't implement
- # set_admin_password we break to avoid a loop
- _msg = _('set_admin_password is not implemented '
- 'by this driver.')
- LOG.warn(_msg, instance=instance)
- self._instance_update(context,
- instance['uuid'],
- task_state=None,
- expected_task_state=task_states.
- UPDATING_PASSWORD)
- raise exception.InstancePasswordSetFailed(
- instance=instance['uuid'], reason=_msg)
- except exception.UnexpectedTaskStateError:
- # interrupted by another (most likely delete) task
- # do not retry
- raise
- except Exception, e:
- # Catch all here because this could be anything.
- LOG.exception(_('set_admin_password failed: %s') % e,
- instance=instance)
- if i == max_tries - 1:
- self._set_instance_error_state(context,
- instance['uuid'])
- # We create a new exception here so that we won't
- # potentially reveal password information to the
- # API caller. The real exception is logged above
- _msg = _('error setting admin password')
- raise exception.InstancePasswordSetFailed(
- instance=instance['uuid'], reason=_msg)
- time.sleep(1)
- continue
+ instance=instance['uuid'], reason=_msg)
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
@reverts_task_state
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index 361e7386a..b5a8b91a2 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -1147,7 +1147,8 @@ class ComputeTestCase(BaseTestCase):
self.compute.terminate_instance(self.context, instance=instance)
def _do_test_set_admin_password_driver_error(self, exc, expected_vm_state,
- expected_task_state):
+ expected_task_state,
+ expected_exception):
"""Ensure expected exception is raised if set_admin_password fails."""
def fake_sleep(_time):
@@ -1172,7 +1173,7 @@ class ComputeTestCase(BaseTestCase):
#error raised from the driver should not reveal internal information
#so a new error is raised
- self.assertRaises(exception.InstancePasswordSetFailed,
+ self.assertRaises(expected_exception,
self.compute.set_admin_password,
self.context,
instance=jsonutils.to_primitive(inst_ref))
@@ -1190,9 +1191,11 @@ class ComputeTestCase(BaseTestCase):
authorized.
"""
exc = exception.NotAuthorized(_('Internal error'))
+ expected_exception = exception.InstancePasswordSetFailed
self._do_test_set_admin_password_driver_error(exc,
vm_states.ERROR,
- None)
+ None,
+ expected_exception)
def test_set_admin_password_driver_not_implemented(self):
"""
@@ -1200,9 +1203,11 @@ class ComputeTestCase(BaseTestCase):
implemented by driver.
"""
exc = NotImplementedError()
+ expected_exception = NotImplementedError
self._do_test_set_admin_password_driver_error(exc,
vm_states.ACTIVE,
- None)
+ None,
+ expected_exception)
def test_inject_file(self):
# Ensure we can write a file to an instance.
diff --git a/nova/virt/xenapi/agent.py b/nova/virt/xenapi/agent.py
index ef08edbc1..e8a81f552 100644
--- a/nova/virt/xenapi/agent.py
+++ b/nova/virt/xenapi/agent.py
@@ -188,7 +188,7 @@ class XenAPIBasedAgent(object):
if resp['returncode'] != 'D0':
msg = _('Failed to exchange keys: %(resp)r') % locals()
LOG.error(msg, instance=self.instance)
- raise Exception(msg)
+ raise NotImplementedError(msg)
# Some old versions of the Windows agent have a trailing \\r\\n
# (ie CRLF escaped) for some reason. Strip that off.
@@ -208,7 +208,7 @@ class XenAPIBasedAgent(object):
if resp['returncode'] != '0':
msg = _('Failed to update password: %(resp)r') % locals()
LOG.error(msg, instance=self.instance)
- raise Exception(msg)
+ raise NotImplementedError(msg)
sshkey = self.instance.get('key_data')
if sshkey: