summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorEd Leafe <ed@leafe.com>2010-12-21 14:17:29 -0600
committerEd Leafe <ed@leafe.com>2010-12-21 14:17:29 -0600
commit005a4e645f8e913c673c6ba07e7b0c8c54f33e1c (patch)
tree4e99be775b9f3b5ed4a35a9061d10aec7f3e8958 /nova
parent086f2d87be3c56ac8dafaf4551096868d57454db (diff)
Refactored duplicate rpc.cast() calls in nova/compute/api.py. Cleaned up some formatting issues.
Diffstat (limited to 'nova')
-rw-r--r--nova/compute/api.py47
-rw-r--r--nova/compute/manager.py32
-rw-r--r--nova/tests/compute_unittest.py7
-rw-r--r--nova/virt/fake.py12
-rw-r--r--nova/virt/xenapi/vmops.py15
-rw-r--r--nova/virt/xenapi_conn.py59
6 files changed, 111 insertions, 61 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py
index c740814da..ae7c84bc5 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -206,8 +206,7 @@ class ComputeAPI(base.Base):
def delete_instance(self, context, instance_id):
logging.debug("Going to try and terminate %d" % instance_id)
try:
- instance = self.db.instance_get_by_internal_id(context,
- instance_id)
+ instance = self.get_instance(context, instance_id)
except exception.NotFound as e:
logging.warning("Instance %d was not found during terminate",
instance_id)
@@ -271,50 +270,38 @@ class ComputeAPI(base.Base):
def get_instance(self, context, instance_id):
return self.db.instance_get_by_internal_id(context, instance_id)
- def reboot(self, context, instance_id):
- """Reboot the given instance."""
- instance = self.db.instance_get_by_internal_id(context, instance_id)
+ def _cast_compute_message(method, context, instance_id):
+ """Generic handler for RPC calls."""
+ instance = self.get_instance(context, instance_id)
host = instance['host']
rpc.cast(context,
self.db.queue_get_for(context, FLAGS.compute_topic, host),
- {"method": "reboot_instance",
+ {"method": method,
"args": {"instance_id": instance['id']}})
+ def reboot(self, context, instance_id):
+ """Reboot the given instance."""
+ self._cast_compute_message("reboot_instance", context, instance_id)
+
def pause(self, context, instance_id):
"""Pause the given instance."""
- instance = self.db.instance_get_by_internal_id(context, instance_id)
- host = instance['host']
- rpc.cast(context,
- self.db.queue_get_for(context, FLAGS.compute_topic, host),
- {"method": "pause_instance",
- "args": {"instance_id": instance['id']}})
+ self._cast_compute_message("pause_instance", context, instance_id)
def unpause(self, context, instance_id):
"""Unpause the given instance."""
- instance = self.db.instance_get_by_internal_id(context, instance_id)
- host = instance['host']
- rpc.cast(context,
- self.db.queue_get_for(context, FLAGS.compute_topic, host),
- {"method": "unpause_instance",
- "args": {"instance_id": instance['id']}})
+ self._cast_compute_message("unpause_instance", context, instance_id)
def rescue(self, context, instance_id):
"""Rescue the given instance."""
- instance = self.db.instance_get_by_internal_id(context, instance_id)
- host = instance['host']
- rpc.cast(context,
- self.db.queue_get_for(context, FLAGS.compute_topic, host),
- {"method": "rescue_instance",
- "args": {"instance_id": instance['id']}})
+ self._cast_compute_message("rescue_instance", context, instance_id)
def unrescue(self, context, instance_id):
"""Unrescue the given instance."""
- instance = self.db.instance_get_by_internal_id(context, instance_id)
- host = instance['host']
- rpc.cast(context,
- self.db.queue_get_for(context, FLAGS.compute_topic, host),
- {"method": "unrescue_instance",
- "args": {"instance_id": instance['id']}})
+ self._cast_compute_message("unrescue_instance", context, instance_id)
+
+ def reset_root_password(self, context, instance_id):
+ """Reset the root/admin pw for the given instance."""
+ self._cast_compute_message("reset_root_password", context, instance_id)
def _get_network_topic(self, context):
"""Retrieves the network host for a project"""
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index a84af6bb9..cb64cd39d 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -156,6 +156,38 @@ class ComputeManager(manager.Manager):
self.driver.reboot(instance_ref)
self._update_state(context, instance_id)
+
+
+
+ # WORKING CODE
+ @exception.wrap_exception
+ def reset_root_password(self, context, instance_id):
+ """Reset the root/admin password for an instance on this server."""
+ context = context.elevated()
+ instance_ref = self.db.instance_get(context, instance_id)
+ self._update_state(context, instance_id)
+
+ if instance_ref['state'] != power_state.RUNNING:
+ logging.warn('trying to reset the password on a non-running '
+ 'instance: %s (state: %s excepted: %s)',
+ instance_ref['internal_id'],
+ instance_ref['state'],
+ power_state.RUNNING)
+
+ logging.debug('instance %s: resetting root password',
+ instance_ref['name'])
+ self.db.instance_set_state(context,
+ instance_id,
+ power_state.NOSTATE,
+ 'resetting_password')
+ #TODO: (dabo) not sure how we will implement this yet.
+ self.driver.reset_root_password(instance_ref)
+ self._update_state(context, instance_id)
+
+
+
+
+
@exception.wrap_exception
def rescue_instance(self, context, instance_id):
"""Rescue an instance on this server."""
diff --git a/nova/tests/compute_unittest.py b/nova/tests/compute_unittest.py
index 187ca31de..16e577c56 100644
--- a/nova/tests/compute_unittest.py
+++ b/nova/tests/compute_unittest.py
@@ -142,6 +142,13 @@ class ComputeTestCase(test.TestCase):
self.compute.reboot_instance(self.context, instance_id)
self.compute.terminate_instance(self.context, instance_id)
+ def test_reset_root_password(self):
+ """Ensure instance can have its root password reset"""
+ instance_id = self._create_instance()
+ self.compute.run_instance(self.context, instance_id)
+ self.compute.reset_root_password(self.context, instance_id)
+ self.compute.terminate_instance(self.context, instance_id)
+
def test_console_output(self):
"""Make sure we can get console output from instance"""
instance_id = self._create_instance()
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 55c6dcef9..ff3f61838 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -118,6 +118,18 @@ class FakeConnection(object):
"""
pass
+ def reset_root_password(self, instance):
+ """
+ Reset the root password on the specified instance.
+
+ The given parameter is an instance of nova.compute.service.Instance,
+ and so the instance is being specified as instance.name.
+
+ The work will be done asynchronously. This function returns a
+ Deferred that allows the caller to detect when it is complete.
+ """
+ pass
+
def rescue(self, instance):
"""
Rescue the specified instance.
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index a18eacf07..c5ae52add 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -34,7 +34,6 @@ class VMOps(object):
"""
Management class for VM-related tasks
"""
-
def __init__(self, session):
global XenAPI
if XenAPI is None:
@@ -45,8 +44,9 @@ class VMOps(object):
def list_instances(self):
""" List VM instances """
- return [self._session.get_xenapi().VM.get_name_label(vm) \
- for vm in self._session.get_xenapi().VM.get_all()]
+ xVM = self._session.get_xenapi().VM
+ return [xVM.get_name_label(vm)
+ for vm in xVM.get_all()]
def spawn(self, instance):
""" Create VM instance """
@@ -89,6 +89,15 @@ class VMOps(object):
task = self._session.call_xenapi('Async.VM.clean_reboot', vm)
self._session.wait_for_task(task)
+ def reset_root_password(self, instance):
+ """ Reset the root/admin password on the VM instance """
+ instance_name = instance.name
+ vm = VMHelper.lookup(self._session, instance_name)
+ if vm is None:
+ raise Exception('instance not present %s' % instance_name)
+ task = self._session.call_xenapi('Async.VM.reset_root_password', vm)
+ self._session.wait_for_task(task)
+
def destroy(self, instance):
""" Destroy VM instance """
vm = VMHelper.lookup(self._session, instance.name)
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 21ed2cd65..199c0b862 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -19,15 +19,15 @@ A connection to XenServer or Xen Cloud Platform.
The concurrency model for this class is as follows:
-All XenAPI calls are on a thread (using t.i.t.deferToThread, via the decorator
-deferredToThread). They are remote calls, and so may hang for the usual
-reasons. They should not be allowed to block the reactor thread.
+All XenAPI calls are on a green thread (using eventlet's "tpool"
+thread pool). They are remote calls, and so may hang for the usual
+reasons.
All long-running XenAPI calls (VM.start, VM.reboot, etc) are called async
-(using XenAPI.VM.async_start etc). These return a task, which can then be
-polled for completion. Polling is handled using reactor.callLater.
+(using XenAPI.VM.async_start etc). These return a task, which can then be
+polled for completion.
-This combination of techniques means that we don't block the reactor thread at
+This combination of techniques means that we don't block the main thread at
all, and at the same time we don't hold lots of threads waiting for
long-running operations.
@@ -75,7 +75,7 @@ flags.DEFINE_string('xenapi_connection_password',
flags.DEFINE_float('xenapi_task_poll_interval',
0.5,
'The interval used for polling of remote tasks '
- '(Async.VM.start, etc). Used only if '
+ '(Async.VM.start, etc). Used only if '
'connection_type=xenapi.')
XenAPI = None
@@ -101,7 +101,7 @@ def get_connection(_):
class XenAPIConnection(object):
- """ A connection to XenServer or Xen Cloud Platform """
+ """A connection to XenServer or Xen Cloud Platform"""
def __init__(self, url, user, pw):
session = XenAPISession(url, user, pw)
@@ -109,31 +109,35 @@ class XenAPIConnection(object):
self._volumeops = VolumeOps(session)
def list_instances(self):
- """ List VM instances """
+ """List VM instances"""
return self._vmops.list_instances()
def spawn(self, instance):
- """ Create VM instance """
+ """Create VM instance"""
self._vmops.spawn(instance)
def reboot(self, instance):
- """ Reboot VM instance """
+ """Reboot VM instance"""
self._vmops.reboot(instance)
+ def reset_root_password(self, instance):
+ """Reset the root/admin password on the VM instance"""
+ self._vmops.reset_root_password(instance)
+
def destroy(self, instance):
- """ Destroy VM instance """
+ """Destroy VM instance"""
self._vmops.destroy(instance)
def pause(self, instance, callback):
- """ Pause VM instance """
+ """Pause VM instance"""
self._vmops.pause(instance, callback)
def unpause(self, instance, callback):
- """ Unpause paused VM instance """
+ """Unpause paused VM instance"""
self._vmops.unpause(instance, callback)
def get_info(self, instance_id):
- """ Return data about VM instance """
+ """Return data about VM instance"""
return self._vmops.get_info(instance_id)
def get_diagnostics(self, instance_id):
@@ -141,33 +145,33 @@ class XenAPIConnection(object):
return self._vmops.get_diagnostics(instance_id)
def get_console_output(self, instance):
- """ Return snapshot of console """
+ """Return snapshot of console"""
return self._vmops.get_console_output(instance)
def attach_volume(self, instance_name, device_path, mountpoint):
- """ Attach volume storage to VM instance """
+ """Attach volume storage to VM instance"""
return self._volumeops.attach_volume(instance_name,
- device_path,
- mountpoint)
+ device_path,
+ mountpoint)
def detach_volume(self, instance_name, mountpoint):
- """ Detach volume storage to VM instance """
+ """Detach volume storage to VM instance"""
return self._volumeops.detach_volume(instance_name, mountpoint)
class XenAPISession(object):
- """ The session to invoke XenAPI SDK calls """
+ """The session to invoke XenAPI SDK calls"""
def __init__(self, url, user, pw):
self._session = XenAPI.Session(url)
self._session.login_with_password(user, pw)
def get_xenapi(self):
- """ Return the xenapi object """
+ """Return the xenapi object"""
return self._session.xenapi
def get_xenapi_host(self):
- """ Return the xenapi host """
+ """Return the xenapi host"""
return self._session.xenapi.session.get_this_host(self._session.handle)
def call_xenapi(self, method, *args):
@@ -184,9 +188,8 @@ class XenAPISession(object):
self.get_xenapi_host(), plugin, fn, args)
def wait_for_task(self, task):
- """Return a Deferred that will give the result of the given task.
+ """Return the result of the given task.
The task is polled until it completes."""
-
done = event.Event()
loop = utils.LoopingCall(self._poll_task, task, done)
loop.start(FLAGS.xenapi_task_poll_interval, now=True)
@@ -195,7 +198,7 @@ class XenAPISession(object):
return rv
def _poll_task(self, task, done):
- """Poll the given XenAPI task, and fire the given Deferred if we
+ """Poll the given XenAPI task, and fire the given action if we
get a result."""
try:
#logging.debug('Polling task %s...', task)
@@ -218,7 +221,7 @@ class XenAPISession(object):
def _unwrap_plugin_exceptions(func, *args, **kwargs):
- """ Parse exception details """
+ """Parse exception details"""
try:
return func(*args, **kwargs)
except XenAPI.Failure, exc:
@@ -240,7 +243,7 @@ def _unwrap_plugin_exceptions(func, *args, **kwargs):
def _parse_xmlrpc_value(val):
- """Parse the given value as if it were an XML-RPC value. This is
+ """Parse the given value as if it were an XML-RPC value. This is
sometimes used as the format for the task.result field."""
if not val:
return val