Merge "Create links in LBaaS detail pages"

This commit is contained in:
Jenkins 2014-04-19 00:46:52 +00:00 committed by Gerrit Code Review
commit 6eea7b1203
11 changed files with 198 additions and 87 deletions

View File

@ -96,7 +96,15 @@ def vip_list(request, **kwargs):
def vip_get(request, vip_id):
return _vip_get(request, vip_id, expand_resource=True)
def _vip_get(request, vip_id, expand_resource=False):
vip = neutronclient(request).show_vip(vip_id).get('vip')
if expand_resource:
vip['subnet'] = neutron.subnet_get(request, vip['subnet_id'])
vip['port'] = neutron.port_get(request, vip['port_id'])
vip['pool'] = _pool_get(request, vip['pool_id'])
return Vip(vip)
@ -132,15 +140,18 @@ def pool_create(request, **kwargs):
return Pool(pool)
def _get_vip_name(request, pool, vip_dict):
def _get_vip(request, pool, vip_dict, expand_name_only=False):
if pool['vip_id'] is not None:
try:
if vip_dict:
return vip_dict.get(pool['vip_id']).name
vip = vip_dict.get(pool['vip_id'])
else:
return vip_get(request, pool['vip_id']).name
vip = _vip_get(request, pool['vip_id'])
except Exception:
return pool['vip_id']
vip = Vip({'id': pool['vip_id'], 'name': ''})
if expand_name_only:
vip = vip.name_or_id
return vip
else:
return None
@ -160,21 +171,25 @@ def _pool_list(request, expand_subnet=False, expand_vip=False, **kwargs):
vips = vip_list(request)
vip_dict = SortedDict((v.id, v) for v in vips)
for p in pools:
p['vip_name'] = _get_vip_name(request, p, vip_dict)
p['vip_name'] = _get_vip(request, p, vip_dict,
expand_name_only=True)
return [Pool(p) for p in pools]
def pool_get(request, pool_id):
return _pool_get(request, pool_id, expand_subnet=True, expand_vip=True)
return _pool_get(request, pool_id, expand_resource=True)
def _pool_get(request, pool_id, expand_subnet=False, expand_vip=False):
def _pool_get(request, pool_id, expand_resource=False):
pool = neutronclient(request).show_pool(pool_id).get('pool')
if expand_subnet:
pool['subnet_name'] = neutron.subnet_get(request,
pool['subnet_id']).cidr
if expand_vip:
pool['vip_name'] = _get_vip_name(request, pool, vip_dict=False)
if expand_resource:
pool['subnet'] = neutron.subnet_get(request, pool['subnet_id'])
pool['vip'] = _get_vip(request, pool, vip_dict=None,
expand_name_only=False)
pool['members'] = _member_list(request, expand_pool=False,
pool_id=pool_id)
pool['health_monitors'] = pool_health_monitor_list(
request, id=pool['health_monitors'])
return Pool(pool)
@ -230,9 +245,16 @@ def pool_health_monitor_list(request, **kwargs):
def pool_health_monitor_get(request, monitor_id):
return _pool_health_monitor_get(request, monitor_id, expand_resource=True)
def _pool_health_monitor_get(request, monitor_id, expand_resource=False):
monitor = neutronclient(request
).show_health_monitor(monitor_id
).get('health_monitor')
if expand_resource:
pool_ids = [p['pool_id'] for p in monitor['pools']]
monitor['pools'] = _pool_list(request, id=pool_ids)
return PoolMonitor(monitor)
@ -276,7 +298,7 @@ def _member_list(request, expand_pool, **kwargs):
pools = _pool_list(request)
pool_dict = SortedDict((p.id, p) for p in pools)
for m in members:
m['pool_name'] = pool_dict.get(m['pool_id']).name
m['pool_name'] = pool_dict.get(m['pool_id']).name_or_id
return [Member(m) for m in members]
@ -287,7 +309,7 @@ def member_get(request, member_id):
def _member_get(request, member_id, expand_pool):
member = neutronclient(request).show_member(member_id).get('member')
if expand_pool:
member['pool_name'] = _pool_get(request, member['pool_id']).name
member['pool'] = _pool_get(request, member['pool_id'])
return Member(member)

View File

@ -244,11 +244,24 @@ class MembersTable(tables.DataTable):
row_actions = (UpdateMemberLink, DeleteMemberLink)
def get_monitor_details(monitor):
if monitor.type in ('HTTP', 'HTTPS'):
return ("%(http_method)s %(url_path)s => %(codes)s" %
{'http_method': monitor.http_method,
'url_path': monitor.url_path,
'codes': monitor.expected_codes})
else:
return _("-")
class MonitorsTable(tables.DataTable):
id = tables.Column("id",
verbose_name=_("ID"),
link="horizon:project:loadbalancers:monitordetails")
monitorType = tables.Column('type', verbose_name=_("Monitor Type"))
monitor_type = tables.Column(
"type", verbose_name=_("Monitor Type"),
link="horizon:project:loadbalancers:monitordetails")
delay = tables.Column("delay", verbose_name=_("Delay"))
timeout = tables.Column("timeout", verbose_name=_("Timeout"))
max_retries = tables.Column("max_retries", verbose_name=_("Max Retries"))
details = tables.Column(get_monitor_details, verbose_name=_("Details"))
class Meta:
name = "monitorstable"

View File

@ -23,6 +23,7 @@ from horizon import tabs
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.loadbalancers import tables
from openstack_dashboard.dashboards.project.loadbalancers import utils
class PoolsTab(tabs.TableTab):
@ -102,6 +103,9 @@ class PoolDetailsTab(tabs.Tab):
pool = []
exceptions.handle(request,
_('Unable to retrieve pool details.'))
for monitor in pool.health_monitors:
display_name = utils.get_monitor_display_name(monitor)
setattr(monitor, 'display_name', display_name)
return {'pool': pool}

View File

@ -9,8 +9,9 @@
<dt>{% trans "Project ID" %}</dt>
<dd>{{ member.tenant_id }}</dd>
<dt>{% trans "Pool ID" %}</dt>
<dd>{{ member.pool_id }}</dd>
<dt>{% trans "Pool" %}</dt>
{% url 'horizon:project:loadbalancers:pooldetails' member.pool_id as pool_url %}
<dd><a href="{{pool_url}}">{{ member.pool.name_or_id }}</a></dd>
<dt>{% trans "Address" %}</dt>
<dd>{{ member.address }}</dd>

View File

@ -34,5 +34,15 @@
<dt>{% trans "Admin State Up" %}</dt>
<dd>{{ monitor.admin_state_up|yesno|capfirst }}</dd>
<dt>{% trans "Pools" %}</dt>
{% if monitor.pools %}
{% for pool in monitor.pools %}
{% url 'horizon:project:loadbalancers:pooldetails' pool.id as pool_url %}
<dd><a href="{{pool_url}}">{{ pool.name_or_id }}</a></dd>
{% endfor %}
{% else %}
<dd>{% trans "None" %}</dd>
{% endif %}
</dl>
</div>

View File

@ -15,14 +15,20 @@
<dt>{% trans "Project ID" %}</dt>
<dd>{{ pool.tenant_id }}</dd>
<dt>{% trans "VIP ID" %}</dt>
<dd>{{ pool.vip_id|default:_("-") }}</dd>
<dt>{% trans "VIP" %}</dt>
{% if pool.vip_id %}
{% url 'horizon:project:loadbalancers:vipdetails' pool.vip_id as vip_url %}
<dd><a href="{{vip_url}}">{{ pool.vip.name_or_id }}</a></dd>
{% else %}
<dd>{% trans "-" %}</dd>
{% endif %}
<dt>{% trans "Provider" %}</dt>
<dd>{{ pool.provider|default:_("N/A") }}</dd>
<dt>{% trans "Subnet ID" %}</dt>
<dd>{{ pool.subnet_id }}</dd>
<dt>{% trans "Subnet" %}</dt>
{% url 'horizon:project:networks:subnets:detail' pool.subnet_id as subnet_url %}
<dd><a href="{{subnet_url}}">{{ pool.subnet.name_or_id }} {{pool.subnet.cidr}}</a></dd>
<dt>{% trans "Protocol" %}</dt>
<dd>{{ pool.protocol }}</dd>
@ -31,10 +37,28 @@
<dd>{{ pool.lb_method }}</dd>
<dt>{% trans "Members" %}</dt>
<dd>{{ pool.members }}</dd>
<dd>
{% if pool.members %}
{% for member in pool.members %}
{% url 'horizon:project:loadbalancers:memberdetails' member.id as member_url %}
<a href="{{member_url}}">{{member.address}}:{{member.protocol_port}}</a><br>
{% endfor %}
{% else %}
<dd>{% trans "-" %}</dd>
{% endif %}
</dd>
<dt>{% trans "Health Monitors" %}</dt>
<dd>{{ pool.health_monitors }}</dd>
<dd>
{% if pool.health_monitors %}
{% for monitor in pool.health_monitors %}
{% url 'horizon:project:loadbalancers:monitordetails' monitor.id as monitor_url %}
<a href="{{monitor_url}}">{{ monitor.display_name }}</a><br>
{% endfor %}
{% else %}
<dd>{% trans "-" %}</dd>
{% endif %}
</dd>
<dt>{% trans "Admin State Up" %}</dt>
<dd>{{ pool.admin_state_up|yesno|capfirst }}</dd>

View File

@ -15,8 +15,9 @@
<dt>{% trans "Project ID" %}</dt>
<dd>{{ vip.tenant_id }}</dd>
<dt>{% trans "Subnet ID" %}</dt>
<dd>{{ vip.subnet_id }}</dd>
<dt>{% trans "Subnet" %}</dt>
{% url 'horizon:project:networks:subnets:detail' vip.subnet_id as subnet_url %}
<dd><a href="{{subnet_url}}">{{ vip.subnet.name_or_id }} {{ vip.subnet.cidr }}</a></dd>
<dt>{% trans "Address" %}</dt>
<dd>{{ vip.address }}</dd>
@ -27,11 +28,13 @@
<dt>{% trans "Protocol" %}</dt>
<dd>{{ vip.protocol }}</dd>
<dt>{% trans "Pool ID" %}</dt>
<dd>{{ vip.pool_id }}</dd>
<dt>{% trans "Pool" %}</dt>
{% url 'horizon:project:loadbalancers:pooldetails' vip.pool_id as pool_url %}
<dd><a href="{{pool_url}}">{{ vip.pool.name_or_id }}</a></dd>
<dt>{% trans "Port ID" %}</dt>
<dd>{{ vip.port_id }}</dd>
{% url 'horizon:project:networks:ports:detail' vip.port_id as port_url %}
<dd><a href="{{port_url}}">{{ vip.port_id }}</a></dd>
<dt>{% trans "Session Persistence" %}</dt>
{% if vip.session_persistence %}

View File

@ -0,0 +1,31 @@
# Copyright 2014, NEC Corporation
#
# 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.
from django.utils.translation import ugettext_lazy as _
def get_monitor_display_name(monitor):
fields = ['type', 'delay', 'max_retries', 'timeout']
if monitor.type in ['HTTP', 'HTTPS']:
fields.extend(['url_path', 'expected_codes', 'http_method'])
name = _("%(type)s: url:%(url_path)s "
"method:%(http_method)s codes:%(expected_codes)s "
"delay:%(delay)d retries:%(max_retries)d "
"timeout:%(timeout)d")
else:
name = _("%(type)s delay:%(delay)d "
"retries:%(max_retries)d "
"timeout:%(timeout)d")
params = dict((key, getattr(monitor, key)) for key in fields)
return name % params

View File

@ -22,6 +22,7 @@ from horizon.utils import validators
from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.loadbalancers import utils
AVAILABLE_PROTOCOLS = ('HTTP', 'HTTPS', 'TCP')
@ -536,25 +537,7 @@ class AddMonitor(workflows.Workflow):
return False
class MonitorMixin():
def _get_monitor_display_name(self, monitor):
fields = ['type', 'delay', 'max_retries', 'timeout']
if monitor.type in ['HTTP', 'HTTPS']:
fields.extend(['url_path', 'expected_codes', 'http_method'])
name = _("%(type)s url:%(url_path)s "
"method:%(http_method)s codes:%(expected_codes)s "
"delay:%(delay)d retries:%(max_retries)d "
"timeout:%(timeout)d")
else:
name = _("%(type)s delay:%(delay)d "
"retries:%(max_retries)d "
"timeout:%(timeout)d")
params = dict((key, getattr(monitor, key)) for key in fields)
return name % params
class AddPMAssociationAction(workflows.Action, MonitorMixin):
class AddPMAssociationAction(workflows.Action):
monitor_id = forms.ChoiceField(label=_("Monitor"))
def __init__(self, request, *args, **kwargs):
@ -571,7 +554,7 @@ class AddPMAssociationAction(workflows.Action, MonitorMixin):
tenant_id=tenant_id)
for m in monitors:
if m.id not in context['pool_monitors']:
display_name = self._get_monitor_display_name(m)
display_name = utils.get_monitor_display_name(m)
monitor_id_choices.append((m.id, display_name))
except Exception:
exceptions.handle(request,
@ -616,7 +599,7 @@ class AddPMAssociation(workflows.Workflow):
return False
class DeletePMAssociationAction(workflows.Action, MonitorMixin):
class DeletePMAssociationAction(workflows.Action):
monitor_id = forms.ChoiceField(label=_("Monitor"))
def __init__(self, request, *args, **kwargs):
@ -632,7 +615,7 @@ class DeletePMAssociationAction(workflows.Action, MonitorMixin):
monitors = api.lbaas.pool_health_monitor_list(request)
for m in monitors:
if m.id in context['pool_monitors']:
display_name = self._get_monitor_display_name(m)
display_name = utils.get_monitor_display_name(m)
monitor_id_choices.append((m.id, display_name))
except Exception:
exceptions.handle(request,

View File

@ -88,24 +88,27 @@ class LbaasApiTests(test.APITestCase):
self.assertIsInstance(v, api.lbaas.Vip)
self.assertTrue(v.id)
@test.create_stubs({neutronclient: ('show_vip',)})
@test.create_stubs({neutronclient: ('show_vip', 'show_pool'),
api.neutron: ('subnet_get', 'port_get')})
def test_vip_get(self):
vip = {'vip': {'id': 'abcdef-c3eb-4fee-9763-12de3338041e',
'address': '10.0.0.100',
'name': 'vip1name',
'description': 'vip1description',
'subnet_id': '12381d38-c3eb-4fee-9763-12de3338041e',
'protocol_port': '80',
'protocol': 'HTTP',
'pool_id': '8913dde8-4915-4b90-8d3e-b95eeedb0d49',
'connection_limit': '10',
'admin_state_up': True
}}
neutronclient.show_vip(vip['vip']['id']).AndReturn(vip)
vip = self.api_vips.first()
neutronclient.show_vip(vip['id']).AndReturn({'vip': vip})
api.neutron.subnet_get(self.request, vip['subnet_id']
).AndReturn(self.subnets.first())
api.neutron.port_get(self.request, vip['port_id']
).AndReturn(self.ports.first())
neutronclient.show_pool(vip['pool_id']
).AndReturn({'pool': self.api_pools.first()})
self.mox.ReplayAll()
ret_val = api.lbaas.vip_get(self.request, vip['vip']['id'])
ret_val = api.lbaas.vip_get(self.request, vip['id'])
self.assertIsInstance(ret_val, api.lbaas.Vip)
self.assertIsInstance(ret_val.subnet, api.neutron.Subnet)
self.assertEqual(vip['subnet_id'], ret_val.subnet.id)
self.assertIsInstance(ret_val.port, api.neutron.Port)
self.assertEqual(vip['port_id'], ret_val.port.id)
self.assertIsInstance(ret_val.pool, api.lbaas.Pool)
self.assertEqual(self.api_pools.first()['id'], ret_val.pool.id)
@test.create_stubs({neutronclient: ('update_vip',)})
def test_vip_update(self):
@ -181,7 +184,9 @@ class LbaasApiTests(test.APITestCase):
self.assertIsInstance(v, api.lbaas.Pool)
self.assertTrue(v.id)
@test.create_stubs({neutronclient: ('show_pool', 'show_vip'),
@test.create_stubs({neutronclient: ('show_pool', 'show_vip',
'list_members',
'list_health_monitors',),
api.neutron: ('subnet_get',)})
def test_pool_get(self):
pool = self.pools.first()
@ -192,10 +197,23 @@ class LbaasApiTests(test.APITestCase):
neutronclient.show_pool(pool.id).AndReturn(pool_dict)
api.neutron.subnet_get(self.request, subnet.id).AndReturn(subnet)
neutronclient.show_vip(pool.vip_id).AndReturn(vip_dict)
neutronclient.list_members(pool_id=pool.id).AndReturn(
{'members': self.members.list()})
neutronclient.list_health_monitors(id=pool.health_monitors).AndReturn(
{'health_monitors': [self.monitors.first()]})
self.mox.ReplayAll()
ret_val = api.lbaas.pool_get(self.request, pool.id)
self.assertIsInstance(ret_val, api.lbaas.Pool)
self.assertIsInstance(ret_val.vip, api.lbaas.Vip)
self.assertEqual(ret_val.vip.id, vip_dict['vip']['id'])
self.assertIsInstance(ret_val.subnet, api.neutron.Subnet)
self.assertEqual(ret_val.subnet.id, subnet.id)
self.assertEqual(2, len(ret_val.members))
self.assertIsInstance(ret_val.members[0], api.lbaas.Member)
self.assertEqual(1, len(ret_val.health_monitors))
self.assertIsInstance(ret_val.health_monitors[0],
api.lbaas.PoolMonitor)
@test.create_stubs({neutronclient: ('update_pool',)})
def test_pool_update(self):
@ -267,25 +285,21 @@ class LbaasApiTests(test.APITestCase):
self.assertIsInstance(v, api.lbaas.PoolMonitor)
self.assertTrue(v.id)
@test.create_stubs({neutronclient: ('show_health_monitor',)})
@test.create_stubs({neutronclient: ('show_health_monitor',
'list_pools')})
def test_pool_health_monitor_get(self):
monitor = {'health_monitor':
{'id': 'abcdef-c3eb-4fee-9763-12de3338041e',
'type': 'PING',
'delay': '10',
'timeout': '10',
'max_retries': '10',
'http_method': 'GET',
'url_path': '/monitor',
'expected_codes': '200',
'admin_state_up': True}}
monitor = self.api_monitors.first()
neutronclient.show_health_monitor(
monitor['health_monitor']['id']).AndReturn(monitor)
monitor['id']).AndReturn({'health_monitor': monitor})
neutronclient.list_pools(id=[p['pool_id'] for p in monitor['pools']]
).AndReturn({'pools': self.api_pools.list()})
self.mox.ReplayAll()
ret_val = api.lbaas.pool_health_monitor_get(
self.request, monitor['health_monitor']['id'])
self.request, monitor['id'])
self.assertIsInstance(ret_val, api.lbaas.PoolMonitor)
self.assertEqual(2, len(ret_val.pools))
self.assertIsInstance(ret_val.pools[0], api.lbaas.Pool)
@test.create_stubs({neutronclient: ('create_member', )})
def test_member_create(self):

View File

@ -438,6 +438,7 @@ def data(TEST):
'protocol': 'HTTP',
'lb_method': 'ROUND_ROBIN',
'health_monitors': ['d4a0500f-db2b-4cc4-afcf-ec026febff96'],
'members': ['78a46e5e-eb1a-418a-88c7-0e3f5968b08'],
'admin_state_up': True,
'status': 'ACTIVE',
'provider': 'haproxy'}
@ -454,6 +455,7 @@ def data(TEST):
'protocol': 'HTTPS',
'lb_method': 'ROUND_ROBIN',
'health_monitors': ['d4a0500f-db2b-4cc4-afcf-ec026febff97'],
'members': [],
'status': 'PENDING_CREATE',
'admin_state_up': True}
TEST.api_pools.add(pool_dict)
@ -467,6 +469,7 @@ def data(TEST):
'other_address': '10.0.0.100',
'description': 'vip description',
'subnet_id': TEST.subnets.first().id,
'port_id': TEST.ports.first().id,
'subnet': TEST.subnets.first().cidr,
'protocol_port': 80,
'protocol': pool_dict['protocol'],
@ -486,6 +489,7 @@ def data(TEST):
'other_address': '10.0.0.110',
'description': 'vip description',
'subnet_id': TEST.subnets.first().id,
'port_id': TEST.ports.list()[0].id,
'subnet': TEST.subnets.first().cidr,
'protocol_port': 80,
'protocol': pool_dict['protocol'],
@ -523,14 +527,17 @@ def data(TEST):
# 1st monitor
monitor_dict = {'id': 'd4a0500f-db2b-4cc4-afcf-ec026febff96',
'type': 'ping',
'type': 'http',
'delay': 10,
'timeout': 10,
'max_retries': 10,
'http_method': 'GET',
'url_path': '/',
'expected_codes': '200',
'admin_state_up': True}
'admin_state_up': True,
"pools": [{"pool_id": TEST.pools.list()[0].id},
{"pool_id": TEST.pools.list()[1].id}],
}
TEST.api_monitors.add(monitor_dict)
TEST.monitors.add(lbaas.PoolMonitor(monitor_dict))
@ -540,10 +547,9 @@ def data(TEST):
'delay': 10,
'timeout': 10,
'max_retries': 10,
'http_method': 'GET',
'url_path': '/',
'expected_codes': '200',
'admin_state_up': True}
'admin_state_up': True,
'pools': [],
}
TEST.api_monitors.add(monitor_dict)
TEST.monitors.add(lbaas.PoolMonitor(monitor_dict))