octavia-dashboard/octavia_dashboard/api/lbaasv2.py

683 lines
26 KiB
Python

# Copyright 2015, eBay Inc.
#
# 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 __future__ import absolute_import
import collections
from django.utils.translation import ugettext_lazy as _
from horizon import messages
from openstack_dashboard.api import neutron
neutronclient = neutron.neutronclient
class LBDetails(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer vip."""
def __init__(self, vip, listener=None, pool=None, members=None,
monitors=None, profile_name=None, cert=None, key=None,
chain=None):
vip['pool'] = pool
pool['members'] = members
pool['monitors'] = monitors
# vip['cert_name'] = cert_name
vip['listener'] = listener
vip['cert'] = cert
vip['key'] = key
vip['chain'] = chain
vip['profile_name'] = profile_name
super(LBDetails, self).__init__(vip)
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
def convert_status(self, value):
return "Enabled" if value else "Disabled"
def readable(self, request=None):
pFormatted = {'id': self.id,
'name': self.name,
'dns_name': self.name,
# 'lb_method': self.lb_method,
'description': self.description,
# 'protocol': self.protocol,
'address': self.vip_address,
# 'port': self.port,
'enabled': self.convert_status(self.admin_state_up),
'use_common_cert': False,
'provisioning_status': self.provisioning_status,
'operating_status': self.operating_status,
# 'monitor' : self.monitor
}
# status_string = 'vip: %s' % self['status'].lower()
pFormatted['status'] = 'na'
# if self.profile_name:
# try:
# if self.profile_name.upper() ==
# _construct_common_cert_profile_name(request).upper():
# pFormatted['use_common_cert'] = True
# pFormatted['cert_name'] = self.profile_name
# else:
# pFormatted['use_common_cert'] = False
# pFormatted['cert_name'] = self.profile_name
# pFormatted['cert'] = self.cert
# pFormatted['private_key'] = self.key
# pFormatted['chain_cert'] = self.chain
# except Exception as e:
# LOG.error("unable to read cert")
if self.listener is not None:
try:
listener = self.AttributeDict(self.listener)
pFormatted['protocol'] = listener.protocol
pFormatted['port'] = listener.protocol_port
except Exception:
pass
if self.pool is not None:
try:
pool = self.AttributeDict(self.pool)
# status_string = '%s \n pool: %s' % (pFormatted['status'],
# pool['status'].lower())
# pFormatted['status'] = status_string
pFormatted['pool'] = pool
pFormatted['pool_id'] = pool.id
pFormatted['lb_method'] = pool.lb_algorithm
if pool.members is not None:
try:
ips = []
pool_members = []
for m in pool.members:
member = self.AttributeDict(m)
pFormatted['instance_port'] = member.protocol_port
pool_member = member
pool_member.port = member.protocol_port
pool_members.append(pool_member)
ips.append(member.address)
pFormatted['pool']['members'] = pool_members
pFormatted['members'] = ips
except Exception:
pass # ignore
if pool.monitors is not None:
try:
for m in pool.monitors:
monitor = self.AttributeDict(m)
# monitor_status =_get_monitor_status(pool['id'],m)
# status_string = '%s \n monitor: %s' %
# (pFormatted['status'], monitor_status.lower())
# pFormatted['status'] = status_string
interval = int(monitor.delay)
# timeout = int(monitor.timeout)
retry = int(monitor.max_retries)
monitor_type = 'http-ecv'
# if monitor.name.upper() in basic_monitors:
# monitor_type = monitor.name
monitor_type = monitor.name
pFormatted['pool']['monitor'] = monitor_type
pFormatted['monitor'] = monitor_type
pFormatted['interval'] = interval
pFormatted['timeout'] = retry
pFormatted['send'] = monitor.url_path \
if hasattr(monitor, 'url_path') else ''
pFormatted['receive'] = monitor.response_string \
if hasattr(monitor, 'response_string') else ''
break
except Exception:
pass # ignore
except Exception:
pass # ignore
if 'cert_name' not in pFormatted:
pFormatted['cert_name'] = ''
if 'cert' not in pFormatted:
pFormatted['cert'] = ''
if 'private_key' not in pFormatted:
pFormatted['private_key'] = ''
if 'chain_cert' not in pFormatted:
pFormatted['chain_cert'] = ''
if 'pool_id' not in pFormatted:
pFormatted['pool_id'] = 'UNKNOWN'
if 'lb_method' not in pFormatted:
pFormatted['lb_method'] = 'UNKNOWN'
if 'monitor' not in pFormatted:
pFormatted['monitor'] = 'None'
# if 'monitor' not in pFormatted['pool']:
# pFormatted['pool']['monitor'] = 'None'
if 'interval' not in pFormatted:
pFormatted['interval'] = 1
if 'timeout' not in pFormatted:
pFormatted['timeout'] = 1
if 'send' not in pFormatted:
pFormatted['send'] = None
if 'receive' not in pFormatted:
pFormatted['receive'] = None
if 'members' not in pFormatted:
pFormatted['members'] = []
if 'instance_port' not in pFormatted:
pFormatted['instance_port'] = ''
return self.AttributeDict(pFormatted)
class Vip(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer vip."""
def __init__(self, apiresource):
super(Vip, self).__init__(apiresource)
class Pool(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer pool."""
def __init__(self, apiresource):
if 'provider' not in apiresource:
apiresource['provider'] = None
super(Pool, self).__init__(apiresource)
class Member(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer member."""
def __init__(self, apiresource):
super(Member, self).__init__(apiresource)
class PoolStats(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer pool stats."""
def __init__(self, apiresource):
super(PoolStats, self).__init__(apiresource)
class PoolMonitor(neutron.NeutronAPIDictWrapper):
"""Wrapper for neutron load balancer pool health monitor."""
def __init__(self, apiresource):
super(PoolMonitor, self).__init__(apiresource)
def vip_create(request, **kwargs):
"""Create a vip for a specified pool.
:param request: request context
:param address: virtual IP address
:param name: name for vip
:param description: description for vip
:param subnet_id: subnet_id for subnet of vip
:param protocol_port: transport layer port number for vip
:returns: Vip object
"""
body = {'vip': {'name': kwargs['name'],
'description': kwargs['description'],
'subnet_id': kwargs['subnet_id'],
'protocol_port': kwargs['protocol_port'],
'protocol': kwargs['protocol'],
'pool_id': kwargs['pool_id'],
'session_persistence': kwargs['session_persistence'],
'admin_state_up': kwargs['admin_state_up']
}}
if kwargs.get('connection_limit'):
body['vip']['connection_limit'] = kwargs['connection_limit']
if kwargs.get('address'):
body['vip']['address'] = kwargs['address']
vip = neutronclient(request).create_vip(body).get('vip')
return Vip(vip)
def vip_list(request, **kwargs):
vips = neutronclient(request).list_vips(**kwargs).get('vips')
return [Vip(v) for v in vips]
def create_loadbalancer_full(request, **kwargs):
loadbalancer_body = {'loadbalancer': {'name': kwargs['name'],
'description': kwargs['description'],
'vip_subnet_id': kwargs['subnet_id'],
'admin_state_up':
kwargs['admin_state_up'],
'vip_address': kwargs['address'],
# 'provider': 'HAProxy'
}}
listener_body = {'listener': {'name': kwargs['name'],
'description': kwargs['description'],
'protocol': kwargs['protocol'],
'protocol_port': kwargs['protocol_port'],
'default_tls_container_id': None,
'sni_container_ids': [],
'connection_limit': 100,
'admin_state_up': kwargs['admin_state_up'],
'loadbalancer_id': None}}
pool_body = {'pool': {'name': kwargs['name'],
'description': kwargs['description'],
'protocol': kwargs['protocol'],
'lb_method': kwargs['lb_method'],
'admin_state_up': kwargs['admin_state_up']
}}
member_body = {'member': {'pool_id': kwargs['pool_id'],
'address': kwargs['address'],
'protocol_port': kwargs['protocol_port'],
'admin_state_up': kwargs['admin_state_up'],
'pool_id': None
}}
if kwargs.get('weight'):
member_body['member']['weight'] = kwargs['weight']
monitor_type = kwargs['type'].upper()
health_monitor_body = {'health_monitor': {'tenant_id': kwargs['tenant_id'],
'type': monitor_type,
'delay': kwargs['delay'],
'timeout': kwargs['timeout'],
'max_retries':
kwargs['max_retries'],
'admin_state_up':
kwargs['admin_state_up'],
'pool_id': None
}
}
if monitor_type in ['HTTP', 'HTTPS']:
health_mon = health_monitor_body['health_monitor']
health_mon['http_method'] = kwargs['http_method']
health_mon['url_path'] = kwargs['url_path']
health_mon['expected_codes'] = kwargs['expected_codes']
try:
client = neutronclient(request)
loadbalancer = client.\
create_loadbalancer(loadbalancer_body).get('loadbalancer')
listener_body['listener']['loadbalancer_id'] = loadbalancer['id']
listener = client.\
create_listener(listener_body).get('listener')
pool = client.create_lbaas_pool(pool_body).get('pool')
member_body['member']['pool_id'] = pool['id']
health_monitor_body['health_monitor']['pool_id'] = pool['id']
health_monitor = client.create_lbaas_healthmonitor(health_monitor_body)\
.get('health_monitor')
member = client.create_lbaas_member(member_body).get('member')
except Exception:
raise Exception(_("Could not create full loadbalancer."))
return [LBDetails(loadbalancer, listener, pool, member, health_monitor)]
def list_loadbalancers(request, **kwargs):
vips = neutronclient(request).list_loadbalancers(**kwargs)
vips = [] if not vips else vips
vips = vips.get('loadbalancers')
lbaas_list = []
for vip in vips:
listeners = vip.get('listeners')
listeners = [] if not listeners else listeners
for listener in listeners:
listener = neutronclient(request).show_listener(listener.get('id'),
**kwargs)
if not listener:
continue
listener = listener.get('listener')
try:
pool = neutronclient(request).\
show_lbaas_pool(listener.get('default_pool_id'), **kwargs)
if not pool:
continue
pool = pool.get('pool')
if pool.get('healthmonitor_id'):
health_monitor = neutronclient(request).\
show_lbaas_healthmonitor(pool.get('healthmonitor_id'),
**kwargs)
health_monitor = health_monitor.get('healthmonitor')
else:
health_monitor = None
members = neutronclient(request).\
list_lbaas_members(listener.get('default_pool_id'),
**kwargs)
lbaas_list.append(LBDetails(vip, listener, pool,
members, health_monitor))
except Exception:
raise Exception(_("Could not get load balancer list."))
return lbaas_list
def show_loadbalancer(request, lbaas_loadbalancer, **kwargs):
vip = neutronclient(request).show_loadbalancer(lbaas_loadbalancer,
**kwargs)
if not vip:
return
loadbalancer = vip.get('loadbalancer')
viplisteners = loadbalancer.get('listeners')
if not viplisteners:
return
for viplistener in viplisteners:
listener = neutronclient(request).\
show_listener(viplistener.get('id'), **kwargs)
if not listener:
continue
listener = listener.get('listener')
pool = neutronclient(request).\
show_lbaas_pool(listener.get('default_pool_id'), **kwargs)
if not pool:
continue
pool = pool.get('pool')
health_monitor = None
if pool.get('healthmonitor_id'):
health_monitor = neutronclient(request).\
show_lbaas_healthmonitor(pool.get('healthmonitor_id'),
**kwargs)
health_monitor = health_monitor.get('healthmonitor')
members = neutronclient(request).\
list_lbaas_members(listener.get('default_pool_id'), **kwargs)
return LBDetails(vip.get('loadbalancer'), listener, pool, members,
health_monitor)
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)
def vip_update(request, vip_id, **kwargs):
vip = neutronclient(request).update_vip(vip_id, kwargs).get('vip')
return Vip(vip)
def vip_delete(request, vip_id):
neutronclient(request).delete_vip(vip_id)
def pool_create(request, **kwargs):
"""Create a pool for specified protocol
:param request: request context
:param name: name for pool
:param description: description for pool
:param subnet_id: subnet_id for subnet of pool
:param protocol: load balanced protocol
:param lb_method: load balancer method
:param admin_state_up: admin state (default on)
"""
body = {'pool': {'name': kwargs['name'],
'description': kwargs['description'],
'subnet_id': kwargs['subnet_id'],
'protocol': kwargs['protocol'],
'lb_method': kwargs['lb_method'],
'admin_state_up': kwargs['admin_state_up'],
'provider': kwargs['provider'],
}}
pool = neutronclient(request).create_pool(body).get('pool')
return Pool(pool)
def _get_vip(request, pool, vip_dict, expand_name_only=False):
if pool['vip_id'] is not None:
try:
if vip_dict:
vip = vip_dict.get(pool['vip_id'])
else:
vip = _vip_get(request, pool['vip_id'])
except Exception:
messages.warning(request, _("Unable to get VIP for pool "
"%(pool)s.") % {"pool": pool["id"]})
vip = Vip({'id': pool['vip_id'], 'name': ''})
if expand_name_only:
vip = vip.name_or_id
return vip
else:
return None
def pool_list(request, **kwargs):
return _pool_list(request, expand_subnet=True, expand_vip=True, **kwargs)
def _pool_list(request, expand_subnet=False, expand_vip=False, **kwargs):
pools = neutronclient(request).list_pools(**kwargs).get('pools')
if expand_subnet:
subnets = neutron.subnet_list(request)
subnet_dict = collections.OrderedDict((s.id, s) for s in subnets)
for p in pools:
subnet = subnet_dict.get(p['subnet_id'])
p['subnet_name'] = subnet.cidr if subnet else None
if expand_vip:
vips = vip_list(request)
vip_dict = collections.OrderedDict((v.id, v) for v in vips)
for p in pools:
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_resource=True)
def _pool_get(request, pool_id, expand_resource=False):
try:
pool = neutronclient(request).show_pool(pool_id).get('pool')
except Exception:
messages.warning(request, _("Unable to get pool detail."))
return None
if expand_resource:
# TODO(lyj): The expand resource(subnet, member etc.) attached
# to a pool could be deleted without cleanup pool related database,
# this will cause exceptions if we trying to get the deleted resources.
# so we need to handle the situation by showing a warning message here.
# we can safely remove the try/except once the neutron bug is fixed
# https://bugs.launchpad.net/neutron/+bug/1406854
try:
pool['subnet'] = neutron.subnet_get(request, pool['subnet_id'])
except Exception:
messages.warning(request, _("Unable to get subnet for pool "
"%(pool)s.") % {"pool": pool_id})
pool['vip'] = _get_vip(request, pool, vip_dict=None,
expand_name_only=False)
try:
pool['members'] = _member_list(request, expand_pool=False,
pool_id=pool_id)
except Exception:
messages.warning(request, _("Unable to get members for pool "
"%(pool)s.") % {"pool": pool_id})
try:
pool['health_monitors'] = pool_health_monitor_list(
request, id=pool['health_monitors'])
except Exception:
messages.warning(request,
_("Unable to get health monitors "
"for pool %(pool)s.") % {"pool": pool_id})
return Pool(pool)
def pool_update(request, pool_id, **kwargs):
pool = neutronclient(request).update_pool(pool_id, kwargs).get('pool')
return Pool(pool)
def pool_delete(request, pool):
neutronclient(request).delete_pool(pool)
# not linked to UI yet
def pool_stats(request, pool_id, **kwargs):
stats = neutronclient(request).retrieve_pool_stats(pool_id, **kwargs)
return PoolStats(stats)
def pool_health_monitor_create(request, **kwargs):
"""Create a health monitor
:param request: request context
:param type: type of monitor
:param delay: delay of monitor
:param timeout: timeout of monitor
:param max_retries: max retries [1..10]
:param http_method: http method
:param url_path: url path
:param expected_codes: http return code
:param admin_state_up: admin state
"""
monitor_type = kwargs['type'].upper()
body = {'health_monitor': {'type': monitor_type,
'delay': kwargs['delay'],
'timeout': kwargs['timeout'],
'max_retries': kwargs['max_retries'],
'admin_state_up': kwargs['admin_state_up']
}}
if monitor_type in ['HTTP', 'HTTPS']:
body['health_monitor']['http_method'] = kwargs['http_method']
body['health_monitor']['url_path'] = kwargs['url_path']
body['health_monitor']['expected_codes'] = kwargs['expected_codes']
mon = neutronclient(request).create_health_monitor(body).get(
'health_monitor')
return PoolMonitor(mon)
def pool_health_monitor_list(request, **kwargs):
monitors = neutronclient(request).list_health_monitors(
**kwargs).get('health_monitors')
return [PoolMonitor(m) for m in monitors]
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)
def pool_health_monitor_update(request, monitor_id, **kwargs):
monitor = neutronclient(request).update_health_monitor(monitor_id, kwargs)
return PoolMonitor(monitor)
def pool_health_monitor_delete(request, mon_id):
neutronclient(request).delete_health_monitor(mon_id)
def member_create(request, **kwargs):
"""Create a load balance member
:param request: request context
:param pool_id: pool_id of pool for member
:param address: IP address
:param protocol_port: transport layer port number
:param weight: weight for member
:param admin_state_up: admin_state
"""
body = {'member': {'pool_id': kwargs['pool_id'],
'address': kwargs['address'],
'protocol_port': kwargs['protocol_port'],
'admin_state_up': kwargs['admin_state_up']
}}
if kwargs.get('weight'):
body['member']['weight'] = kwargs['weight']
member = neutronclient(request).create_member(body).get('member')
return Member(member)
def member_list(request, **kwargs):
return _member_list(request, expand_pool=True, **kwargs)
def _member_list(request, expand_pool, **kwargs):
members = neutronclient(request).list_members(**kwargs).get('members')
if expand_pool:
pools = _pool_list(request)
pool_dict = collections.OrderedDict((p.id, p) for p in pools)
for m in members:
m['pool_name'] = pool_dict.get(m['pool_id']).name_or_id
return [Member(m) for m in members]
def member_get(request, member_id):
return _member_get(request, member_id, expand_pool=True)
def _member_get(request, member_id, expand_pool):
member = neutronclient(request).show_member(member_id).get('member')
if expand_pool:
member['pool'] = _pool_get(request, member['pool_id'])
return Member(member)
def member_update(request, member_id, **kwargs):
member = neutronclient(request).update_member(member_id, kwargs)
return Member(member)
def member_delete(request, mem_id):
neutronclient(request).delete_member(mem_id)
def pool_monitor_association_create(request, **kwargs):
"""Associate a health monitor with pool
:param request: request context
:param monitor_id: id of monitor
:param pool_id: id of pool
"""
body = {'health_monitor': {'id': kwargs['monitor_id'], }}
neutronclient(request).associate_health_monitor(
kwargs['pool_id'], body)
def pool_monitor_association_delete(request, **kwargs):
"""Disassociate a health monitor from pool
:param request: request context
:param monitor_id: id of monitor
:param pool_id: id of pool
"""
neutronclient(request).disassociate_health_monitor(
kwargs['pool_id'], kwargs['monitor_id'])