diff options
| author | Ed Leafe <ed@leafe.com> | 2010-12-21 14:17:29 -0600 |
|---|---|---|
| committer | Ed Leafe <ed@leafe.com> | 2010-12-21 14:17:29 -0600 |
| commit | 005a4e645f8e913c673c6ba07e7b0c8c54f33e1c (patch) | |
| tree | 4e99be775b9f3b5ed4a35a9061d10aec7f3e8958 | |
| parent | 086f2d87be3c56ac8dafaf4551096868d57454db (diff) | |
Refactored duplicate rpc.cast() calls in nova/compute/api.py. Cleaned up some formatting issues.
| -rw-r--r-- | nova/compute/api.py | 47 | ||||
| -rw-r--r-- | nova/compute/manager.py | 32 | ||||
| -rw-r--r-- | nova/tests/compute_unittest.py | 7 | ||||
| -rw-r--r-- | nova/virt/fake.py | 12 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 15 | ||||
| -rw-r--r-- | nova/virt/xenapi_conn.py | 59 |
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 |
