Convert octavia-dashboard to use Octavia v2 API

This patch coverts the Octavia dasboard over to use the openstack SDK
and the new Octavia v2 API.

It's octavia-dashboard, now with less neutron-lbaas (ok, no neutron-lbaas)

Change-Id: I71fd67128210c3ff365838414920a1de1883ebd2
This commit is contained in:
Michael Johnson 2017-08-31 17:19:51 -07:00 committed by Jacky Hu
parent ec394cd7d9
commit d49b14ac01
21 changed files with 252 additions and 477 deletions

View File

@ -17,9 +17,12 @@
from six.moves import _thread as thread from six.moves import _thread as thread
from time import sleep from time import sleep
from django.conf import settings
from django.views import generic from django.views import generic
from horizon import conf from horizon import conf
from openstack import connection
from openstack import profile
from openstack_dashboard.api import neutron from openstack_dashboard.api import neutron
from openstack_dashboard.api.rest import urls from openstack_dashboard.api.rest import urls
@ -28,6 +31,54 @@ from openstack_dashboard.api.rest import utils as rest_utils
neutronclient = neutron.neutronclient neutronclient = neutron.neutronclient
def _get_sdk_connection(request):
"""Creates an SDK connection based on the request.
:param request: Django request object
:returns: SDK connection object
"""
prof = profile.Profile()
prof.set_region(profile.Profile.ALL, request.user.services_region)
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
return connection.Connection(profile=prof,
verify=insecure,
cert=cacert,
user_agent='octavia-dashboard',
auth_plugin='token',
project_id=request.user.project_id,
default_domain_id=request.user.domain_id,
token=request.user.token.unscoped_token,
auth_url=request.user.endpoint)
def _sdk_object_to_list(object):
"""Converts an SDK generator object to a list of dictionaries.
:param object: SDK generator object
:returns: List of dictionaries
"""
result_list = []
for item in object:
result_list.append(_get_sdk_object_dict(item))
return result_list
def _get_sdk_object_dict(object):
"""Converts an SDK object to a dictionary.
Fixes any SDK imposed object oddities.
:param object: SDK object
:returns: Dictionary
"""
item_dict = object.to_dict()
if 'is_admin_state_up' in item_dict:
item_dict['admin_state_up'] = item_dict['is_admin_state_up']
return item_dict
def poll_loadbalancer_status(request, loadbalancer_id, callback, def poll_loadbalancer_status(request, loadbalancer_id, callback,
from_state='PENDING_UPDATE', to_state='ACTIVE', from_state='PENDING_UPDATE', to_state='ACTIVE',
callback_kwargs=None): callback_kwargs=None):
@ -47,9 +98,9 @@ def poll_loadbalancer_status(request, loadbalancer_id, callback,
status = from_state status = from_state
while status == from_state: while status == from_state:
sleep(interval) sleep(interval)
lb = neutronclient(request).show_loadbalancer( conn = _get_sdk_connection(request)
loadbalancer_id).get('loadbalancer') lb = conn.load_balancer.get_load_balancer(loadbalancer_id)
status = lb['provisioning_status'] status = lb.provisioning_status
if status == to_state: if status == to_state:
kwargs = {'loadbalancer_id': loadbalancer_id} kwargs = {'loadbalancer_id': loadbalancer_id}
@ -60,27 +111,26 @@ def poll_loadbalancer_status(request, loadbalancer_id, callback,
def create_loadbalancer(request): def create_loadbalancer(request):
data = request.DATA data = request.DATA
spec = {
'vip_subnet_id': data['loadbalancer']['subnet'] conn = _get_sdk_connection(request)
} loadbalancer = conn.load_balancer.create_load_balancer(
if data['loadbalancer'].get('name'): project_id=request.user.project_id,
spec['name'] = data['loadbalancer']['name'] vip_subnet_id=data['loadbalancer']['subnet'],
if data['loadbalancer'].get('description'): name=data['loadbalancer'].get('name'),
spec['description'] = data['loadbalancer']['description'] description=data['loadbalancer'].get('description'),
if data['loadbalancer'].get('ip'): vip_address=data['loadbalancer'].get('ip'))
spec['vip_address'] = data['loadbalancer']['ip']
loadbalancer = neutronclient(request).create_loadbalancer(
{'loadbalancer': spec}).get('loadbalancer')
if data.get('listener'): if data.get('listener'):
# There is work underway to add a new API to LBaaS v2 that will # There is work underway to add a new API to LBaaS v2 that will
# allow us to pass in all information at once. Until that is # allow us to pass in all information at once. Until that is
# available we use a separate thread to poll for the load # available we use a separate thread to poll for the load
# balancer status and create the other resources when it becomes # balancer status and create the other resources when it becomes
# active. # active.
args = (request, loadbalancer['id'], create_listener) args = (request, loadbalancer.id, create_listener)
kwargs = {'from_state': 'PENDING_CREATE'} kwargs = {'from_state': 'PENDING_CREATE'}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs) thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
return loadbalancer
return _get_sdk_object_dict(loadbalancer)
def create_listener(request, **kwargs): def create_listener(request, **kwargs):
@ -88,28 +138,30 @@ def create_listener(request, **kwargs):
""" """
data = request.DATA data = request.DATA
listenerSpec = {
'protocol': data['listener']['protocol'],
'protocol_port': data['listener']['port'],
'loadbalancer_id': kwargs['loadbalancer_id']
}
if data['listener'].get('name'):
listenerSpec['name'] = data['listener']['name']
if data['listener'].get('description'):
listenerSpec['description'] = data['listener']['description']
if data.get('certificates'):
listenerSpec['default_tls_container_ref'] = data['certificates'][0]
listenerSpec['sni_container_refs'] = data['certificates']
listener = neutronclient(request).create_listener( try:
{'listener': listenerSpec}).get('listener') default_tls_ref = data['certificates'][0]
except (KeyError, IndexError):
default_tls_ref = None
conn = _get_sdk_connection(request)
# TODO(johnsom) Add SNI support
# https://bugs.launchpad.net/octavia/+bug/1714294
listener = conn.load_balancer.create_listener(
protocol=data['listener']['protocol'],
protocol_port=data['listener']['port'],
load_balancer_id=kwargs['loadbalancer_id'],
name=data['listener'].get('name'),
description=data['listener'].get('description'),
default_tls_container_ref=default_tls_ref,
sni_container_refs=None)
if data.get('pool'): if data.get('pool'):
args = (request, kwargs['loadbalancer_id'], create_pool) args = (request, kwargs['loadbalancer_id'], create_pool)
kwargs = {'callback_kwargs': {'listener_id': listener['id']}} kwargs = {'callback_kwargs': {'listener_id': listener.id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs) thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
return listener return _get_sdk_object_dict(listener)
def create_pool(request, **kwargs): def create_pool(request, **kwargs):
@ -117,29 +169,26 @@ def create_pool(request, **kwargs):
""" """
data = request.DATA data = request.DATA
poolSpec = {
'protocol': data['pool']['protocol'], conn = _get_sdk_connection(request)
'lb_algorithm': data['pool']['method'], pool = conn.load_balancer.create_pool(
'listener_id': kwargs['listener_id'] protocol=data['pool']['protocol'],
} lb_algorithm=data['pool']['method'],
if data['pool'].get('name'): listener_id=kwargs['listener_id'],
poolSpec['name'] = data['pool']['name'] name=data['pool'].get('name'),
if data['pool'].get('description'): description=data['pool'].get('description'))
poolSpec['description'] = data['pool']['description']
pool = neutronclient(request).create_lbaas_pool(
{'pool': poolSpec}).get('pool')
if data.get('members'): if data.get('members'):
args = (request, kwargs['loadbalancer_id'], add_member) args = (request, kwargs['loadbalancer_id'], add_member)
kwargs = {'callback_kwargs': {'pool_id': pool['id'], kwargs = {'callback_kwargs': {'pool_id': pool.id,
'index': 0}} 'index': 0}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs) thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
elif data.get('monitor'): elif data.get('monitor'):
args = (request, kwargs['loadbalancer_id'], create_health_monitor) args = (request, kwargs['loadbalancer_id'], create_health_monitor)
kwargs = {'callback_kwargs': {'pool_id': pool['id']}} kwargs = {'callback_kwargs': {'pool_id': pool.id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs) thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
return pool return _get_sdk_object_dict(pool)
def create_health_monitor(request, **kwargs): def create_health_monitor(request, **kwargs):
@ -147,21 +196,19 @@ def create_health_monitor(request, **kwargs):
""" """
data = request.DATA data = request.DATA
monitorSpec = {
'type': data['monitor']['type'], conn = _get_sdk_connection(request)
'delay': data['monitor']['interval'], health_mon = conn.load_balancer.create_health_monitor(
'timeout': data['monitor']['timeout'], type=data['monitor']['type'],
'max_retries': data['monitor']['retry'], delay=data['monitor']['interval'],
'pool_id': kwargs['pool_id'] timeout=data['monitor']['timeout'],
} max_retries=data['monitor']['retry'],
if data['monitor'].get('method'): pool_id=kwargs['pool_id'],
monitorSpec['http_method'] = data['monitor']['method'] http_method=data['monitor'].get('method'),
if data['monitor'].get('path'): url_path=data['monitor'].get('path'),
monitorSpec['url_path'] = data['monitor']['path'] expected_codes=data['monitor'].get('status'))
if data['monitor'].get('status'):
monitorSpec['expected_codes'] = data['monitor']['status'] return _get_sdk_object_dict(health_mon)
return neutronclient(request).create_lbaas_healthmonitor(
{'healthmonitor': monitorSpec}).get('healthmonitor')
def add_member(request, **kwargs): def add_member(request, **kwargs):
@ -182,16 +229,14 @@ def add_member(request, **kwargs):
loadbalancer_id = kwargs.get('loadbalancer_id') loadbalancer_id = kwargs.get('loadbalancer_id')
member = members[index] member = members[index]
memberSpec = {
'address': member['address'],
'protocol_port': member['port'],
'subnet_id': member['subnet']
}
if member.get('weight'):
memberSpec['weight'] = member['weight']
member = neutronclient(request).create_lbaas_member( conn = _get_sdk_connection(request)
pool_id, {'member': memberSpec}).get('member') member = conn.load_balancer.create_member(
pool_id,
address=member['address'],
protocol_port=member['port'],
subnet_id=member['subnet'],
weight=member.get('weight'))
index += 1 index += 1
if kwargs.get('members_to_add'): if kwargs.get('members_to_add'):
@ -214,7 +259,7 @@ def add_member(request, **kwargs):
kwargs = {'callback_kwargs': {'pool_id': pool_id}} kwargs = {'callback_kwargs': {'pool_id': pool_id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs) thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
return member return _get_sdk_object_dict(member)
def remove_member(request, **kwargs): def remove_member(request, **kwargs):
@ -229,7 +274,9 @@ def remove_member(request, **kwargs):
members_to_delete = kwargs['members_to_delete'] members_to_delete = kwargs['members_to_delete']
member_id = members_to_delete.pop(0) member_id = members_to_delete.pop(0)
neutronclient(request).delete_lbaas_member(member_id, pool_id) conn = _get_sdk_connection(request)
conn.load_balancer.delete_member(member_id, pool_id,
ignore_missing=True)
args = (request, loadbalancer_id, update_member_list) args = (request, loadbalancer_id, update_member_list)
kwargs = {'callback_kwargs': { kwargs = {'callback_kwargs': {
@ -244,15 +291,15 @@ def update_loadbalancer(request, **kwargs):
""" """
data = request.DATA data = request.DATA
spec = {}
loadbalancer_id = kwargs.get('loadbalancer_id') loadbalancer_id = kwargs.get('loadbalancer_id')
if data['loadbalancer'].get('name'): conn = _get_sdk_connection(request)
spec['name'] = data['loadbalancer']['name'] loadbalancer = conn.load_balancer.update_load_balancer(
if data['loadbalancer'].get('description'): loadbalancer_id,
spec['description'] = data['loadbalancer']['description'] name=data['loadbalancer'].get('name'),
return neutronclient(request).update_loadbalancer( description=data['loadbalancer'].get('description'))
loadbalancer_id, {'loadbalancer': spec}).get('loadbalancer')
return _get_sdk_object_dict(loadbalancer)
def update_listener(request, **kwargs): def update_listener(request, **kwargs):
@ -260,23 +307,20 @@ def update_listener(request, **kwargs):
""" """
data = request.DATA data = request.DATA
listener_spec = {}
listener_id = data['listener'].get('id') listener_id = data['listener'].get('id')
loadbalancer_id = data.get('loadbalancer_id') loadbalancer_id = data.get('loadbalancer_id')
if data['listener'].get('name'): conn = _get_sdk_connection(request)
listener_spec['name'] = data['listener']['name'] listener = conn.load_balancer.update_listener(
if data['listener'].get('description'): listener=listener_id,
listener_spec['description'] = data['listener']['description'] name=data['listener'].get('name'),
description=data['listener'].get('description'))
listener = neutronclient(request).update_listener(
listener_id, {'listener': listener_spec}).get('listener')
if data.get('pool'): if data.get('pool'):
args = (request, loadbalancer_id, update_pool) args = (request, loadbalancer_id, update_pool)
thread.start_new_thread(poll_loadbalancer_status, args) thread.start_new_thread(poll_loadbalancer_status, args)
return listener return _get_sdk_object_dict(listener)
def update_pool(request, **kwargs): def update_pool(request, **kwargs):
@ -284,23 +328,20 @@ def update_pool(request, **kwargs):
""" """
data = request.DATA data = request.DATA
pool_spec = {}
pool_id = data['pool'].get('id') pool_id = data['pool'].get('id')
loadbalancer_id = data.get('loadbalancer_id') loadbalancer_id = data.get('loadbalancer_id')
if data['pool'].get('name'): conn = _get_sdk_connection(request)
pool_spec['name'] = data['pool']['name'] pool = conn.load_balancer.update_pool(
if data['pool'].get('description'): pool=pool_id,
pool_spec['description'] = data['pool']['description'] name=data['pool'].get('name'),
description=data['pool'].get('description'))
pools = neutronclient(request).update_lbaas_pool(
pool_id, {'pool': pool_spec}).get('pools')
# Assemble the lists of member id's to add and remove, if any exist # Assemble the lists of member id's to add and remove, if any exist
tenant_id = request.user.project_id
request_member_data = data.get('members', []) request_member_data = data.get('members', [])
existing_members = neutronclient(request).list_lbaas_members(
pool_id, tenant_id=tenant_id).get('members') existing_members = _sdk_object_to_list(conn.load_balancer.members(pool_id))
(members_to_add, members_to_delete) = get_members_to_add_remove( (members_to_add, members_to_delete) = get_members_to_add_remove(
request_member_data, existing_members) request_member_data, existing_members)
@ -315,7 +356,7 @@ def update_pool(request, **kwargs):
args = (request, loadbalancer_id, update_monitor) args = (request, loadbalancer_id, update_monitor)
thread.start_new_thread(poll_loadbalancer_status, args) thread.start_new_thread(poll_loadbalancer_status, args)
return pools return _get_sdk_object_dict(pool)
def update_monitor(request, **kwargs): def update_monitor(request, **kwargs):
@ -323,26 +364,19 @@ def update_monitor(request, **kwargs):
""" """
data = request.DATA data = request.DATA
monitor_spec = {}
monitor_id = data['monitor']['id'] monitor_id = data['monitor']['id']
if data['monitor'].get('interval'): conn = _get_sdk_connection(request)
monitor_spec['delay'] = data['monitor']['interval'] healthmonitor = conn.load_balancer.update_health_monitor(
if data['monitor'].get('timeout'): monitor_id,
monitor_spec['timeout'] = data['monitor']['timeout'] delay=data['monitor'].get('interval'),
if data['monitor'].get('retry'): timeout=data['monitor'].get('timeout'),
monitor_spec['max_retries'] = data['monitor']['retry'] max_retries=data['monitor'].get('timeout'),
if data['monitor'].get('method'): http_method=data['monitor'].get('method'),
monitor_spec['http_method'] = data['monitor']['method'] url_path=data['monitor'].get('path'),
if data['monitor'].get('path'): expected_codes=data['monitor'].get('status'))
monitor_spec['url_path'] = data['monitor']['path']
if data['monitor'].get('status'):
monitor_spec['expected_codes'] = data['monitor']['status']
healthmonitor = neutronclient(request).update_lbaas_healthmonitor( return _get_sdk_object_dict(healthmonitor)
monitor_id, {'healthmonitor': monitor_spec}).get('healthmonitor')
return healthmonitor
def update_member_list(request, **kwargs): def update_member_list(request, **kwargs):
@ -411,12 +445,12 @@ class LoadBalancers(generic.View):
The listing result is an object with property "items". The listing result is an object with property "items".
""" """
tenant_id = request.user.project_id conn = _get_sdk_connection(request)
loadbalancers = neutronclient(request).list_loadbalancers( lb_list = _sdk_object_to_list(conn.load_balancer.load_balancers(
tenant_id=tenant_id).get('loadbalancers') project_id=request.user.project_id))
if request.GET.get('full') and neutron.floating_ip_supported(request): if request.GET.get('full') and neutron.floating_ip_supported(request):
add_floating_ip_info(request, loadbalancers) add_floating_ip_info(request, lb_list)
return {'items': loadbalancers} return {'items': lb_list}
@rest_utils.ajax() @rest_utils.ajax()
def post(self, request): def post(self, request):
@ -428,23 +462,6 @@ class LoadBalancers(generic.View):
return create_loadbalancer(request) return create_loadbalancer(request)
@urls.register
class LoadBalancerStatusTree(generic.View):
"""API for retrieving the resource status tree for a single load balancer.
"""
url_regex = r'lbaas/loadbalancers/(?P<loadbalancer_id>[^/]+)/statuses/$'
@rest_utils.ajax()
def get(self, request, loadbalancer_id):
"""Get the status tree for a specific load balancer.
http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915/statuses
"""
return neutronclient(request).retrieve_loadbalancer_status(
loadbalancer_id)
@urls.register @urls.register
class LoadBalancer(generic.View): class LoadBalancer(generic.View):
"""API for retrieving, updating, and deleting a single load balancer. """API for retrieving, updating, and deleting a single load balancer.
@ -458,11 +475,12 @@ class LoadBalancer(generic.View):
http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915 http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915
""" """
loadbalancer = neutronclient(request).show_loadbalancer( conn = _get_sdk_connection(request)
loadbalancer_id).get('loadbalancer') loadbalancer = conn.load_balancer.find_load_balancer(loadbalancer_id)
loadbalancer_dict = _get_sdk_object_dict(loadbalancer)
if request.GET.get('full') and neutron.floating_ip_supported(request): if request.GET.get('full') and neutron.floating_ip_supported(request):
add_floating_ip_info(request, [loadbalancer]) add_floating_ip_info(request, [loadbalancer_dict])
return loadbalancer return loadbalancer_dict
@rest_utils.ajax() @rest_utils.ajax()
def put(self, request, loadbalancer_id): def put(self, request, loadbalancer_id):
@ -478,7 +496,9 @@ class LoadBalancer(generic.View):
http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915 http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915
""" """
neutronclient(request).delete_loadbalancer(loadbalancer_id) conn = _get_sdk_connection(request)
conn.load_balancer.delete_load_balancer(loadbalancer_id,
ignore_missing=True)
@urls.register @urls.register
@ -495,9 +515,10 @@ class Listeners(generic.View):
The listing result is an object with property "items". The listing result is an object with property "items".
""" """
loadbalancer_id = request.GET.get('loadbalancerId') loadbalancer_id = request.GET.get('loadbalancerId')
tenant_id = request.user.project_id conn = _get_sdk_connection(request)
result = neutronclient(request).list_listeners(tenant_id=tenant_id) listener_list = _sdk_object_to_list(conn.load_balancer.listeners(
listener_list = result.get('listeners') project_id=request.user.project_id))
if loadbalancer_id: if loadbalancer_id:
listener_list = self._filter_listeners(listener_list, listener_list = self._filter_listeners(listener_list,
loadbalancer_id) loadbalancer_id)
@ -517,7 +538,7 @@ class Listeners(generic.View):
filtered_listeners = [] filtered_listeners = []
for listener in listener_list: for listener in listener_list:
if listener['loadbalancers'][0]['id'] == loadbalancer_id: if listener['load_balancers'][0]['id'] == loadbalancer_id:
filtered_listeners.append(listener) filtered_listeners.append(listener)
return filtered_listeners return filtered_listeners
@ -540,8 +561,9 @@ class Listener(generic.View):
http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915 http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915
""" """
listener = neutronclient(request).show_listener( conn = _get_sdk_connection(request)
listener_id).get('listener') listener = conn.load_balancer.find_listener(listener_id)
listener = _get_sdk_object_dict(listener)
if request.GET.get('includeChildResources'): if request.GET.get('includeChildResources'):
resources = {} resources = {}
@ -549,20 +571,20 @@ class Listener(generic.View):
if listener.get('default_pool_id'): if listener.get('default_pool_id'):
pool_id = listener['default_pool_id'] pool_id = listener['default_pool_id']
pool = neutronclient(request).show_lbaas_pool( pool = conn.load_balancer.find_pool(pool_id)
pool_id).get('pool') pool = _get_sdk_object_dict(pool)
resources['pool'] = pool resources['pool'] = pool
if pool.get('members'): if pool.get('members'):
tenant_id = request.user.project_id member_list = _sdk_object_to_list(
members = neutronclient(request).list_lbaas_members( conn.load_balancer.members(pool_id))
pool_id, tenant_id=tenant_id).get('members') resources['members'] = member_list
resources['members'] = members
if pool.get('healthmonitor_id'): if pool.get('healt_hmonitor_id'):
monitor_id = pool['healthmonitor_id'] monitor_id = pool['health_monitor_id']
monitor = neutronclient(request).show_lbaas_healthmonitor( monitor = conn.load_balancer.find_health_monitor(
monitor_id).get('healthmonitor') monitor_id)
monitor = _get_sdk_object_dict(monitor)
resources['monitor'] = monitor resources['monitor'] = monitor
return resources return resources
@ -583,7 +605,8 @@ class Listener(generic.View):
http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915 http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915
""" """
neutronclient(request).delete_listener(listener_id) conn = _get_sdk_connection(request)
conn.load_balancer.delete_listener(listener_id, ignore_missing=True)
@urls.register @urls.register
@ -622,22 +645,24 @@ class Pool(generic.View):
http://localhost/api/lbaas/pools/cc758c90-3d98-4ea1-af44-aab405c9c915 http://localhost/api/lbaas/pools/cc758c90-3d98-4ea1-af44-aab405c9c915
""" """
pool = neutronclient(request).show_lbaas_pool(pool_id).get('pool') conn = _get_sdk_connection(request)
pool = conn.load_balancer.find_pool(pool_id)
pool = _get_sdk_object_dict(pool)
if request.GET.get('includeChildResources'): if request.GET.get('includeChildResources'):
resources = {} resources = {}
resources['pool'] = pool resources['pool'] = pool
if pool.get('members'): if pool.get('members'):
tenant_id = request.user.project_id member_list = _sdk_object_to_list(
members = neutronclient(request).list_lbaas_members( conn.load_balancer.members(pool_id))
pool_id, tenant_id=tenant_id).get('members') resources['members'] = member_list
resources['members'] = members
if pool.get('healthmonitor_id'): if pool.get('health_monitor_id'):
monitor_id = pool['healthmonitor_id'] monitor_id = pool['health_monitor_id']
monitor = neutronclient(request).show_lbaas_healthmonitor( monitor = conn.load_balancer.find_health_monitor(
monitor_id).get('healthmonitor') monitor_id)
monitor = _get_sdk_object_dict(monitor)
resources['monitor'] = monitor resources['monitor'] = monitor
return resources return resources
@ -658,7 +683,8 @@ class Pool(generic.View):
http://localhost/api/lbaas/pools/cc758c90-3d98-4ea1-af44-aab405c9c915 http://localhost/api/lbaas/pools/cc758c90-3d98-4ea1-af44-aab405c9c915
""" """
neutronclient(request).delete_lbaas_pool(pool_id) conn = _get_sdk_connection(request)
conn.load_balancer.delete_pool(pool_id)
@urls.register @urls.register
@ -674,10 +700,9 @@ class Members(generic.View):
The listing result is an object with property "items". The listing result is an object with property "items".
""" """
tenant_id = request.user.project_id conn = _get_sdk_connection(request)
result = neutronclient(request).list_lbaas_members(pool_id, members_list = _sdk_object_to_list(conn.load_balancer.members(pool_id))
tenant_id=tenant_id) return {'items': members_list}
return {'items': result.get('members')}
@rest_utils.ajax() @rest_utils.ajax()
def put(self, request, pool_id): def put(self, request, pool_id):
@ -685,10 +710,12 @@ class Members(generic.View):
""" """
# Assemble the lists of member id's to add and remove, if any exist # Assemble the lists of member id's to add and remove, if any exist
tenant_id = request.user.project_id
request_member_data = request.DATA.get('members', []) request_member_data = request.DATA.get('members', [])
existing_members = neutronclient(request).list_lbaas_members(
pool_id, tenant_id=tenant_id).get('members') conn = _get_sdk_connection(request)
existing_members = _sdk_object_to_list(
conn.load_balancer.members(pool_id))
(members_to_add, members_to_delete) = get_members_to_add_remove( (members_to_add, members_to_delete) = get_members_to_add_remove(
request_member_data, existing_members) request_member_data, existing_members)
@ -713,8 +740,9 @@ class Member(generic.View):
"""Get a specific member belonging to a specific pool. """Get a specific member belonging to a specific pool.
""" """
return neutronclient(request).show_lbaas_member( conn = _get_sdk_connection(request)
member_id, pool_id).get('member') member = conn.load_balancer.find_member(member_id, pool_id)
return _get_sdk_object_dict(member)
@rest_utils.ajax() @rest_utils.ajax()
def put(self, request, member_id, pool_id): def put(self, request, member_id, pool_id):
@ -722,11 +750,10 @@ class Member(generic.View):
""" """
data = request.DATA data = request.DATA
spec = { conn = _get_sdk_connection(request)
'weight': data['weight'] member = conn.load_balancer.update_member(
} member_id, pool_id, weight=data['weight'])
return neutronclient(request).update_lbaas_member( return _get_sdk_object_dict(member)
member_id, pool_id, {'member': spec})
@urls.register @urls.register
@ -751,26 +778,29 @@ class HealthMonitor(generic.View):
"""API for retrieving a single health monitor. """API for retrieving a single health monitor.
""" """
url_regex = r'lbaas/healthmonitors/(?P<healthmonitor_id>[^/]+)/$' url_regex = r'lbaas/healthmonitors/(?P<health_monitor_id>[^/]+)/$'
@rest_utils.ajax() @rest_utils.ajax()
def get(self, request, healthmonitor_id): def get(self, request, health_monitor_id):
"""Get a specific health monitor. """Get a specific health monitor.
""" """
return neutronclient(request).show_lbaas_healthmonitor( conn = _get_sdk_connection(request)
healthmonitor_id).get('healthmonitor') health_mon = conn.load_balancer.find_health_monitor(health_monitor_id)
return _get_sdk_object_dict(health_mon)
@rest_utils.ajax() @rest_utils.ajax()
def delete(self, request, healthmonitor_id): def delete(self, request, health_monitor_id):
"""Delete a specific health monitor. """Delete a specific health monitor.
http://localhost/api/lbaas/healthmonitors/cc758c90-3d98-4ea1-af44-aab405c9c915 http://localhost/api/lbaas/healthmonitors/cc758c90-3d98-4ea1-af44-aab405c9c915
""" """
neutronclient(request).delete_lbaas_healthmonitor(healthmonitor_id) conn = _get_sdk_connection(request)
conn.load_balancer.delete_health_monitor(health_monitor_id,
ignore_missing=True)
@rest_utils.ajax() @rest_utils.ajax()
def put(self, request, healthmonitor_id): def put(self, request, health_monitor_id):
"""Edit a health monitor. """Edit a health monitor.
""" """

View File

@ -701,8 +701,8 @@ msgstr ""
msgid "Subnet ID" msgid "Subnet ID"
msgstr "Subnetz-ID" msgstr "Subnetz-ID"
msgid "Tenant ID" msgid "Project ID"
msgstr "Mandanten-ID" msgstr "Projekt-ID"
msgid "" msgid ""
"The Available Instances table contains existing compute instances that can " "The Available Instances table contains existing compute instances that can "

View File

@ -696,8 +696,8 @@ msgstr ""
msgid "Subnet ID" msgid "Subnet ID"
msgstr "Subnet ID (ID subnet)" msgstr "Subnet ID (ID subnet)"
msgid "Tenant ID" msgid "Project ID"
msgstr "Tenant ID" msgstr "Project ID"
msgid "" msgid ""
"The Available Instances table contains existing compute instances that can " "The Available Instances table contains existing compute instances that can "

View File

@ -449,8 +449,8 @@ msgstr "サブネット<span class=\"hz-icon-required fa fa-asterisk\"></span>"
msgid "Subnet ID" msgid "Subnet ID"
msgstr "サブネット ID" msgstr "サブネット ID"
msgid "Tenant ID" msgid "Project ID"
msgstr "テナント ID" msgstr "プロジェクト ID"
msgid "The URL path is not valid." msgid "The URL path is not valid."
msgstr "URLは有効ではありません。" msgstr "URLは有効ではありません。"

View File

@ -628,8 +628,8 @@ msgstr ""
msgid "Subnet ID" msgid "Subnet ID"
msgstr "ID подсети" msgstr "ID подсети"
msgid "Tenant ID" msgid "Project ID"
msgstr "ИД арендатора" msgstr "ID проекта"
msgid "The IP address is not valid." msgid "The IP address is not valid."
msgstr "IP адрес не действителен." msgstr "IP адрес не действителен."

View File

@ -672,8 +672,8 @@ msgstr ""
msgid "Subnet ID" msgid "Subnet ID"
msgstr "子网ID" msgstr "子网ID"
msgid "Tenant ID" msgid "Project ID"
msgstr "租户ID" msgstr "项目ID"
msgid "" msgid ""
"The Available Instances table contains existing compute instances that can " "The Available Instances table contains existing compute instances that can "

View File

@ -41,7 +41,6 @@
deleteLoadBalancer: deleteLoadBalancer, deleteLoadBalancer: deleteLoadBalancer,
createLoadBalancer: createLoadBalancer, createLoadBalancer: createLoadBalancer,
editLoadBalancer: editLoadBalancer, editLoadBalancer: editLoadBalancer,
getLoadBalancerStatusTree: getLoadBalancerStatusTree,
getListeners: getListeners, getListeners: getListeners,
getListener: getListener, getListener: getListener,
createListener: createListener, createListener: createListener,
@ -148,21 +147,6 @@
}); });
} }
/**
* @name horizon.app.core.openstack-service-api.lbaasv2.getLoadBalancerStatusTree
* @description
* Get the status tree for a load balancer
* @param {string} id
* Specifies the id of the load balancer to request the status tree for.
*/
function getLoadBalancerStatusTree(id) {
return apiService.get('/api/lbaas/loadbalancers/' + id + '/statuses/')
.error(function () {
toastService.add('error', gettext('Unable to retrieve load balancer status tree.'));
});
}
// Listeners // Listeners
/** /**

View File

@ -59,13 +59,6 @@
error: 'Unable to delete load balancer.', error: 'Unable to delete load balancer.',
testInput: [ '1234' ] testInput: [ '1234' ]
}, },
{
func: 'getLoadBalancerStatusTree',
method: 'get',
path: '/api/lbaas/loadbalancers/1234/statuses/',
error: 'Unable to retrieve load balancer status tree.',
testInput: [ '1234' ]
},
{ {
func: 'getListeners', func: 'getListeners',
method: 'get', method: 'get',

View File

@ -73,7 +73,7 @@
poolId = pool.id; poolId = pool.id;
return $q.all([ return $q.all([
statePromise, statePromise,
qExtensions.booleanAsPromise(!pool.healthmonitor_id), qExtensions.booleanAsPromise(!pool.health_monitor_id),
policy.ifAllowed({ rules: [['neutron', 'create_health_monitor']] }) policy.ifAllowed({ rules: [['neutron', 'create_health_monitor']] })
]); ]);
} }

View File

@ -89,7 +89,7 @@
it('should not allow creating a health monitor if one already exists', function() { it('should not allow creating a health monitor if one already exists', function() {
loadBalancerState.resolve(); loadBalancerState.resolve();
init('active', '1', loadBalancerState.promise); init('active', '1', loadBalancerState.promise);
expect(allowed({ healthmonitor_id: '1234' })).toBe(false); expect(allowed({ health_monitor_id: '1234' })).toBe(false);
}); });
it('should redirect after create', function() { it('should redirect after create', function() {

View File

@ -33,8 +33,8 @@
<dd>{$ ctrl.healthmonitor.admin_state_up | yesno $}</dd> <dd>{$ ctrl.healthmonitor.admin_state_up | yesno $}</dd>
<dt translate>Monitor ID</dt> <dt translate>Monitor ID</dt>
<dd>{$ ::ctrl.healthmonitor.id $}</dd> <dd>{$ ::ctrl.healthmonitor.id $}</dd>
<dt translate>Tenant ID</dt> <dt translate>Project ID</dt>
<dd>{$ ::ctrl.healthmonitor.tenant_id $}</dd> <dd>{$ ::ctrl.healthmonitor.project_id $}</dd>
</dl> </dl>
</div> </div>
</div> </div>

View File

@ -33,8 +33,8 @@
</dd> </dd>
<dt translate>Listener ID</dt> <dt translate>Listener ID</dt>
<dd>{$ ::ctrl.listener.id $}</dd> <dd>{$ ::ctrl.listener.id $}</dd>
<dt translate>Tenant ID</dt> <dt translate>Project ID</dt>
<dd>{$ ::ctrl.listener.tenant_id $}</dd> <dd>{$ ::ctrl.listener.project_id $}</dd>
</dl> </dl>
</div> </div>
</div> </div>

View File

@ -25,8 +25,7 @@
'horizon.dashboard.project.lbaasv2.members.actions.rowActions', 'horizon.dashboard.project.lbaasv2.members.actions.rowActions',
'$routeParams', '$routeParams',
'$q', '$q',
'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.loadbalancers.service'
'horizon.dashboard.project.lbaasv2.members.service'
]; ];
/** /**
@ -41,12 +40,11 @@
* @param $routeParams The angular $routeParams service. * @param $routeParams The angular $routeParams service.
* @param $q The angular service for promises. * @param $q The angular service for promises.
* @param loadBalancersService The LBaaS v2 load balancers service. * @param loadBalancersService The LBaaS v2 load balancers service.
* @param membersService The LBaaS v2 members service.
* @returns undefined * @returns undefined
*/ */
function MemberDetailController( function MemberDetailController(
api, rowActions, $routeParams, $q, loadBalancersService, membersService api, rowActions, $routeParams, $q, loadBalancersService
) { ) {
var ctrl = this; var ctrl = this;
@ -85,15 +83,6 @@
function success(property) { function success(property) {
return angular.bind(null, function setProp(property, response) { return angular.bind(null, function setProp(property, response) {
ctrl[property] = response.data; ctrl[property] = response.data;
if (property === 'member') {
membersService.associateMemberStatuses(
ctrl.loadbalancerId,
ctrl.listenerId,
ctrl.poolId,
[ctrl.member]);
}
}, property); }, property);
} }

View File

@ -17,7 +17,7 @@
'use strict'; 'use strict';
describe('LBaaS v2 Member Detail Controller', function() { describe('LBaaS v2 Member Detail Controller', function() {
var $controller, lbaasv2API, membersService, apiFail, qAllFail, actions; var $controller, lbaasv2API, apiFail, qAllFail, actions;
function fakePromise(data, reject) { function fakePromise(data, reject) {
return { return {
@ -81,13 +81,11 @@
beforeEach(inject(function($injector) { beforeEach(inject(function($injector) {
lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
actions = $injector.get('horizon.dashboard.project.lbaasv2.members.actions.rowActions'); actions = $injector.get('horizon.dashboard.project.lbaasv2.members.actions.rowActions');
membersService = $injector.get('horizon.dashboard.project.lbaasv2.members.service');
spyOn(lbaasv2API, 'getMember').and.callFake(fakeAPI); spyOn(lbaasv2API, 'getMember').and.callFake(fakeAPI);
spyOn(lbaasv2API, 'getPool').and.callFake(fakeAPI); spyOn(lbaasv2API, 'getPool').and.callFake(fakeAPI);
spyOn(lbaasv2API, 'getListener').and.callFake(fakeAPI); spyOn(lbaasv2API, 'getListener').and.callFake(fakeAPI);
spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI);
spyOn(actions, 'init').and.callThrough(); spyOn(actions, 'init').and.callThrough();
spyOn(membersService, 'associateMemberStatuses');
$controller = $injector.get('$controller'); $controller = $injector.get('$controller');
})); }));
@ -106,12 +104,6 @@
expect(actions.init).toHaveBeenCalledWith('loadbalancerId', 'poolId'); expect(actions.init).toHaveBeenCalledWith('loadbalancerId', 'poolId');
}); });
it('should invoke the "associateMemberStatuses" method', function() {
var ctrl = createController();
expect(membersService.associateMemberStatuses).toHaveBeenCalledWith(
ctrl.loadbalancerId, ctrl.listenerId, ctrl.poolId, [ctrl.member]);
});
it('should throw error on API fail', function() { it('should throw error on API fail', function() {
apiFail = true; apiFail = true;
var init = function() { var init = function() {

View File

@ -29,8 +29,8 @@
<dd>{$ ctrl.member.admin_state_up | yesno $}</dd> <dd>{$ ctrl.member.admin_state_up | yesno $}</dd>
<dt translate>Member ID</dt> <dt translate>Member ID</dt>
<dd>{$ ::ctrl.member.id $}</dd> <dd>{$ ::ctrl.member.id $}</dd>
<dt translate>Tenant ID</dt> <dt translate>Project ID</dt>
<dd>{$ ::ctrl.member.tenant_id $}</dd> <dd>{$ ::ctrl.member.project_id $}</dd>
</dl> </dl>
</div> </div>
</div> </div>

View File

@ -1,92 +0,0 @@
/*
* Copyright 2016 IBM Corp.
*
* 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.
*/
(function () {
'use strict';
angular
.module('horizon.dashboard.project.lbaasv2.members')
.factory('horizon.dashboard.project.lbaasv2.members.service', membersService);
membersService.$inject = [
'horizon.app.core.openstack-service-api.lbaasv2'
];
/**
* @ngdoc service
* @name horizon.dashboard.project.lbaasv2.members.service
* @description General service for LBaaS v2 members.
* @param api The LBaaS V2 service API.
* @returns The members service.
*/
function membersService(api) {
var service = {
associateMemberStatuses: associateMemberStatuses
};
return service;
////////////
/**
* @ngdoc method
* @name horizon.dashboard.project.lbaasv2.members.service.associateMemberStatuses
* @description Associates the list of specified members with their corresponding statuses
* that are retrieved from the load balancer status tree.
* @param loadBalancerId The load balancer ID.
* @param listenerId The listener ID that the members belong to.
* @param poolId The pool ID that the members belong to.
* @param members The list of members to associate with their corresponding health statuses.
* @returns None
*/
function associateMemberStatuses(loadBalancerId, listenerId, poolId, members) {
api.getLoadBalancerStatusTree(loadBalancerId).then(function(response) {
// Collect the member status data for all specified members
var memberStatusData = [];
var listeners = response.data.statuses.loadbalancer.listeners;
for (var listenerIndex = 0; listenerIndex < listeners.length; listenerIndex++) {
var listener = listeners[listenerIndex];
if (listener.id === listenerId) {
var pools = listener.pools;
for (var poolIndex = 0; poolIndex < pools.length; poolIndex++) {
var pool = pools[poolIndex];
if (pool.id === poolId) {
memberStatusData = pool.members;
break;
}
}
break;
}
}
// Attach the status properties to each member object
members.forEach(mapStatusToMember);
function mapStatusToMember(member) {
for (var memberIndex = 0; memberIndex < memberStatusData.length; memberIndex++) {
var memberWithStatuses = memberStatusData[memberIndex];
if (memberWithStatuses.id === member.id) {
member.operating_status = memberWithStatuses.operating_status;
member.provisioning_status = memberWithStatuses.provisioning_status;
break;
}
}
}
});
}
}
}());

View File

@ -1,107 +0,0 @@
/*
* Copyright 2016 IBM Corp.
*
* 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.
*/
(function() {
'use strict';
describe('LBaaS v2 Members Service', function() {
var service, $q, scope;
beforeEach(module('horizon.framework.widgets.toast'));
beforeEach(module('horizon.framework.conf'));
beforeEach(module('horizon.framework.util'));
beforeEach(module('horizon.app.core.openstack-service-api'));
beforeEach(module('horizon.dashboard.project.lbaasv2'));
beforeEach(module(function($provide) {
$provide.value('horizon.app.core.openstack-service-api.lbaasv2', {
getLoadBalancerStatusTree: function() {
var deferred = $q.defer();
var response = {
data: {
statuses: {
loadbalancer: {
id: 'loadbalancer1',
listeners: [
{
id: 'listener0',
pools: []
},
{
id: 'listener1',
pools: [
{
id: 'pool0',
members: []
},
{
id: 'pool1',
members: [
{
id: 'member1',
operating_status: 'ONLINE',
provisioning_status: 'ACTIVE'
},
{
id: 'member2',
operating_status: 'OFFLINE',
provisioning_status: 'INACTIVE'
}
]
}
]
}
]
}
}
}
};
deferred.resolve(response);
return deferred.promise;
}
});
}));
beforeEach(inject(function ($injector) {
service = $injector.get('horizon.dashboard.project.lbaasv2.members.service');
$q = $injector.get('$q');
scope = $injector.get('$rootScope').$new();
}));
it('should define service attributes', function() {
expect(service.associateMemberStatuses).toBeDefined();
});
it('should correctly associate member health statuses', function() {
var members = [
{ id: 'member1' },
{ id: 'member2' }
];
service.associateMemberStatuses('loadbalancer1', 'listener1', 'pool1', members);
scope.$apply();
expect(members.length).toBe(2);
expect(members[0].operating_status).toBe('ONLINE');
expect(members[0].provisioning_status).toBe('ACTIVE');
expect(members[1].operating_status).toBe('OFFLINE');
expect(members[1].provisioning_status).toBe('INACTIVE');
});
});
})();

View File

@ -25,8 +25,7 @@
'horizon.dashboard.project.lbaasv2.members.actions.rowActions', 'horizon.dashboard.project.lbaasv2.members.actions.rowActions',
'horizon.dashboard.project.lbaasv2.members.actions.batchActions', 'horizon.dashboard.project.lbaasv2.members.actions.batchActions',
'$routeParams', '$routeParams',
'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.loadbalancers.service'
'horizon.dashboard.project.lbaasv2.members.service'
]; ];
/** /**
@ -41,12 +40,11 @@
* @param batchActions The members batch actions service. * @param batchActions The members batch actions service.
* @param $routeParams The angular $routeParams service. * @param $routeParams The angular $routeParams service.
* @param loadBalancersService The LBaaS v2 load balancers service. * @param loadBalancersService The LBaaS v2 load balancers service.
* @param membersService The LBaaS v2 members service.
* @returns undefined * @returns undefined
*/ */
function MembersTableController( function MembersTableController(
api, rowActions, batchActions, $routeParams, loadBalancersService, membersService api, rowActions, batchActions, $routeParams, loadBalancersService
) { ) {
var ctrl = this; var ctrl = this;
ctrl.items = []; ctrl.items = [];
@ -76,11 +74,6 @@
function success(response) { function success(response) {
ctrl.src = response.data.items; ctrl.src = response.data.items;
ctrl.loading = false; ctrl.loading = false;
membersService.associateMemberStatuses(
ctrl.loadbalancerId,
ctrl.listenerId,
ctrl.poolId,
ctrl.src);
} }
function fail(/*response*/) { function fail(/*response*/) {

View File

@ -18,7 +18,7 @@
'use strict'; 'use strict';
describe('LBaaS v2 Members Table Controller', function() { describe('LBaaS v2 Members Table Controller', function() {
var controller, lbaasv2API, membersService, scope; var controller, lbaasv2API, scope;
var items = [{ foo: 'bar' }]; var items = [{ foo: 'bar' }];
var apiFail = false; var apiFail = false;
@ -47,10 +47,8 @@
beforeEach(inject(function($injector) { beforeEach(inject(function($injector) {
lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2');
membersService = $injector.get('horizon.dashboard.project.lbaasv2.members.service');
controller = $injector.get('$controller'); controller = $injector.get('$controller');
spyOn(lbaasv2API, 'getMembers').and.callFake(fakeAPI); spyOn(lbaasv2API, 'getMembers').and.callFake(fakeAPI);
spyOn(membersService, 'associateMemberStatuses');
})); }));
function createController() { function createController() {
@ -85,12 +83,6 @@
expect(ctrl.src.length).toBe(1); expect(ctrl.src.length).toBe(1);
}); });
it('should invoke the "associateMemberStatuses" method', function() {
var ctrl = createController();
expect(membersService.associateMemberStatuses).toHaveBeenCalledWith(
ctrl.loadbalancerId, ctrl.listenerId, ctrl.poolId, ctrl.src);
});
it('should show error if loading fails', function() { it('should show error if loading fails', function() {
apiFail = true; apiFail = true;
var ctrl = createController(); var ctrl = createController();

View File

@ -27,17 +27,17 @@
<dd>{$ ctrl.pool.admin_state_up | yesno $}</dd> <dd>{$ ctrl.pool.admin_state_up | yesno $}</dd>
<dt translate>Health Monitor ID</dt> <dt translate>Health Monitor ID</dt>
<dd> <dd>
<a ng-href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}/healthmonitors/{$ ::ctrl.pool.healthmonitor_id $}" ng-if="ctrl.pool.healthmonitor_id"> <a ng-href="project/load_balancer/{$ ::ctrl.loadbalancer.id $}/listeners/{$ ::ctrl.listener.id $}/pools/{$ ::ctrl.pool.id $}/healthmonitors/{$ ::ctrl.pool.health_monitor_id $}" ng-if="ctrl.pool.health_monitor_id">
{$ ::ctrl.pool.healthmonitor_id $} {$ ::ctrl.pool.health_monitor_id $}
</a> </a>
<span ng-if="!ctrl.pool.healthmonitor_id"> <span ng-if="!ctrl.pool.health_monitor_id">
{$ 'None' | translate $} {$ 'None' | translate $}
</span> </span>
</dd> </dd>
<dt translate>Pool ID</dt> <dt translate>Pool ID</dt>
<dd>{$ ::ctrl.pool.id $}</dd> <dd>{$ ::ctrl.pool.id $}</dd>
<dt translate>Tenant ID</dt> <dt translate>Project ID</dt>
<dd>{$ ::ctrl.pool.tenant_id $}</dd> <dd>{$ ::ctrl.pool.project_id $}</dd>
</dl> </dl>
</div> </div>
</div> </div>

View File

@ -4,4 +4,5 @@
pbr!=2.1.0,>=2.0.0 # Apache-2.0 pbr!=2.1.0,>=2.0.0 # Apache-2.0
Babel!=2.4.0,>=2.3.4 # BSD Babel!=2.4.0,>=2.3.4 # BSD
openstacksdk>=0.9.18 # Apache-2.0
python-barbicanclient!=4.5.0,!=4.5.1,>=4.0.0 # Apache-2.0 python-barbicanclient!=4.5.0,!=4.5.1,>=4.0.0 # Apache-2.0