Files
octavia-dashboard/octavia_dashboard/api/rest/lbaasv2.py
Pavlo Shchelokovskyy 3d429a46be Optimize empty loadbalancer page
do not ask for list of floating IPs if there's no LBs,
no need for (potentially costly) API calls
when the result will be thrown out anyway.

Change-Id: I9a7f72fa8f95fe56a95216b72f7c1d7542cfcbcc
Signed-off-by: Pavlo Shchelokovskyy <shchelokovskyy@gmail.com>
2025-12-02 18:46:35 +00:00

1484 lines
48 KiB
Python

# Copyright 2015 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.
"""API over the neutron LBaaS v2 service.
"""
import _thread as thread
import time
from django.views import generic
from horizon import conf
from octavia_dashboard.sdk_connection import get_sdk_connection
from openstack import exceptions
from openstack_dashboard.api import neutron
from openstack_dashboard.api.rest import urls
from openstack_dashboard.api.rest import utils as rest_utils
neutronclient = neutron.neutronclient
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,
from_state='PENDING_UPDATE', to_state='ACTIVE',
callback_kwargs=None):
"""Poll for the status of the load balancer.
Polls for the status of the load balancer and calls a function when the
status changes to a specified state.
:param request: django request object
:param loadbalancer_id: id of the load balancer to poll
:param callback: function to call when polling is complete
:param from_state: initial expected state of the load balancer
:param to_state: state to check for
:param callback_kwargs: kwargs to pass into the callback function
"""
interval = conf.HORIZON_CONFIG['ajax_poll_interval'] / 1000.0
status = from_state
while status == from_state:
time.sleep(interval)
conn = get_sdk_connection(request)
lb = conn.load_balancer.get_load_balancer(loadbalancer_id)
status = lb.provisioning_status
if status == to_state:
kwargs = {'loadbalancer_id': loadbalancer_id}
if callback_kwargs:
kwargs.update(callback_kwargs)
callback(request, **kwargs)
def _retry_on_conflict(conn, func, *args, retry_timeout=120, **kwargs):
load_balancer_getter = kwargs.pop('load_balancer_getter')
resource_id = kwargs.pop('resource_id')
interval = conf.HORIZON_CONFIG['ajax_poll_interval'] / 1000.0
load_balancer_id = load_balancer_getter(conn, resource_id)
start = time.time()
while time.time() - start < retry_timeout:
lb = conn.load_balancer.get_load_balancer(load_balancer_id)
if lb.provisioning_status == 'PENDING_UPDATE':
time.sleep(interval)
continue
try:
func(*args, **kwargs)
except exceptions.ConflictException:
# Still catching 409/Conflict as there might have multiple threads
# waiting for a non-PENDING provisioning state
time.sleep(interval)
continue
break
def retry_on_conflict(conn, func, *args, retry_timeout=120, **kwargs):
load_balancer_getter = kwargs.pop('load_balancer_getter')
resource_id = kwargs.pop('resource_id')
try:
func(*args, **kwargs)
except exceptions.ConflictException:
thread.start_new_thread(
_retry_on_conflict,
(conn, func, *args),
{'retry_timeout': retry_timeout,
'load_balancer_getter': load_balancer_getter,
'resource_id': resource_id,
**kwargs})
def listener_get_load_balancer_id(conn, listener_id):
listener = conn.load_balancer.get_listener(listener_id)
return listener.load_balancers[0]['id']
def l7_policy_get_load_balancer_id(conn, l7_policy_id):
l7_policy = conn.load_balancer.get_l7_policy(l7_policy_id)
listener = conn.load_balancer.get_listener(l7_policy.listener_id)
return listener.load_balancers[0]['id']
def pool_get_load_balancer_id(conn, pool_id):
pool = conn.load_balancer.get_pool(pool_id)
return pool.loadbalancers[0]['id']
def health_monitor_get_load_balancer_id(conn, health_monitor_id):
pool_id = conn.load_balancer.get_health_monitor(health_monitor_id)
return pool_get_load_balancer_id(conn, pool_id)
def create_loadbalancer(request):
data = request.DATA
conn = get_sdk_connection(request)
build_kwargs = dict(
project_id=request.user.project_id,
vip_subnet_id=data['loadbalancer']['vip_subnet_id'],
name=data['loadbalancer'].get('name'),
description=data['loadbalancer'].get('description'),
vip_address=data['loadbalancer'].get('vip_address'),
admin_state_up=data['loadbalancer'].get('admin_state_up'),
)
flavor_id = data['loadbalancer'].get('flavor_id')
if flavor_id:
build_kwargs['flavor_id'] = flavor_id
availability_zone = data['loadbalancer'].get('availability_zone')
if availability_zone:
build_kwargs['availability_zone'] = availability_zone
loadbalancer = conn.load_balancer.create_load_balancer(**build_kwargs)
if data.get('listener'):
# 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
# available we use a separate thread to poll for the load
# balancer status and create the other resources when it becomes
# active.
args = (request, loadbalancer.id, create_listener)
kwargs = {'from_state': 'PENDING_CREATE'}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
return _get_sdk_object_dict(loadbalancer)
def create_listener(request, **kwargs):
"""Create a new listener.
"""
data = request.DATA
try:
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']['protocol_port'],
load_balancer_id=kwargs['loadbalancer_id'],
name=data['listener'].get('name'),
description=data['listener'].get('description'),
connection_limit=data['listener'].get('connection_limit'),
default_tls_container_ref=default_tls_ref,
sni_container_refs=None,
admin_state_up=data['listener'].get('admin_state_up'),
insert_headers=data['listener'].get('insert_headers'),
timeout_client_data=data['listener'].get('timeout_client_data'),
timeout_member_connect=data['listener'].get('timeout_member_connect'),
timeout_member_data=data['listener'].get('timeout_member_data'),
timeout_tcp_inspect=data['listener'].get('timeout_tcp_inspect'),
allowed_cidrs=data['listener'].get('allowed_cidrs'),
# Replace empty string by None (uses default tls cipher string)
tls_ciphers=data['listener'].get('tls_ciphers') or None,
)
if data.get('pool'):
args = (request, kwargs['loadbalancer_id'], create_pool)
kwargs = {'callback_kwargs': {'listener_id': listener.id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
return _get_sdk_object_dict(listener)
def create_l7_policy(request, **kwargs):
"""Create a new l7 policy.
"""
data = request.DATA
conn = get_sdk_connection(request)
l7_policy = conn.load_balancer.create_l7_policy(
action=data['l7policy']['action'],
admin_state_up=data['l7policy'].get('admin_state_up'),
description=data['l7policy'].get('description'),
listener_id=kwargs['listener_id'],
name=data['l7policy'].get('name'),
position=data['l7policy'].get('position'),
redirect_pool_id=data['l7policy'].get('redirect_pool_id'),
redirect_url=data['l7policy'].get('redirect_url'),
)
return _get_sdk_object_dict(l7_policy)
def create_l7_rule(request, **kwargs):
"""Create a new l7 rule.
"""
data = request.DATA
conn = get_sdk_connection(request)
l7_rule = conn.load_balancer.create_l7_rule(
admin_state_up=data['l7rule'].get('admin_state_up'),
compare_type=data['l7rule']['compare_type'],
invert=data['l7rule'].get('invert'),
key=data['l7rule'].get('key'),
l7_policy=kwargs['l7_policy_id'],
type=data['l7rule']['type'],
rule_value=data['l7rule']['rule_value'],
)
return _get_sdk_object_dict(l7_rule)
def create_pool(request, **kwargs):
"""Create a new pool.
"""
data = request.DATA
conn = get_sdk_connection(request)
pool = conn.load_balancer.create_pool(
protocol=data['pool']['protocol'],
lb_algorithm=data['pool']['lb_algorithm'],
session_persistence=data['pool'].get('session_persistence'),
listener_id=kwargs['listener_id'],
loadbalancer_id=kwargs['loadbalancer_id'],
name=data['pool'].get('name'),
description=data['pool'].get('description'),
admin_state_up=data['pool'].get('admin_state_up'),
tls_enabled=data['pool'].get('tls_enabled'),
# Replace empty string by None (uses default tls cipher string)
tls_ciphers=data['pool'].get('tls_ciphers') or None,
)
if data.get('members'):
args = (request, kwargs['loadbalancer_id'], add_member)
kwargs = {'callback_kwargs': {'pool_id': pool.id,
'index': 0}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
elif data.get('monitor'):
args = (request, kwargs['loadbalancer_id'], create_health_monitor)
kwargs = {'callback_kwargs': {'pool_id': pool.id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
return _get_sdk_object_dict(pool)
def create_health_monitor(request, **kwargs):
"""Create a new health monitor for a pool.
"""
data = request.DATA
conn = get_sdk_connection(request)
health_mon = conn.load_balancer.create_health_monitor(
type=data['monitor']['type'],
delay=data['monitor']['delay'],
timeout=data['monitor']['timeout'],
max_retries=data['monitor']['max_retries'],
max_retries_down=data['monitor']['max_retries_down'],
pool_id=kwargs['pool_id'],
http_method=data['monitor'].get('http_method'),
url_path=data['monitor'].get('url_path'),
expected_codes=data['monitor'].get('expected_codes'),
admin_state_up=data['monitor'].get('admin_state_up'),
name=data['monitor'].get('name')
)
return _get_sdk_object_dict(health_mon)
def create_flavor(request, **kwargs):
"""Create a new flavor.
"""
data = request.DATA
conn = get_sdk_connection(request)
flavor = conn.load_balancer.create_flavor(
name=data['flavor']['name'],
flavor_profile_id=data['flavor']['flavor_profile_id'],
description=data['flavor'].get('description'),
enabled=data['flavor'].get('enabled'),
)
return _get_sdk_object_dict(flavor)
def create_flavor_profile(request, **kwargs):
"""Create a new flavor profile.
"""
data = request.DATA
conn = get_sdk_connection(request)
flavor_profile = conn.load_balancer.create_flavor(
name=data['flavor_profile']['name'],
provider_name=data['flavor_profile']['provider_name'],
flavor_data=data['flavor_profile']['flavor_data'],
)
return _get_sdk_object_dict(flavor_profile)
def add_member(request, **kwargs):
"""Add a member to a pool.
"""
data = request.DATA
members = data.get('members')
pool_id = kwargs.get('pool_id')
if kwargs.get('members_to_add'):
members_to_add = kwargs['members_to_add']
index = [members.index(member) for member in members
if member['id'] == members_to_add[0]][0]
loadbalancer_id = data.get('loadbalancer_id')
else:
index = kwargs.get('index')
loadbalancer_id = kwargs.get('loadbalancer_id')
member = members[index]
conn = get_sdk_connection(request)
monitor_address = member.get('monitor_address')
member = conn.load_balancer.create_member(
pool_id,
address=member['address'],
protocol_port=member['protocol_port'],
subnet_id=member['subnet_id'],
weight=member.get('weight'),
monitor_address=monitor_address if monitor_address else None,
monitor_port=member.get('monitor_port'),
admin_state_up=member.get('admin_state_up'),
backup=member.get('backup', False),
name=member.get('name'),
)
index += 1
if kwargs.get('members_to_add'):
args = (request, loadbalancer_id, update_member_list)
members_to_add = kwargs['members_to_add']
members_to_add.pop(0)
kwargs = {'callback_kwargs': {
'existing_members': kwargs.get('existing_members'),
'members_to_add': members_to_add,
'members_to_delete': kwargs.get('members_to_delete'),
'pool_id': pool_id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
elif len(members) > index:
args = (request, loadbalancer_id, add_member)
kwargs = {'callback_kwargs': {'pool_id': pool_id,
'index': index}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
elif data.get('monitor'):
args = (request, loadbalancer_id, create_health_monitor)
kwargs = {'callback_kwargs': {'pool_id': pool_id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
return _get_sdk_object_dict(member)
def remove_member(request, **kwargs):
"""Remove a member from the pool.
"""
data = request.DATA
loadbalancer_id = data.get('loadbalancer_id')
pool_id = kwargs.get('pool_id')
if kwargs.get('members_to_delete'):
members_to_delete = kwargs['members_to_delete']
member_id = members_to_delete.pop(0)
conn = get_sdk_connection(request)
conn.load_balancer.delete_member(member_id, pool_id,
ignore_missing=True)
args = (request, loadbalancer_id, update_member_list)
kwargs = {'callback_kwargs': {
'existing_members': kwargs.get('existing_members'),
'members_to_add': kwargs.get('members_to_add'),
'members_to_delete': members_to_delete,
'pool_id': pool_id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
def update_loadbalancer(request, **kwargs):
"""Update a load balancer.
"""
data = request.DATA
loadbalancer_id = kwargs.get('loadbalancer_id')
conn = get_sdk_connection(request)
loadbalancer = conn.load_balancer.update_load_balancer(
loadbalancer_id,
name=data['loadbalancer'].get('name'),
description=data['loadbalancer'].get('description'),
admin_state_up=data['loadbalancer'].get('admin_state_up'))
return _get_sdk_object_dict(loadbalancer)
def update_listener(request, **kwargs):
"""Update a listener.
"""
data = request.DATA
listener_id = data['listener'].get('id')
loadbalancer_id = data.get('loadbalancer_id')
default_pool_id = data['listener'].get('default_pool_id')
if not default_pool_id:
default_pool_id = None
else:
default_pool_id = default_pool_id[:36]
try:
default_tls_ref = data['certificates'][0]
except (KeyError, IndexError):
default_tls_ref = None
conn = get_sdk_connection(request)
listener = conn.load_balancer.update_listener(
listener=listener_id,
name=data['listener'].get('name'),
description=data['listener'].get('description'),
connection_limit=data['listener'].get('connection_limit'),
default_tls_container_ref=default_tls_ref,
sni_container_refs=None,
admin_state_up=data['listener'].get('admin_state_up'),
default_pool_id=default_pool_id,
insert_headers=data['listener'].get('insert_headers'),
timeout_client_data=data['listener'].get('timeout_client_data'),
timeout_member_connect=data['listener'].get('timeout_member_connect'),
timeout_member_data=data['listener'].get('timeout_member_data'),
timeout_tcp_inspect=data['listener'].get('timeout_tcp_inspect'),
allowed_cidrs=data['listener'].get('allowed_cidrs'),
# Replace empty string by None (uses default tls cipher string)
tls_ciphers=data['listener'].get('tls_ciphers') or None,
)
if data.get('pool'):
args = (request, loadbalancer_id, update_pool)
thread.start_new_thread(poll_loadbalancer_status, args)
return _get_sdk_object_dict(listener)
def update_l7_policy(request, **kwargs):
"""Update a l7 policy.
"""
data = request.DATA
l7_policy_id = data['l7policy'].get('id')
conn = get_sdk_connection(request)
l7_policy = conn.load_balancer.update_l7_policy(
action=data['l7policy']['action'],
admin_state_up=data['l7policy'].get('admin_state_up'),
description=data['l7policy'].get('description'),
l7_policy=l7_policy_id,
name=data['l7policy'].get('name'),
position=data['l7policy'].get('position'),
redirect_pool_id=data['l7policy'].get('redirect_pool_id'),
redirect_url=data['l7policy'].get('redirect_url'),
)
return _get_sdk_object_dict(l7_policy)
def update_l7_rule(request, **kwargs):
"""Update a l7 rule.
"""
data = request.DATA
l7_rule_id = data['l7rule'].get('id')
conn = get_sdk_connection(request)
l7_rule = conn.load_balancer.update_l7_rule(
admin_state_up=data['l7rule'].get('admin_state_up'),
compare_type=data['l7rule']['compare_type'],
invert=data['l7rule'].get('invert'),
key=data['l7rule'].get('key'),
l7_policy=kwargs['l7_policy_id'],
l7rule=l7_rule_id,
type=data['l7rule']['type'],
rule_value=data['l7rule']['rule_value'],
)
return _get_sdk_object_dict(l7_rule)
def update_pool(request, **kwargs):
"""Update a pool.
"""
data = request.DATA
pool_id = data['pool'].get('id')
loadbalancer_id = data.get('loadbalancer_id')
conn = get_sdk_connection(request)
pool = conn.load_balancer.update_pool(
pool=pool_id,
lb_algorithm=data['pool']['lb_algorithm'],
session_persistence=data['pool'].get('session_persistence'),
name=data['pool'].get('name'),
description=data['pool'].get('description'),
admin_state_up=data['pool'].get('admin_state_up'),
tls_enabled=data['pool'].get('tls_enabled'),
# Replace empty string by None (uses default tls cipher string)
tls_ciphers=data['pool'].get('tls_ciphers') or None,
)
# Assemble the lists of member id's to add and remove, if any exist
request_member_data = data.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(
request_member_data, existing_members)
if members_to_add or members_to_delete:
args = (request, loadbalancer_id, update_member_list)
kwargs = {'callback_kwargs': {'existing_members': existing_members,
'members_to_add': members_to_add,
'members_to_delete': members_to_delete,
'pool_id': pool_id}}
thread.start_new_thread(poll_loadbalancer_status, args, kwargs)
elif data.get('monitor'):
args = (request, loadbalancer_id, update_monitor)
thread.start_new_thread(poll_loadbalancer_status, args)
return _get_sdk_object_dict(pool)
def update_monitor(request, **kwargs):
"""Update a health monitor.
"""
data = request.DATA
monitor_id = data['monitor']['id']
hm_type = data['monitor']['type']
conn = get_sdk_connection(request)
healthmonitor_kwargs = {
'delay': data['monitor'].get('delay'),
'timeout': data['monitor'].get('timeout'),
'max_retries': data['monitor'].get('max_retries'),
'max_retries_down': data['monitor'].get('max_retries_down'),
'admin_state_up': data['monitor'].get('admin_state_up'),
'name': data['monitor'].get('name')
}
if hm_type in ('HTTP', 'HTTPS'):
healthmonitor_kwargs.update({
'http_method': data['monitor'].get('http_method'),
'url_path': data['monitor'].get('url_path'),
'expected_codes': data['monitor'].get('expected_codes')
})
healthmonitor = conn.load_balancer.update_health_monitor(
monitor_id,
**healthmonitor_kwargs
)
return _get_sdk_object_dict(healthmonitor)
def update_flavor(request, **kwargs):
"""Update a flavor.
"""
data = request.DATA
flavor_id = data['flavor']['id']
conn = get_sdk_connection(request)
flavor = conn.load_balancer.update_flavor(
flavor_id,
name=data['flavor'].get('name'),
description=data['flavor'].get('description'),
enabled=data['flavor'].get('enabled'),
)
return _get_sdk_object_dict(flavor)
def update_flavor_profile(request, **kwargs):
"""Update a flavor profile.
"""
data = request.DATA
flavor_profile_id = data['flavor_profile']['id']
conn = get_sdk_connection(request)
flavor_profile = conn.load_balancer.update_flavor_profile(
flavor_profile_id,
name=data['flavor_profile'].get('name'),
provider_name=data['flavor_profile'].get('provider_name'),
flavor_data=data['flavor_profile'].get('flavor_data'),
)
return _get_sdk_object_dict(flavor_profile)
def update_member_list(request, **kwargs):
"""Update the list of members by adding or removing the necessary members.
"""
data = request.DATA
loadbalancer_id = data.get('loadbalancer_id')
pool_id = kwargs.get('pool_id')
existing_members = kwargs.get('existing_members')
members_to_add = kwargs.get('members_to_add')
members_to_delete = kwargs.get('members_to_delete')
if members_to_delete:
kwargs = {'existing_members': existing_members,
'members_to_add': members_to_add,
'members_to_delete': members_to_delete,
'pool_id': pool_id}
remove_member(request, **kwargs)
elif members_to_add:
kwargs = {'existing_members': existing_members,
'members_to_add': members_to_add,
'members_to_delete': members_to_delete,
'pool_id': pool_id}
add_member(request, **kwargs)
elif data.get('monitor'):
args = (request, loadbalancer_id, update_monitor)
thread.start_new_thread(poll_loadbalancer_status, args)
def get_members_to_add_remove(request_member_data, existing_members):
new_member_ids = [member['id'] for member in request_member_data]
existing_member_ids = [member['id'] for member in existing_members]
members_to_add = [member_id for member_id in new_member_ids
if member_id not in existing_member_ids]
members_to_delete = [member_id for member_id in existing_member_ids
if member_id not in new_member_ids]
return members_to_add, members_to_delete
def add_floating_ip_info(request, loadbalancers):
"""Add floating IP address info to each load balancer.
"""
if not loadbalancers:
return
floating_ips = neutron.tenant_floating_ip_list(request)
for lb in loadbalancers:
floating_ip = {}
associated_ip = next((fip for fip in floating_ips
if fip['port_id'] == lb['vip_port_id']), None)
if associated_ip is not None:
floating_ip['id'] = associated_ip['id']
floating_ip['ip'] = associated_ip['ip']
lb['floating_ip'] = floating_ip
@urls.register
class LoadBalancers(generic.View):
"""API for load balancers.
"""
url_regex = r'lbaas/loadbalancers/$'
@rest_utils.ajax()
def get(self, request):
"""List load balancers for current project.
The listing result is an object with property "items".
"""
conn = get_sdk_connection(request)
lb_list = _sdk_object_to_list(conn.load_balancer.load_balancers(
project_id=request.user.project_id))
if request.GET.get('full') and neutron.floating_ip_supported(request):
add_floating_ip_info(request, lb_list)
return {'items': lb_list}
@rest_utils.ajax()
def post(self, request):
"""Create a new load balancer.
Creates a new load balancer as well as other optional resources such as
a listener, pool, monitor, etc.
"""
return create_loadbalancer(request)
@urls.register
class LoadBalancer(generic.View):
"""API for retrieving, updating, and deleting a single load balancer.
"""
url_regex = r'lbaas/loadbalancers/(?P<loadbalancer_id>[^/]+)/$'
@rest_utils.ajax()
def get(self, request, loadbalancer_id):
"""Get a specific load balancer.
http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
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):
add_floating_ip_info(request, [loadbalancer_dict])
return loadbalancer_dict
@rest_utils.ajax()
def put(self, request, loadbalancer_id):
"""Edit a load balancer.
"""
kwargs = {'loadbalancer_id': loadbalancer_id}
update_loadbalancer(request, **kwargs)
@rest_utils.ajax()
def delete(self, request, loadbalancer_id):
"""Delete a specific load balancer.
http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
conn.load_balancer.delete_load_balancer(loadbalancer_id,
ignore_missing=True,
cascade=True)
@urls.register
class Listeners(generic.View):
"""API for load balancer listeners.
"""
url_regex = r'lbaas/listeners/$'
@rest_utils.ajax()
def get(self, request):
"""List of listeners for the current project.
The listing result is an object with property "items".
"""
loadbalancer_id = request.GET.get('loadbalancerId')
conn = get_sdk_connection(request)
listener_list = _sdk_object_to_list(conn.load_balancer.listeners(
project_id=request.user.project_id))
if loadbalancer_id:
listener_list = self._filter_listeners(listener_list,
loadbalancer_id)
return {'items': listener_list}
@rest_utils.ajax()
def post(self, request):
"""Create a new listener.
Creates a new listener as well as other optional resources such as
a pool, members, and health monitor.
"""
kwargs = {'loadbalancer_id': request.DATA.get('loadbalancer_id')}
return create_listener(request, **kwargs)
def _filter_listeners(self, listener_list, loadbalancer_id):
filtered_listeners = []
for listener in listener_list:
if listener['load_balancers'][0]['id'] == loadbalancer_id:
filtered_listeners.append(listener)
return filtered_listeners
@urls.register
class Listener(generic.View):
"""API for retrieving, updating, and deleting a single listener.
"""
url_regex = r'lbaas/listeners/(?P<listener_id>[^/]+)/$'
@rest_utils.ajax()
def get(self, request, listener_id):
"""Get a specific listener.
If the param 'includeChildResources' is passed in as a truthy value,
the details of all resources that exist under the listener will be
returned along with the listener details.
http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
listener = conn.load_balancer.find_listener(listener_id)
listener = _get_sdk_object_dict(listener)
if request.GET.get('includeChildResources'):
resources = {}
resources['listener'] = listener
if listener.get('default_pool_id'):
pool_id = listener['default_pool_id']
pool = conn.load_balancer.find_pool(pool_id)
pool = _get_sdk_object_dict(pool)
resources['pool'] = pool
if pool.get('members'):
member_list = _sdk_object_to_list(
conn.load_balancer.members(pool_id))
resources['members'] = member_list
if pool.get('health_monitor_id'):
monitor_id = pool['health_monitor_id']
monitor = conn.load_balancer.find_health_monitor(
monitor_id)
monitor = _get_sdk_object_dict(monitor)
resources['monitor'] = monitor
return resources
else:
return listener
@rest_utils.ajax()
def put(self, request, listener_id):
"""Edit a listener as well as any resources below it.
"""
kwargs = {'listener_id': listener_id}
update_listener(request, **kwargs)
@rest_utils.ajax()
def delete(self, request, listener_id):
"""Delete a specific listener.
http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
retry_on_conflict(
conn, conn.load_balancer.delete_listener,
listener_id, ignore_missing=True,
load_balancer_getter=listener_get_load_balancer_id,
resource_id=listener_id)
@urls.register
class L7Policies(generic.View):
"""API for load balancer l7 policies.
"""
url_regex = r'lbaas/l7policies/$'
@rest_utils.ajax()
def get(self, request):
"""List of l7 policies for the current project.
The listing result is an object with property "items".
"""
listener_id = request.GET.get('listenerId')
conn = get_sdk_connection(request)
l7_policy_list = _sdk_object_to_list(conn.load_balancer.l7_policies(
listener_id=listener_id))
return {'items': l7_policy_list}
@rest_utils.ajax()
def post(self, request):
"""Create a new l7 policy.
Creates a new l7 policy as well as other optional resources such as
l7 rules.
"""
kwargs = {'listener_id': request.DATA.get('parentResourceId')}
return create_l7_policy(request, **kwargs)
@urls.register
class L7Policy(generic.View):
"""API for retrieving a single l7 policy.
"""
url_regex = r'lbaas/l7policies/(?P<l7_policy_id>[^/]+)/$'
@rest_utils.ajax()
def get(self, request, l7_policy_id):
"""Get a specific l7 policy.
If the param 'includeChildResources' is passed in as a truthy value,
the details of all resources that exist under the l7 policy will be
returned along with the l7 policy details.
http://localhost/api/lbaas/l7policies/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
l7_policy = conn.load_balancer.find_l7_policy(l7_policy_id)
l7_policy = _get_sdk_object_dict(l7_policy)
if request.GET.get('includeChildResources'):
resources = {}
if l7_policy.get('rules'):
l7_rules_list = _sdk_object_to_list(
conn.load_balancer.l7_rules(l7_policy_id))
l7_policy['rules'] = l7_rules_list
resources['l7policy'] = l7_policy
return resources
else:
return l7_policy
@rest_utils.ajax()
def put(self, request, l7_policy_id):
"""Edit a l7 policy as well as any resources below it.
"""
kwargs = {'l7_policy_id': l7_policy_id}
update_l7_policy(request, **kwargs)
@rest_utils.ajax()
def delete(self, request, l7_policy_id):
"""Delete a specific l7 policy.
http://localhost/api/lbaas/l7policies/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
retry_on_conflict(
conn, conn.load_balancer.delete_l7_policy,
l7_policy_id,
load_balancer_getter=l7_policy_get_load_balancer_id,
resource_id=l7_policy_id)
@urls.register
class L7Rules(generic.View):
"""API for load balancer l7 rules.
"""
url_regex = r'lbaas/l7policies/(?P<l7_policy_id>[^/]+)/l7rules/$'
@rest_utils.ajax()
def get(self, request, l7_policy_id):
"""List of l7 rules for the current project.
The listing result is an object with property "items".
"""
conn = get_sdk_connection(request)
l7_rule_list = _sdk_object_to_list(conn.load_balancer.l7_rules(
l7_policy_id))
return {'items': l7_rule_list}
@rest_utils.ajax()
def post(self, request, l7_policy_id):
"""Create a new l7 rule.
Creates a new l7 rule as well as other optional resources such as
l7 rules.
"""
kwargs = {'l7_policy_id': l7_policy_id}
return create_l7_rule(request, **kwargs)
@urls.register
class L7Rule(generic.View):
"""API for retrieving a single l7 rule.
"""
url_regex = (
r'lbaas/l7policies/(?P<l7_policy_id>[^/]+)'
r'/l7rules/(?P<l7_rule_id>[^/]+)/$'
)
@rest_utils.ajax()
def get(self, request, l7_rule_id, l7_policy_id):
"""Get a specific l7 rule."""
conn = get_sdk_connection(request)
l7_rule = conn.load_balancer.find_l7_rule(l7_rule_id, l7_policy_id)
return _get_sdk_object_dict(l7_rule)
@rest_utils.ajax()
def put(self, request, l7_rule_id, l7_policy_id):
"""Edit a specific l7 rule."""
kwargs = {'l7_rule_id': l7_rule_id, 'l7_policy_id': l7_policy_id}
update_l7_rule(request, **kwargs)
@rest_utils.ajax()
def delete(self, request, l7_rule_id, l7_policy_id):
"""Delete a specific l7 rule."""
conn = get_sdk_connection(request)
retry_on_conflict(
conn, conn.load_balancer.delete_l7_rule,
l7_rule_id, l7_policy_id,
load_balancer_getter=l7_policy_get_load_balancer_id,
resource_id=l7_policy_id)
@urls.register
class Pools(generic.View):
"""API for load balancer pools.
"""
url_regex = r'lbaas/pools/$'
@rest_utils.ajax()
def get(self, request):
"""List of pools for the current project.
The listing result is an object with property "items".
"""
loadbalancer_id = request.GET.get('loadbalancerId')
listener_id = request.GET.get('listenerId')
conn = get_sdk_connection(request)
pool_list = _sdk_object_to_list(conn.load_balancer.pools(
project_id=request.user.project_id))
if loadbalancer_id or listener_id:
pool_list = self._filter_pools(pool_list,
loadbalancer_id,
listener_id)
return {'items': pool_list}
@rest_utils.ajax()
def post(self, request):
"""Create a new pool.
Creates a new pool as well as other optional resources such as
members and health monitor.
"""
kwargs = {'loadbalancer_id': request.DATA.get('loadbalancer_id'),
'listener_id': request.DATA.get('parentResourceId')}
return create_pool(request, **kwargs)
def _filter_pools(self, pool_list, loadbalancer_id, listener_id):
filtered_pools = []
for pool in pool_list:
if loadbalancer_id:
if pool['loadbalancers'][0]['id'] == loadbalancer_id:
if listener_id:
if (pool['listeners'] and
pool['listeners'][0]['id'] == listener_id):
filtered_pools.append(pool)
else:
filtered_pools.append(pool)
elif (pool['listeners'] and
pool['listeners'][0]['id'] == listener_id):
filtered_pools.append(pool)
return filtered_pools
@urls.register
class Pool(generic.View):
"""API for retrieving a single pool.
"""
url_regex = r'lbaas/pools/(?P<pool_id>[^/]+)/$'
@rest_utils.ajax()
def get(self, request, pool_id):
"""Get a specific pool.
If the param 'includeChildResources' is passed in as a truthy value,
the details of all resources that exist under the pool will be
returned along with the pool details.
http://localhost/api/lbaas/pools/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
pool = conn.load_balancer.find_pool(pool_id)
pool = _get_sdk_object_dict(pool)
if request.GET.get('includeChildResources'):
resources = {}
resources['pool'] = pool
if pool.get('members'):
member_list = _sdk_object_to_list(
conn.load_balancer.members(pool_id))
resources['members'] = member_list
if pool.get('health_monitor_id'):
monitor_id = pool['health_monitor_id']
monitor = conn.load_balancer.find_health_monitor(
monitor_id)
monitor = _get_sdk_object_dict(monitor)
resources['monitor'] = monitor
return resources
else:
return pool
@rest_utils.ajax()
def put(self, request, pool_id):
"""Edit a listener as well as any resources below it.
"""
kwargs = {'pool_id': pool_id}
update_pool(request, **kwargs)
@rest_utils.ajax()
def delete(self, request, pool_id):
"""Delete a specific pool.
http://localhost/api/lbaas/pools/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
retry_on_conflict(
conn, conn.load_balancer.delete_pool,
pool_id,
load_balancer_getter=pool_get_load_balancer_id,
resource_id=pool_id)
@urls.register
class Members(generic.View):
"""API for load balancer members.
"""
url_regex = r'lbaas/pools/(?P<pool_id>[^/]+)/members/$'
@rest_utils.ajax()
def get(self, request, pool_id):
"""List of members for the current project.
The listing result is an object with property "items".
"""
conn = get_sdk_connection(request)
members_list = _sdk_object_to_list(conn.load_balancer.members(pool_id))
return {'items': members_list}
@rest_utils.ajax()
def put(self, request, pool_id):
"""Update the list of members for the current project.
"""
# Assemble the lists of member id's to add and remove, if any exist
request_member_data = request.DATA.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(
request_member_data, existing_members)
if members_to_add or members_to_delete:
kwargs = {'existing_members': existing_members,
'members_to_add': members_to_add,
'members_to_delete': members_to_delete,
'pool_id': pool_id}
update_member_list(request, **kwargs)
@urls.register
class Member(generic.View):
"""API for retrieving a single member.
"""
url_regex = r'lbaas/pools/(?P<pool_id>[^/]+)' + \
'/members/(?P<member_id>[^/]+)/$'
@rest_utils.ajax()
def get(self, request, member_id, pool_id):
"""Get a specific member belonging to a specific pool.
"""
conn = get_sdk_connection(request)
member = conn.load_balancer.find_member(member_id, pool_id)
return _get_sdk_object_dict(member)
@rest_utils.ajax()
def delete(self, request, member_id, pool_id):
"""Delete a specific member belonging to a specific pool.
"""
conn = get_sdk_connection(request)
retry_on_conflict(
conn, conn.load_balancer.delete_member,
member_id, pool_id,
load_balancer_getter=pool_get_load_balancer_id,
resource_id=pool_id)
@rest_utils.ajax()
def put(self, request, member_id, pool_id):
"""Edit a pool member.
"""
data = request.DATA
conn = get_sdk_connection(request)
monitor_address = data.get('monitor_address')
member = conn.load_balancer.update_member(
member_id, pool_id, weight=data.get('weight'),
monitor_address=monitor_address if monitor_address else None,
monitor_port=data.get('monitor_port'),
admin_state_up=data.get('admin_state_up'),
backup=data.get('backup', False),
name=data.get('name'),
)
return _get_sdk_object_dict(member)
@urls.register
class HealthMonitors(generic.View):
"""API for load balancer pool health monitors.
"""
url_regex = r'lbaas/healthmonitors/$'
@rest_utils.ajax()
def get(self, request):
"""List of health monitors for the current project.
The listing result is an object with property "items".
"""
pool_id = request.GET.get('poolId')
conn = get_sdk_connection(request)
health_monitor_list = _sdk_object_to_list(
conn.load_balancer.health_monitors(
project_id=request.user.project_id
)
)
if pool_id:
health_monitor_list = self._filter_health_monitors(
health_monitor_list,
pool_id)
return {'items': health_monitor_list}
@rest_utils.ajax()
def post(self, request):
"""Create a new health monitor.
"""
kwargs = {'loadbalancer_id': request.DATA.get('loadbalancer_id'),
'pool_id': request.DATA.get('parentResourceId')}
return create_health_monitor(request, **kwargs)
def _filter_health_monitors(self, health_monitor_list, pool_id):
filtered_health_monitors = []
for health_monitor in health_monitor_list:
if health_monitor['pools'][0]['id'] == pool_id:
filtered_health_monitors.append(health_monitor)
return filtered_health_monitors
@urls.register
class HealthMonitor(generic.View):
"""API for retrieving a single health monitor.
"""
url_regex = r'lbaas/healthmonitors/(?P<health_monitor_id>[^/]+)/$'
@rest_utils.ajax()
def get(self, request, health_monitor_id):
"""Get a specific health monitor.
"""
conn = get_sdk_connection(request)
health_mon = conn.load_balancer.find_health_monitor(health_monitor_id)
return _get_sdk_object_dict(health_mon)
@rest_utils.ajax()
def delete(self, request, health_monitor_id):
"""Delete a specific health monitor.
http://localhost/api/lbaas/healthmonitors/cc758c90-3d98-4ea1-af44-aab405c9c915
"""
conn = get_sdk_connection(request)
retry_on_conflict(
conn, conn.load_balancer.delete_health_monitor,
health_monitor_id,
ignore_missing=True,
load_balancer_getter=health_monitor_get_load_balancer_id,
resource_id=health_monitor_id)
@rest_utils.ajax()
def put(self, request, health_monitor_id):
"""Edit a health monitor.
"""
update_monitor(request)
@urls.register
class Flavors(generic.View):
"""API for load balancer flavors.
"""
url_regex = r'lbaas/flavors/$'
@rest_utils.ajax()
def get(self, request):
"""List of flavors for the current project.
The listing result is an object with property "items".
"""
conn = get_sdk_connection(request)
flavor_list = _sdk_object_to_list(
conn.load_balancer.flavors()
)
return {'items': flavor_list}
@rest_utils.ajax()
def post(self, request):
"""Create a new flavor.
"""
kwargs = {
'flavor': request.DATA.get('flavor')
}
return create_flavor(request, **kwargs)
@urls.register
class Flavor(generic.View):
"""API for retrieving a single flavor.
"""
url_regex = r'lbaas/flavors/(?P<flavor_id>[^/]+)/$'
@rest_utils.ajax()
def get(self, request, flavor_id):
"""Get a specific flavor.
"""
conn = get_sdk_connection(request)
flavor = conn.load_balancer.find_flavor(flavor_id)
return _get_sdk_object_dict(flavor)
@rest_utils.ajax()
def delete(self, request, flavor_id):
"""Delete a specific flavor.
http://localhost/api/lbaas/flavors/3971d368-ca9b-4770-929a-3adca5bf89eb
"""
conn = get_sdk_connection(request)
conn.load_balancer.delete_flavor(flavor_id,
ignore_missing=True)
@rest_utils.ajax()
def put(self, request, flavor_id):
"""Edit a flavor.
"""
update_flavor(request)
@urls.register
class FlavorProfiles(generic.View):
"""API for load balancer flavor profiles.
"""
url_regex = r'lbaas/flavorprofiles/$'
@rest_utils.ajax()
def get(self, request):
"""List of flavor profiles for the current project.
The listing result is an object with property "items".
"""
conn = get_sdk_connection(request)
flavor_profile_list = _sdk_object_to_list(
conn.load_balancer.flavor_profiles()
)
return {'items': flavor_profile_list}
@rest_utils.ajax()
def post(self, request):
"""Create a new flavor_profile.
"""
kwargs = {
'flavor_profile': request.DATA.get('flavor_profile')
}
return create_flavor_profile(request, **kwargs)
@urls.register
class FlavorProfile(generic.View):
"""API for retrieving a single flavor profile.
"""
url_regex = r'lbaas/flavorprofiles/(?P<flavor_profile_id>[^/]+)/$'
@rest_utils.ajax()
def get(self, request, flavor_profile_id):
"""Get a specific flavor profile.
"""
conn = get_sdk_connection(request)
flavor_profile = conn.load_balancer.find_flavor_profile(
flavor_profile_id)
return _get_sdk_object_dict(flavor_profile)
@rest_utils.ajax()
def delete(self, request, flavor_profile_id):
"""Delete a specific flavor profile.
http://localhost/api/lbaas/flavorprofiles/e8150eab-aefa-42cc-867e-3fb336da52bd
"""
conn = get_sdk_connection(request)
conn.load_balancer.delete_flavor_profile(flavor_profile_id,
ignore_missing=True)
@rest_utils.ajax()
def put(self, request, flavor_profile_id):
"""Edit a flavor profile.
"""
update_flavor_profile(request)
@urls.register
class AvailabilityZones(generic.View):
"""API for load balancer availability zones.
"""
url_regex = r'lbaas/availabilityzones/$'
@rest_utils.ajax()
def get(self, request):
"""List of availability zones for the current project.
The listing result is an object with property "items".
"""
conn = get_sdk_connection(request)
availability_zone_list = _sdk_object_to_list(
conn.load_balancer.availability_zones()
)
return {'items': availability_zone_list}