From bcdedbf1aa7f4904d09e08da28a00fdb0be6d4ea Mon Sep 17 00:00:00 2001 From: Guillaume Thouvenin Date: Fri, 11 Mar 2016 15:23:13 +0100 Subject: [PATCH] Use OpenStack API to collect the status of Neutron agents This change uses the Neutron API to get the status of the Neutron agents instead of querying the MySQL database. Change-Id: I60fa2386a887e9dac2fe4f1234d225ad6402bf2d Partial-Bug: #1546188 --- .../puppet/manifests/controller.pp | 10 ------ .../files/collectd/collectd_openstack.py | 36 +++++++++++++------ .../files/collectd/openstack_neutron.py | 36 +++++++++++++++++-- .../files/plugins/decoders/collectd.lua | 33 +++++------------ 4 files changed, 68 insertions(+), 47 deletions(-) diff --git a/deployment_scripts/puppet/manifests/controller.pp b/deployment_scripts/puppet/manifests/controller.pp index e5ffe2fa5..0b60b7783 100644 --- a/deployment_scripts/puppet/manifests/controller.pp +++ b/deployment_scripts/puppet/manifests/controller.pp @@ -364,16 +364,6 @@ if $influxdb_mode != 'disabled' { password => $nova['db_password'], } - unless $contrail { - lma_collector::collectd::dbi_services { 'neutron': - username => 'neutron', - dbname => 'neutron', - password => $neutron['database']['passwd'], - report_interval => 15, - downtime_factor => 4, - } - } - class { 'lma_collector::collectd::haproxy': socket => $haproxy_socket, # Ignore internal stats ('Stats' for 6.1, 'stats' for 7.0) and lma proxies diff --git a/deployment_scripts/puppet/modules/lma_collector/files/collectd/collectd_openstack.py b/deployment_scripts/puppet/modules/lma_collector/files/collectd/collectd_openstack.py index 2c2327730..6dd33955d 100644 --- a/deployment_scripts/puppet/modules/lma_collector/files/collectd/collectd_openstack.py +++ b/deployment_scripts/puppet/modules/lma_collector/files/collectd/collectd_openstack.py @@ -191,26 +191,40 @@ class CollectdPlugin(base.Base): where 'state' can be 'up', 'down' or 'disabled' """ - ost_services_r = self.get(service, 'os-services') + + if service == 'neutron': + endpoint = 'v2.0/agents' + entry = 'agents' + else: + endpoint = 'os-services' + entry = 'services' + + ost_services_r = self.get(service, endpoint) r_status = ost_services_r.status_code try: r_json = ost_services_r.json() except ValueError: r_json = {} - if r_status == 200 and 'services' in r_json: - for val in r_json['services']: + if r_status == 200 and entry in r_json: + for val in r_json[entry]: data = {'host': val['host'], 'service': val['binary']} - if val['status'] == 'disabled': - data['state'] = 'disabled' - elif val['state'] == 'up' or val['state'] == 'down': - data['state'] = val['state'] + if service == 'neutron': + if not val['admin_state_up']: + data['state'] = 'disabled' + else: + data['state'] = 'up' if val['alive'] else 'down' else: - msg = "Unknown state for {} workers:{}".format( - service, val['state']) - self.logger.warning(msg) - continue + if val['status'] == 'disabled': + data['state'] = 'disabled' + elif val['state'] == 'up' or val['state'] == 'down': + data['state'] = val['state'] + else: + msg = "Unknown state for {} workers:{}".format( + service, val['state']) + self.logger.warning(msg) + continue yield data else: diff --git a/deployment_scripts/puppet/modules/lma_collector/files/collectd/openstack_neutron.py b/deployment_scripts/puppet/modules/lma_collector/files/collectd/openstack_neutron.py index e7905e103..e1882d51b 100644 --- a/deployment_scripts/puppet/modules/lma_collector/files/collectd/openstack_neutron.py +++ b/deployment_scripts/puppet/modules/lma_collector/files/collectd/openstack_neutron.py @@ -15,6 +15,9 @@ # # Collectd plugin for getting resource statistics from Neutron import collectd +from collections import Counter +from collections import defaultdict +import re import base import collectd_openstack as openstack @@ -26,6 +29,7 @@ INTERVAL = openstack.INTERVAL class NeutronStatsPlugin(openstack.CollectdPlugin): """ Class to report the statistics on Neutron service. + state of agents number of networks broken down by status number of subnets number of ports broken down by owner and status @@ -33,8 +37,13 @@ class NeutronStatsPlugin(openstack.CollectdPlugin): number of floating IP addresses broken down by free/associated """ + neutron_re = re.compile('^neutron-') + agent_re = re.compile('-agent$') + states = {'up': 0, 'down': 1, 'disabled': 2} + @base.read_callback_wrapper def read_callback(self): + def groupby_network(x): return "networks.%s" % x.get('status', 'unknown').lower() @@ -60,6 +69,29 @@ class NeutronStatsPlugin(openstack.CollectdPlugin): status = 'free' return "floatingips.%s" % status + # Get information of the state per agent + # State can be up or down + aggregated_agents = defaultdict(Counter) + + for agent in self.iter_workers('neutron'): + host = agent['host'].split('.')[0] + service = self.agent_re.sub( + '', self.neutron_re.sub('', agent['service'])) + state = agent['state'] + + aggregated_agents[service][state] += 1 + self.dispatch_value('neutron_agent', + self.states[state], + {'host': host, + 'service': service, + 'state': state}) + + for service in aggregated_agents: + for state in self.states: + self.dispatch_value('neutron_agents', + aggregated_agents[service][state], + {'service': service, 'state': state}) + # Networks networks = self.get_objects('neutron', 'networks', api_version='v2.0') status = self.count_objects_group_by(networks, @@ -97,14 +129,14 @@ class NeutronStatsPlugin(openstack.CollectdPlugin): self.dispatch_value(s, nb) self.dispatch_value('floatingips', len(floatingips)) - def dispatch_value(self, name, value): + def dispatch_value(self, name, value, meta=None): v = collectd.Values( plugin=PLUGIN_NAME, # metric source type='gauge', type_instance=name, interval=INTERVAL, # w/a for https://github.com/collectd/collectd/issues/716 - meta={'0': True}, + meta=meta or {'0': True}, values=[value] ) v.dispatch() diff --git a/deployment_scripts/puppet/modules/lma_collector/files/plugins/decoders/collectd.lua b/deployment_scripts/puppet/modules/lma_collector/files/plugins/decoders/collectd.lua index 428c5109e..b6f50a670 100644 --- a/deployment_scripts/puppet/modules/lma_collector/files/plugins/decoders/collectd.lua +++ b/deployment_scripts/puppet/modules/lma_collector/files/plugins/decoders/collectd.lua @@ -39,19 +39,6 @@ function replace_dot_by_sep (str) return string.gsub(str, '%.', sep) end -function split_service_and_state_and_hostname(str) - -- Possible values: - -- services.compute.down.node-1.test.domain.local - -- services.scheduler.up - -- agents.dhcp.down.node-44 - -- agents.dhcp.up - -- services.scheduler.disabled.rbd:volumes - local service, state, hostname = string.match(str, '^%w+%.([%w-]+)%.([%w-]+)%.?(.-)$') - -- remove domain part of the hostname or nil if string is empty - hostname = string.match(hostname, '^([^.]+)') - return replace_dot_by_sep(service), state, hostname -end - function process_message () local ok, samples = pcall(cjson.decode, read_message("Payload")) if not ok then @@ -266,6 +253,15 @@ function process_message () skip_it = true elseif sample['type_instance'] == 'subnets' then msg['Fields']['name'] = 'openstack' .. sep .. 'neutron' .. sep .. 'subnets' + elseif sample['type_instance'] == 'neutron_agents' or + sample['type_instance'] == 'neutron_agent' then + msg['Fields']['name'] = 'openstack_' .. sample['type_instance'] + msg['Fields']['tag_fields'] = { 'service', 'state' } + msg['Fields']['service'] = sample['meta']['service'] + msg['Fields']['state'] = sample['meta']['state'] + if sample['type_instance'] == 'neutron_agent' then + msg['Fields']['hostname'] = sample['meta']['host'] + end elseif string.match(sample['type_instance'], '^ports') then local resource, owner, state = string.match(sample['type_instance'], '^([^.]+)%.([^.]+)%.(.+)$') msg['Fields']['name'] = 'openstack' .. sep .. 'neutron' .. sep .. replace_dot_by_sep(resource) @@ -331,17 +327,6 @@ function process_message () msg['Fields'][additional_tag] = sample['type_instance'] end end - elseif metric_source == 'dbi' and sample['plugin_instance'] == 'agents_neutron' then - local service, state, hostname = split_service_and_state_and_hostname(sample['type_instance']) - if hostname then - msg['Fields']['name'] = 'openstack' .. sep .. 'neutron' .. sep .. 'agent' - msg['Fields']['hostname'] = hostname - else - msg['Fields']['name'] = 'openstack' .. sep .. 'neutron' .. sep .. 'agents' - end - msg['Fields']['tag_fields'] = { 'service', 'state' } - msg['Fields']['service'] = service - msg['Fields']['state'] = state elseif metric_source == 'pacemaker_resource' then msg['Fields']['name'] = 'pacemaker_local_resource_active' msg['Fields']['tag_fields'] = { 'resource' }