192 lines
5.9 KiB
Lua
192 lines
5.9 KiB
Lua
-- Copyright 2015 Mirantis, Inc.
|
|
--
|
|
-- Licensed under the Apache License, Version 2.0 (the "License");
|
|
-- you may not use this file except in compliance with the License.
|
|
-- You may obtain a copy of the License at
|
|
--
|
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
--
|
|
-- Unless required by applicable law or agreed to in writing, software
|
|
-- distributed under the License is distributed on an "AS IS" BASIS,
|
|
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
-- See the License for the specific language governing permissions and
|
|
-- limitations under the License.
|
|
require "string"
|
|
require "cjson"
|
|
|
|
local patt = require 'patterns'
|
|
local utils = require 'lma_utils'
|
|
|
|
-- Mapping table from event_type prefixes to notification loggers
|
|
local logger_map = {
|
|
--cinder
|
|
volume = 'cinder',
|
|
snapshot = 'cinder',
|
|
-- glance
|
|
image = 'glance',
|
|
-- heat
|
|
orchestration = 'heat',
|
|
-- keystone
|
|
identity = 'keystone',
|
|
-- nova
|
|
compute = 'nova',
|
|
compute_task = 'nova',
|
|
scheduler = 'nova',
|
|
keypair = 'nova',
|
|
-- neutron
|
|
floatingip = 'neutron',
|
|
security_group = 'neutron',
|
|
security_group_rule = 'neutron',
|
|
network = 'neutron',
|
|
port = 'neutron',
|
|
router = 'neutron',
|
|
subnet = 'neutron',
|
|
-- sahara
|
|
sahara = 'sahara',
|
|
}
|
|
|
|
-- Mapping table between the attributes in the notification's payload and the
|
|
-- fields in the Heka message
|
|
local payload_fields = {
|
|
-- all
|
|
tenant_id = 'tenant_id',
|
|
user_id = 'user_id',
|
|
display_name = 'display_name',
|
|
-- nova
|
|
vcpus = 'vcpus',
|
|
availability_zone = 'availability_zone',
|
|
instance_id = 'instance_id',
|
|
instance_type = 'instance_type',
|
|
image_name = 'image_name',
|
|
memory_mb = 'memory_mb',
|
|
disk_gb = 'disk_gb',
|
|
state = 'state',
|
|
old_state = 'old_state',
|
|
old_task_state = 'old_task_state',
|
|
new_task_state = 'new_task_state',
|
|
created_at = 'created_at',
|
|
launched_at = 'launched_at',
|
|
deleted_at = 'deleted_at',
|
|
terminated_at = 'terminated_at',
|
|
-- neutron
|
|
network_id = 'network_id',
|
|
subnet_id = 'subnet_id',
|
|
port_id = 'port_id',
|
|
-- cinder
|
|
volume_id = 'volume_id',
|
|
size = 'size',
|
|
status = 'state',
|
|
replication_status = 'replication_status',
|
|
}
|
|
|
|
function normalize_uuid(uuid)
|
|
return patt.Uuid:match(uuid)
|
|
end
|
|
|
|
-- Mapping table defining transformation functions to be applied, keys are the
|
|
-- attributes in the notification's payload and values are Lua functions
|
|
local transform_functions = {
|
|
created_at = utils.format_datetime,
|
|
launched_at = utils.format_datetime,
|
|
deleted_at = utils.format_datetime,
|
|
terminated_at = utils.format_datetime,
|
|
user_id = normalize_uuid,
|
|
tenant_id = normalize_uuid,
|
|
instance_id = normalize_uuid,
|
|
network_id = normalize_uuid,
|
|
subnet_id = normalize_uuid,
|
|
port_id = normalize_uuid,
|
|
volume_id = normalize_uuid,
|
|
}
|
|
|
|
local include_full_notification = read_config("include_full_notification") or false
|
|
|
|
function process_cadf_event(notif, msg)
|
|
local cadf_event = notif.payload
|
|
|
|
msg.Type = 'audit'
|
|
msg.Logger = notif.publisher_id
|
|
msg.Severity = utils.label_to_severity_map[notif.priority]
|
|
msg.Timestamp = patt.Timestamp:match(cadf_event.eventTime)
|
|
|
|
msg.Fields.action = cadf_event.action
|
|
-- notif.event_type can be 'http.request' or 'http.response'
|
|
msg.Fields.notification_type = notif.event_type
|
|
-- cadf_event.eventType can be 'activity', 'monitor', ...
|
|
msg.Fields.event_type = cadf_event.eventType
|
|
msg.Fields.outcome = cadf_event.outcome
|
|
msg.Fields.severity_label = notif.priority
|
|
end
|
|
|
|
function process_notification(notif, msg)
|
|
local openstack_notif = notif.payload
|
|
|
|
msg.Type = 'notification'
|
|
msg.Logger = logger_map[string.match(notif.event_type, '([^.]+)')]
|
|
msg.Severity = utils.label_to_severity_map[notif.priority]
|
|
msg.Timestamp = patt.Timestamp:match(notif.timestamp)
|
|
|
|
msg.Fields.publisher, msg.Hostname = string.match(notif.publisher_id, '([^.]+)%.([%w_-]+)')
|
|
if openstack_notif.host ~= nil then
|
|
msg.Hostname = string.match(openstack_notif.host, '([%w_-]+)')
|
|
end
|
|
|
|
msg.Fields.event_type = notif.event_type
|
|
msg.Fields.severity_label = notif.priority
|
|
msg.Fields.hostname = msg.Hostname
|
|
|
|
for k, v in pairs(payload_fields) do
|
|
local val = openstack_notif[k]
|
|
if val ~= nil then
|
|
local name = payload_fields[k] or k
|
|
local transform = transform_functions[k]
|
|
if transform ~= nil then
|
|
msg.Fields[name] = transform(val)
|
|
else
|
|
msg.Fields[name] = val
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function process_message()
|
|
local msg = {Fields={}}
|
|
local data = read_message("Payload")
|
|
local ok, notif = pcall(cjson.decode, data)
|
|
if not ok then
|
|
return -1, string.format("Failed to parse notification: %s: '%s'", notif, string.sub(data or 'N/A', 1, 64))
|
|
end
|
|
|
|
local oslo_version = notif['oslo.version']
|
|
if oslo_version then
|
|
-- messagingv2 notifications
|
|
ok, notif = pcall(cjson.decode, notif['oslo.message'])
|
|
if not ok then
|
|
return -1, string.format("Failed to parse v%s notification: %s: '%s'", oslo_version, notif, string.sub(data or 'N/A', 1, 64))
|
|
end
|
|
end
|
|
|
|
if include_full_notification then
|
|
msg.Payload = data
|
|
else
|
|
msg.Payload = utils.safe_json_encode(notif.payload) or '{}'
|
|
end
|
|
|
|
local ok, error_msg
|
|
if notif.payload.eventType and notif.payload.eventTime then
|
|
-- Payload of CADF event notifications always contain at least
|
|
-- eventType and eventTime fields
|
|
-- http://docs.openstack.org/developer/pycadf/specification/events.html
|
|
ok, error_msg = pcall(process_cadf_event, notif, msg)
|
|
else
|
|
ok, error_msg = pcall(process_notification, notif, msg)
|
|
end
|
|
|
|
if not ok then
|
|
return -1, error_msg
|
|
end
|
|
|
|
utils.inject_tags(msg)
|
|
return utils.safe_inject_message(msg)
|
|
end
|