diff options
| author | Brian Elliott <brian.elliott@rackspace.com> | 2012-05-13 21:06:29 +0000 |
|---|---|---|
| committer | Brian Elliott <brian.elliott@rackspace.com> | 2012-05-24 16:53:40 +0000 |
| commit | bc0f2235d9b27e604b9264b5c19adce3cf306bc2 (patch) | |
| tree | f8c9b9aa9b9dbbceca9a4d5f58e52db0f98fd3cc /nova/compute | |
| parent | 9c9c4d78530a3a1e50dd5b7496ef54e51c4b48f5 (diff) | |
Added a instance state update notification
Added a instance update notification (compute.instance.update) that
will report on changes to vm_state and task_state. The goal here is
to provide useful insight into instance state transitions. (e.g.
BUILDING->ACTIVE)
The new notification has minimial dependencies and is intended for
wide use across the different layers/packages within nova. Calls
in compute api/manager, scheduler, and the virt layer that modify
the instance state have been instrumented with this notification.
Change-Id: I223eb7eccc8aa079b782f6bb17727cd0b71d18ed
Diffstat (limited to 'nova/compute')
| -rw-r--r-- | nova/compute/api.py | 23 | ||||
| -rw-r--r-- | nova/compute/manager.py | 8 | ||||
| -rw-r--r-- | nova/compute/utils.py | 94 |
3 files changed, 35 insertions, 90 deletions
diff --git a/nova/compute/api.py b/nova/compute/api.py index e83dfb3a6..3fd358a34 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -41,6 +41,7 @@ from nova import flags import nova.image from nova import log as logging from nova import network +from nova import notifications from nova.openstack.common import cfg from nova.openstack.common import excutils from nova.openstack.common import jsonutils @@ -599,6 +600,11 @@ class API(base.Base): instance_id = instance['id'] instance_uuid = instance['uuid'] + # send a state update notification for the initial create to + # show it going from non-existent to BUILDING + notifications.send_update_with_states(context, instance, None, + vm_states.BUILDING, None, None) + for security_group_id in security_groups: self.db.instance_add_security_group(elevated, instance_uuid, @@ -919,8 +925,14 @@ class API(base.Base): :returns: None """ - rv = self.db.instance_update(context, instance["id"], kwargs) - return dict(rv.iteritems()) + + # Update the instance record and send a state update notification + # if task or vm state changed + old_ref, instance_ref = self.db.instance_update_and_get_original( + context, instance["id"], kwargs) + notifications.send_update(context, old_ref, instance_ref) + + return dict(instance_ref.iteritems()) @wrap_check_policy @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.SHUTOFF, @@ -1260,9 +1272,16 @@ class API(base.Base): else: raise Exception(_('Image type not recognized %s') % image_type) + # change instance state and notify + old_vm_state = instance["vm_state"] + old_task_state = instance["task_state"] + self.db.instance_test_and_set( context, instance_uuid, 'task_state', [None], task_state) + notifications.send_update_with_states(context, instance, old_vm_state, + instance["vm_state"], old_task_state, instance["task_state"]) + properties = { 'instance_uuid': instance_uuid, 'user_id': str(context.user_id), diff --git a/nova/compute/manager.py b/nova/compute/manager.py index bd3cd02cc..6a0251a15 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -61,6 +61,7 @@ from nova import log as logging from nova import manager from nova import network from nova.network import model as network_model +from nova import notifications from nova.notifier import api as notifier from nova.openstack.common import cfg from nova.openstack.common import excutils @@ -253,7 +254,12 @@ class ComputeManager(manager.SchedulerDependentManager): def _instance_update(self, context, instance_id, **kwargs): """Update an instance in the database using kwargs as value.""" - return self.db.instance_update(context, instance_id, kwargs) + + (old_ref, instance_ref) = self.db.instance_update_and_get_original( + context, instance_id, kwargs) + notifications.send_update(context, old_ref, instance_ref) + + return instance_ref def _set_instance_error_state(self, context, instance_uuid): try: diff --git a/nova/compute/utils.py b/nova/compute/utils.py index 7a6ac8671..ab5ccfbf0 100644 --- a/nova/compute/utils.py +++ b/nova/compute/utils.py @@ -25,6 +25,7 @@ from nova import flags from nova import log from nova import network from nova.network import model as network_model +from nova import notifications from nova.notifier import api as notifier_api from nova import utils @@ -52,45 +53,10 @@ def notify_usage_exists(context, instance_ref, current_period=False, override in the notification if not None. """ - admin_context = nova.context.get_admin_context(read_deleted='yes') - begin, end = utils.last_completed_audit_period() - bw = {} - if current_period: - audit_start = end - audit_end = utils.utcnow() - else: - audit_start = begin - audit_end = end - - if (instance_ref.get('info_cache') and - instance_ref['info_cache'].get('network_info')): - - cached_info = instance_ref['info_cache']['network_info'] - nw_info = network_model.NetworkInfo.hydrate(cached_info) - else: - try: - nw_info = network.API().get_instance_nw_info(admin_context, - instance_ref) - except Exception: - LOG.exception('Failed to get nw_info', instance=instance_ref) - if ignore_missing_network_data: - return - raise - - macs = [vif['address'] for vif in nw_info] - uuids = [instance_ref.uuid] - - bw_usages = db.bw_usage_get_by_uuids(admin_context, uuids, audit_start) - bw_usages = [b for b in bw_usages if b.mac in macs] - - for b in bw_usages: - label = 'net-name-not-found-%s' % b['mac'] - for vif in nw_info: - if vif['address'] == b['mac']: - label = vif['network']['label'] - break + audit_start, audit_end = notifications.audit_period_bounds(current_period) - bw[label] = dict(bw_in=b.bw_in, bw_out=b.bw_out) + bw = notifications.bandwidth_usage(instance_ref, audit_start, + ignore_missing_network_data) if system_metadata is None: try: @@ -100,10 +66,7 @@ def notify_usage_exists(context, instance_ref, current_period=False, system_metadata = {} # add image metadata to the notification: - image_meta = {} - for md_key, md_value in system_metadata.iteritems(): - if md_key.startswith('image_'): - image_meta[md_key[6:]] = md_value + image_meta = notifications.image_meta(system_metadata) extra_info = dict(audit_period_beginning=str(audit_start), audit_period_ending=str(audit_end), @@ -231,49 +194,6 @@ def legacy_network_info(network_model): return network_info -def _usage_from_instance(context, instance_ref, network_info, - system_metadata, **kw): - """ - Get usage information for an instance which is common to all - notifications. - - :param network_info: network_info provided if not None - :param system_metadata: system_metadata DB entries for the instance, - if not None. *NOTE*: Currently unused here in trunk, but needed for - potential custom modifications. - """ - - def null_safe_str(s): - return str(s) if s else '' - - image_ref_url = utils.generate_image_url(instance_ref['image_ref']) - - usage_info = dict( - tenant_id=instance_ref['project_id'], - user_id=instance_ref['user_id'], - instance_id=instance_ref['uuid'], - instance_type=instance_ref['instance_type']['name'], - instance_type_id=instance_ref['instance_type_id'], - memory_mb=instance_ref['memory_mb'], - disk_gb=instance_ref['root_gb'] + instance_ref['ephemeral_gb'], - display_name=instance_ref['display_name'], - created_at=str(instance_ref['created_at']), - # Nova's deleted vs terminated instance terminology is confusing, - # this should be when the instance was deleted (i.e. terminated_at), - # not when the db record was deleted. (mdragon) - deleted_at=null_safe_str(instance_ref['terminated_at']), - launched_at=null_safe_str(instance_ref['launched_at']), - image_ref_url=image_ref_url, - state=instance_ref['vm_state'], - state_description=null_safe_str(instance_ref['task_state'])) - - if network_info is not None: - usage_info['fixed_ips'] = network_info.fixed_ips() - - usage_info.update(kw) - return usage_info - - def notify_about_instance_usage(context, instance, event_suffix, network_info=None, system_metadata=None, extra_usage_info=None, host=None): @@ -296,8 +216,8 @@ def notify_about_instance_usage(context, instance, event_suffix, if not extra_usage_info: extra_usage_info = {} - usage_info = _usage_from_instance(context, instance, network_info, - system_metadata, **extra_usage_info) + usage_info = notifications.usage_from_instance(context, instance, + network_info, system_metadata, **extra_usage_info) notifier_api.notify(context, 'compute.%s' % host, 'compute.instance.%s' % event_suffix, |
