31
32
FLAGS = flags.FLAGS
34
def notify_usage_exists(instance_ref, current_period=False):
35
""" Generates 'exists' notification for an instance for usage auditing
38
Generates usage for last completed period, unless 'current_period'
40
admin_context = context.get_admin_context(read_deleted='yes')
41
begin, end = utils.current_audit_period()
33
LOG = log.getLogger(__name__)
36
def notify_usage_exists(context, instance_ref, current_period=False,
37
ignore_missing_network_data=True,
38
system_metadata=None, extra_usage_info=None):
39
"""Generates 'exists' notification for an instance for usage auditing
42
:param current_period: if True, this will generate a usage for the
43
current usage period; if False, this will generate a usage for the
44
previous audit period.
46
:param ignore_missing_network_data: if True, log any exceptions generated
47
while getting network info; if False, raise the exception.
48
:param system_metadata: system_metadata DB entries for the instance,
49
if not None. *NOTE*: Currently unused here in trunk, but needed for
50
potential custom modifications.
51
:param extra_usage_info: Dictionary containing extra values to add or
52
override in the notification if not None.
55
admin_context = nova.context.get_admin_context(read_deleted='yes')
56
begin, end = utils.last_completed_audit_period()
53
68
cached_info = instance_ref['info_cache']['network_info']
54
69
nw_info = network_model.NetworkInfo.hydrate(cached_info)
56
nw_info = network.API().get_instance_nw_info(admin_context,
72
nw_info = network.API().get_instance_nw_info(admin_context,
75
LOG.exception('Failed to get nw_info', instance=instance_ref)
76
if ignore_missing_network_data:
59
80
macs = [vif['address'] for vif in nw_info]
60
for b in db.bw_usage_get_by_macs(admin_context,
81
uuids = [instance_ref.uuid]
83
bw_usages = db.bw_usage_get_by_uuids(admin_context, uuids, audit_start)
84
bw_usages = [b for b in bw_usages if b.mac in macs]
63
87
label = 'net-name-not-found-%s' % b['mac']
64
88
for vif in nw_info:
65
89
if vif['address'] == b['mac']:
69
93
bw[label] = dict(bw_in=b.bw_in, bw_out=b.bw_out)
70
usage_info = utils.usage_from_instance(instance_ref,
71
audit_period_beginning=str(audit_start),
72
audit_period_ending=str(audit_end),
74
notifier_api.notify('compute.%s' % FLAGS.host,
75
'compute.instance.exists',
95
if system_metadata is None:
97
system_metadata = db.instance_system_metadata_get(
98
context, instance_ref.uuid)
99
except exception.NotFound:
102
# add image metadata to the notification:
104
for md_key, md_value in system_metadata.iteritems():
105
if md_key.startswith('image_'):
106
image_meta[md_key[6:]] = md_value
108
extra_info = dict(audit_period_beginning=str(audit_start),
109
audit_period_ending=str(audit_end),
110
bandwidth=bw, image_meta=image_meta)
113
extra_info.update(extra_usage_info)
115
notify_about_instance_usage(context, instance_ref, 'exists',
116
system_metadata=system_metadata, extra_usage_info=extra_info)
80
119
def legacy_network_info(network_model):
191
230
network_info.append((network_dict, info_dict))
192
231
return network_info
234
def _usage_from_instance(context, instance_ref, network_info,
235
system_metadata, **kw):
237
Get usage information for an instance which is common to all
240
:param network_info: network_info provided if not None
241
:param system_metadata: system_metadata DB entries for the instance,
242
if not None. *NOTE*: Currently unused here in trunk, but needed for
243
potential custom modifications.
246
def null_safe_str(s):
247
return str(s) if s else ''
249
image_ref_url = utils.generate_image_url(instance_ref['image_ref'])
252
tenant_id=instance_ref['project_id'],
253
user_id=instance_ref['user_id'],
254
instance_id=instance_ref['uuid'],
255
instance_type=instance_ref['instance_type']['name'],
256
instance_type_id=instance_ref['instance_type_id'],
257
memory_mb=instance_ref['memory_mb'],
258
disk_gb=instance_ref['root_gb'] + instance_ref['ephemeral_gb'],
259
display_name=instance_ref['display_name'],
260
created_at=str(instance_ref['created_at']),
261
# Nova's deleted vs terminated instance terminology is confusing,
262
# this should be when the instance was deleted (i.e. terminated_at),
263
# not when the db record was deleted. (mdragon)
264
deleted_at=null_safe_str(instance_ref['terminated_at']),
265
launched_at=null_safe_str(instance_ref['launched_at']),
266
image_ref_url=image_ref_url,
267
state=instance_ref['vm_state'],
268
state_description=null_safe_str(instance_ref['task_state']))
270
if network_info is not None:
271
usage_info['fixed_ips'] = network_info.fixed_ips()
273
usage_info.update(kw)
277
def notify_about_instance_usage(context, instance, event_suffix,
278
network_info=None, system_metadata=None,
279
extra_usage_info=None, host=None):
281
Send a notification about an instance.
283
:param event_suffix: Event type like "delete.start" or "exists"
284
:param network_info: Networking information, if provided.
285
:param system_metadata: system_metadata DB entries for the instance,
287
:param extra_usage_info: Dictionary containing extra values to add or
288
override in the notification.
289
:param host: Compute host for the instance, if specified. Default is
296
if not extra_usage_info:
297
extra_usage_info = {}
299
usage_info = _usage_from_instance(context, instance, network_info,
300
system_metadata, **extra_usage_info)
302
notifier_api.notify(context, 'compute.%s' % host,
303
'compute.instance.%s' % event_suffix,
304
notifier_api.INFO, usage_info)