From 240419544fa1a5b147c1075cb1e5c2c51037bb1c Mon Sep 17 00:00:00 2001 From: Christian Berendt Date: Fri, 26 Jul 2013 09:18:24 +0200 Subject: [PATCH] added Network Agents to System Info panel Added a new tab to the System Info panel showing all Network Agents. fixes bug #1204375 Change-Id: I9c23105dde8528749275aba70065384dec354fb7 --- openstack_dashboard/api/neutron.py | 14 ++++++ .../dashboards/admin/info/tables.py | 47 +++++++++++++++++++ .../dashboards/admin/info/tabs.py | 27 ++++++++++- .../dashboards/admin/info/tests.py | 11 ++++- .../test/test_data/neutron_data.py | 41 ++++++++++++++++ 5 files changed, 138 insertions(+), 2 deletions(-) diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py index 2944acac58..8d30783974 100644 --- a/openstack_dashboard/api/neutron.py +++ b/openstack_dashboard/api/neutron.py @@ -54,6 +54,15 @@ class NeutronAPIDictWrapper(base.APIDictWrapper): return self._apidict.items() +class Agent(NeutronAPIDictWrapper): + """Wrapper for neutron agents""" + + def __init__(self, apiresource): + apiresource['admin_state'] = \ + 'UP' if apiresource['admin_state_up'] else 'DOWN' + super(Agent, self).__init__(apiresource) + + class Network(NeutronAPIDictWrapper): """Wrapper for neutron Networks""" @@ -627,6 +636,11 @@ def list_extensions(request): return {} +def agent_list(request): + agents = neutronclient(request).list_agents() + return [Agent(a) for a in agents['agents']] + + def is_extension_supported(request, extension_alias): extensions = list_extensions(request) diff --git a/openstack_dashboard/dashboards/admin/info/tables.py b/openstack_dashboard/dashboards/admin/info/tables.py index 1307177c48..81760d77de 100644 --- a/openstack_dashboard/dashboards/admin/info/tables.py +++ b/openstack_dashboard/dashboards/admin/info/tables.py @@ -149,3 +149,50 @@ class AggregatesTable(tables.DataTable): class Meta: name = "aggregates" verbose_name = _("Host Aggregates") + + +class NetworkAgentsFilterAction(tables.FilterAction): + def filter(self, table, agents, filter_string): + q = filter_string.lower() + + def comp(agent): + if q in agent.agent_type.lower(): + return True + return False + + return filter(comp, agents) + + +def get_network_agent_status(agent): + if agent.admin_state_up: + return 'enabled' + + return 'disabled' + + +def get_network_agent_state(agent): + if agent.alive: + return 'up' + + return 'down' + + +class NetworkAgentsTable(tables.DataTable): + agent_type = tables.Column('agent_type', verbose_name=_('Type')) + binary = tables.Column("binary", verbose_name=_('Name')) + host = tables.Column('host', verbose_name=_('Host')) + status = tables.Column(get_network_agent_status, verbose_name=_('Status')) + state = tables.Column(get_network_agent_state, verbose_name=_('State')) + heartbeat_timestamp = tables.Column('heartbeat_timestamp', + verbose_name=_('Updated At'), + filters=(utils_filters.parse_isotime, + filters.timesince)) + + def get_object_id(self, obj): + return "%s-%s" % (obj.binary, obj.host) + + class Meta: + name = "network_agents" + verbose_name = _("Network Agents") + table_actions = (NetworkAgentsFilterAction,) + multi_select = False diff --git a/openstack_dashboard/dashboards/admin/info/tabs.py b/openstack_dashboard/dashboards/admin/info/tabs.py index 37a4afce77..5ebf257d04 100644 --- a/openstack_dashboard/dashboards/admin/info/tabs.py +++ b/openstack_dashboard/dashboards/admin/info/tabs.py @@ -19,7 +19,9 @@ from django.utils.translation import ugettext_lazy as _ # noqa from horizon import exceptions from horizon import tabs +from openstack_dashboard.api import base from openstack_dashboard.api import keystone +from openstack_dashboard.api import neutron from openstack_dashboard.api import nova from openstack_dashboard.dashboards.admin.info import tables @@ -92,7 +94,30 @@ class NovaServicesTab(tabs.TableTab): return services +class NetworkAgentsTab(tabs.TableTab): + table_classes = (tables.NetworkAgentsTable,) + name = _("Network Agents") + slug = "network_agents" + template_name = ("horizon/common/_detail_table.html") + + def allowed(self, request): + return base.is_service_enabled(request, 'network') + + def get_network_agents_data(self): + try: + agents = neutron.agent_list(self.tab_group.request) + except Exception: + agents = [] + msg = _('Unable to get network agents list.') + exceptions.check_message(["Connection", "refused"], msg) + raise + + return agents + + class SystemInfoTabs(tabs.TabGroup): slug = "system_info" - tabs = (ServicesTab, NovaServicesTab, ZonesTab, HostAggregatesTab) + tabs = (ServicesTab, NovaServicesTab, + ZonesTab, HostAggregatesTab, + NetworkAgentsTab) sticky = True diff --git a/openstack_dashboard/dashboards/admin/info/tests.py b/openstack_dashboard/dashboards/admin/info/tests.py index b3eaaf3ca8..46cc43b64d 100644 --- a/openstack_dashboard/dashboards/admin/info/tests.py +++ b/openstack_dashboard/dashboards/admin/info/tests.py @@ -28,7 +28,8 @@ class SystemInfoViewTests(test.BaseAdminViewTests): @test.create_stubs({api.nova: ('service_list', 'availability_zone_list', - 'aggregate_list')}) + 'aggregate_list'), + api.neutron: ('agent_list',)}) def test_index(self): services = self.services.list() api.nova.service_list(IsA(http.HttpRequest)).AndReturn(services) @@ -36,6 +37,8 @@ class SystemInfoViewTests(test.BaseAdminViewTests): .AndReturn(self.availability_zones.list()) api.nova.aggregate_list(IsA(http.HttpRequest)) \ .AndReturn(self.aggregates.list()) + agents = self.agents.list() + api.neutron.agent_list(IsA(http.HttpRequest)).AndReturn(agents) self.mox.ReplayAll() @@ -63,3 +66,9 @@ class SystemInfoViewTests(test.BaseAdminViewTests): aggregates_tab = res.context['tab_group'].get_tab('aggregates') self.assertQuerysetEqual(aggregates_tab._tables['aggregates'].data, ['', '']) + + network_agents_tab = res.context['tab_group'].get_tab('network_agents') + self.assertQuerysetEqual( + network_agents_tab._tables['network_agents'].data, + [agent.__repr__() for agent in self.agents.list()] + ) diff --git a/openstack_dashboard/test/test_data/neutron_data.py b/openstack_dashboard/test/test_data/neutron_data.py index f2fa2728bd..2d6ad6caf4 100644 --- a/openstack_dashboard/test/test_data/neutron_data.py +++ b/openstack_dashboard/test/test_data/neutron_data.py @@ -24,6 +24,7 @@ from openstack_dashboard.test.test_data import utils def data(TEST): # data returned by openstack_dashboard.api.neutron wrapper + TEST.agents = utils.TestDataContainer() TEST.networks = utils.TestDataContainer() TEST.subnets = utils.TestDataContainer() TEST.ports = utils.TestDataContainer() @@ -38,6 +39,7 @@ def data(TEST): TEST.neutron_quotas = utils.TestDataContainer() # data return by neutronclient + TEST.api_agents = utils.TestDataContainer() TEST.api_networks = utils.TestDataContainer() TEST.api_subnets = utils.TestDataContainer() TEST.api_ports = utils.TestDataContainer() @@ -473,3 +475,42 @@ def data(TEST): extensions = {} extensions['extensions'] = [extension_1, extension_2] TEST.api_extensions.add(extensions) + + #------------------------------------------------------------ + # 1st agent + agent_dict = {"binary": "neutron-openvswitch-agent", + "description": None, + "admin_state_up": True, + "heartbeat_timestamp": "2013-07-26 06:51:47", + "alive": True, + "id": "c876ff05-f440-443e-808c-1d34cda3e88a", + "topic": "N/A", + "host": "devstack001", + "agent_type": "Open vSwitch agent", + "started_at": "2013-07-26 05:23:28", + "created_at": "2013-07-26 05:23:28", + "configurations": {"devices": 2}} + TEST.api_agents.add(agent_dict) + TEST.agents.add(neutron.Agent(agent_dict)) + + # 2nd agent + agent_dict = {"binary": "neutron-dhcp-agent", + "description": None, + "admin_state_up": True, + "heartbeat_timestamp": "2013-07-26 06:51:48", + "alive": True, + "id": "f0d12e3d-1973-41a2-b977-b95693f9a8aa", + "topic": "dhcp_agent", + "host": "devstack001", + "agent_type": "DHCP agent", + "started_at": "2013-07-26 05:23:30", + "created_at": "2013-07-26 05:23:30", + "configurations": { + "subnets": 1, + "use_namespaces": True, + "dhcp_lease_duration": 120, + "dhcp_driver": "neutron.agent.linux.dhcp.Dnsmasq", + "networks": 1, + "ports": 1}} + TEST.api_agents.add(agent_dict) + TEST.agents.add(neutron.Agent(agent_dict))