Remove old unused code.
The octavia-dashboard repo had legacy code that is not used in the current version of the dashboard. This patch removes that code. Change-Id: Icf410babf285e2b5c55dd717f18a27b7cdc3eba3
This commit is contained in:
parent
d77592cdd6
commit
89674dbf29
@ -1,7 +1,6 @@
|
|||||||
[run]
|
[run]
|
||||||
branch = True
|
branch = True
|
||||||
source = neutron_lbaas_dashboard
|
source = octavia_dashboard
|
||||||
omit = neutron_lbaas_dashboard/openstack/*
|
|
||||||
|
|
||||||
[report]
|
[report]
|
||||||
ignore_errors = True
|
ignore_errors = True
|
||||||
|
@ -1 +0,0 @@
|
|||||||
from . import lbaasv2 # noqa
|
|
@ -1,682 +0,0 @@
|
|||||||
# 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'])
|
|
@ -1,36 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
|
|
||||||
class LBaaSException(Exception):
|
|
||||||
|
|
||||||
"""The base exception class for all exceptions this library raises.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, code, message=None, details=None, request_id=None,
|
|
||||||
url=None, method=None):
|
|
||||||
self.code = code
|
|
||||||
self.message = message or self.__class__.message
|
|
||||||
self.details = details
|
|
||||||
self.request_id = request_id
|
|
||||||
self.url = url
|
|
||||||
self.method = method
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
formatted_string = "%s (HTTP %s)" % (self.message, self.code)
|
|
||||||
if self.request_id:
|
|
||||||
formatted_string += " (Request-ID: %s)" % self.request_id
|
|
||||||
|
|
||||||
return formatted_string
|
|
@ -1,47 +0,0 @@
|
|||||||
# 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 django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
import horizon
|
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.project import dashboard
|
|
||||||
|
|
||||||
|
|
||||||
class LoadBalancersUI(horizon.Panel):
|
|
||||||
name = _("Load Balancers V2")
|
|
||||||
slug = 'loadbalancersv2'
|
|
||||||
permissions = ('openstack.services.network',)
|
|
||||||
|
|
||||||
def allowed(self, context):
|
|
||||||
# todo temporarily enabling panel for any user
|
|
||||||
# request = context['request']
|
|
||||||
# if not request.user.has_perms(self.permissions):
|
|
||||||
# return False
|
|
||||||
# try:
|
|
||||||
# if not neutron.is_service_enabled(request,
|
|
||||||
# config_name='enable_lb',
|
|
||||||
# ext_name='lbaas'):
|
|
||||||
# return False
|
|
||||||
# except Exception:
|
|
||||||
# LOG.error("Call to list enabled services failed. This is likely "
|
|
||||||
# "due to a problem communicating with the Neutron "
|
|
||||||
# "endpoint. Load Balancers panel will not be displayed")
|
|
||||||
# return False
|
|
||||||
# if not super(LoadBalancer, self).allowed(context):
|
|
||||||
# return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
dashboard.Project.register(LoadBalancersUI)
|
|
@ -1,189 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from django.core import urlresolvers
|
|
||||||
from django.template.defaultfilters import linebreaksbr
|
|
||||||
from django.utils.http import urlencode
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from horizon import tables
|
|
||||||
|
|
||||||
from octavia_dashboard import api
|
|
||||||
|
|
||||||
|
|
||||||
class TerminateLoadBalancer(tables.BatchAction):
|
|
||||||
name = "terminate"
|
|
||||||
action_present = _("Terminate")
|
|
||||||
action_past = _("Scheduled termination of")
|
|
||||||
data_type_singular = _("Load Balancer")
|
|
||||||
data_type_plural = _("Load Balancers")
|
|
||||||
classes = ('btn-danger', 'btn-terminate')
|
|
||||||
|
|
||||||
def allowed(self, request, loadbalancer=None):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def action(self, request, obj_id):
|
|
||||||
api.lbaasv2.vip_delete(request, obj_id)
|
|
||||||
|
|
||||||
|
|
||||||
class EnableLoadBalancer(tables.BatchAction):
|
|
||||||
name = "enable"
|
|
||||||
action_present = _("Enable")
|
|
||||||
action_past = _("Enabled LB")
|
|
||||||
data_type_singular = _("Load Balancer")
|
|
||||||
data_type_plural = _("Load Balancers")
|
|
||||||
classes = ('btn-enable', "btn-action-required")
|
|
||||||
action_failure = "error enable"
|
|
||||||
|
|
||||||
def allowed(self, request, loadbalancer=None):
|
|
||||||
if loadbalancer.admin_state_up:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def action(self, request, obj_id):
|
|
||||||
api.lbaasv2.vip_set_status(request, obj_id, True)
|
|
||||||
|
|
||||||
|
|
||||||
class DisableLoadBalancer(tables.BatchAction):
|
|
||||||
name = "disable"
|
|
||||||
action_present = _("Disable")
|
|
||||||
action_past = _("Disabled LB")
|
|
||||||
data_type_singular = _("Load Balancer")
|
|
||||||
data_type_plural = _("Load Balancers")
|
|
||||||
classes = ("btn-confirm", 'btn-disable',)
|
|
||||||
action_failure = "error disable"
|
|
||||||
|
|
||||||
def allowed(self, request, loadbalancer=None):
|
|
||||||
if loadbalancer.admin_state_up:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def action(self, request, obj_id):
|
|
||||||
api.lbaasv2.vip_set_status(request, obj_id, False)
|
|
||||||
|
|
||||||
|
|
||||||
class LaunchLink(tables.LinkAction):
|
|
||||||
name = "launch"
|
|
||||||
verbose_name = _("Launch Load Balancer")
|
|
||||||
url = "horizon:project:loadbalancersv2:launch"
|
|
||||||
classes = ("btn-launch", "ajax-modal")
|
|
||||||
|
|
||||||
def allowed(self, request, datum):
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class EditLoadBalancer(tables.LinkAction):
|
|
||||||
name = "edit"
|
|
||||||
verbose_name = _("Edit Load Balancer")
|
|
||||||
url = "horizon:project:loadbalancersv2:update"
|
|
||||||
classes = ("ajax-modal", "btn-edit")
|
|
||||||
|
|
||||||
def get_link_url(self, project):
|
|
||||||
return self._get_link_url(project, 'loadbalancer_info')
|
|
||||||
|
|
||||||
def _get_link_url(self, project, step_slug):
|
|
||||||
base_url = urlresolvers.reverse(self.url, args=[project.id])
|
|
||||||
param = urlencode({"step": step_slug})
|
|
||||||
return "?".join([base_url, param])
|
|
||||||
|
|
||||||
def allowed(self, request, loadbalancer):
|
|
||||||
# return not is_deleting(loadbalancer) when async is implemented
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateRow(tables.Row):
|
|
||||||
ajax = True
|
|
||||||
|
|
||||||
def get_data(self, request, loadbalancer_id):
|
|
||||||
loadbalancer = api.lbaasv2.vip_update(request, loadbalancer_id)
|
|
||||||
return loadbalancer
|
|
||||||
|
|
||||||
|
|
||||||
def convert_title(value):
|
|
||||||
return re.sub("([A-Z])", " \g<0>", value)
|
|
||||||
|
|
||||||
|
|
||||||
def convert_camel(value):
|
|
||||||
if not value:
|
|
||||||
return value
|
|
||||||
if value.isupper() or value.islower():
|
|
||||||
return value.title()
|
|
||||||
else:
|
|
||||||
value = value.replace(' ', '')
|
|
||||||
return re.sub("([A-Z])", " \g<0>", value)
|
|
||||||
|
|
||||||
|
|
||||||
def upper_case(value):
|
|
||||||
return value.upper()
|
|
||||||
|
|
||||||
|
|
||||||
def convert_status(value):
|
|
||||||
return "Enabled" if value else "Disabled"
|
|
||||||
|
|
||||||
|
|
||||||
def get_lb_method(value):
|
|
||||||
return value.pool['lb_algorithm']
|
|
||||||
|
|
||||||
|
|
||||||
def get_protocol(value):
|
|
||||||
return value.listener['protocol']
|
|
||||||
|
|
||||||
|
|
||||||
def get_monitor(value):
|
|
||||||
return value['pool']['monitors']['type']
|
|
||||||
|
|
||||||
|
|
||||||
def get_lb(instance):
|
|
||||||
if hasattr(instance, "vip_address"):
|
|
||||||
return "%s:%s" % (instance.vip_address,
|
|
||||||
instance.listener['protocol_port'])
|
|
||||||
return _("Not available")
|
|
||||||
|
|
||||||
|
|
||||||
class LoadBalancersTable(tables.DataTable):
|
|
||||||
vip = tables.Column(get_lb,
|
|
||||||
link=("horizon:project:loadbalancersv2:detail"),
|
|
||||||
verbose_name=_("Load Balancer"))
|
|
||||||
name = tables.Column("name",
|
|
||||||
link=("horizon:project:loadbalancersv2:detail"),
|
|
||||||
verbose_name=_("Name"))
|
|
||||||
lb_method = tables.Column(get_lb_method,
|
|
||||||
filters=(upper_case,),
|
|
||||||
verbose_name=_("Method"))
|
|
||||||
protocol = tables.Column(get_protocol,
|
|
||||||
filters=(upper_case,),
|
|
||||||
verbose_name=_("Protocol"))
|
|
||||||
monitor = tables.Column(get_monitor,
|
|
||||||
filters=(upper_case,),
|
|
||||||
verbose_name=_("Monitor"))
|
|
||||||
status = tables.Column("provisioning_status",
|
|
||||||
filters=(convert_camel, linebreaksbr),
|
|
||||||
verbose_name=_("Provisioning Status"))
|
|
||||||
operating_status = tables.Column("operating_status",
|
|
||||||
filters=(convert_camel, linebreaksbr),
|
|
||||||
verbose_name=_("Operating Status"))
|
|
||||||
enabled = tables.Column("admin_state_up",
|
|
||||||
filters=(convert_status,),
|
|
||||||
verbose_name=_("Admin Status"))
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = "loadbalancersv2"
|
|
||||||
verbose_name = _("Load Balancers")
|
|
||||||
row_class = UpdateRow
|
|
||||||
table_actions = (LaunchLink, TerminateLoadBalancer)
|
|
||||||
row_actions = (EditLoadBalancer, TerminateLoadBalancer,
|
|
||||||
EnableLoadBalancer, DisableLoadBalancer)
|
|
@ -1,33 +0,0 @@
|
|||||||
# 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 django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from horizon import tabs
|
|
||||||
|
|
||||||
|
|
||||||
class OverviewTab(tabs.Tab):
|
|
||||||
name = _("Overview")
|
|
||||||
slug = "overview"
|
|
||||||
template_name = ("project/loadbalancersv2/"
|
|
||||||
"_detail_overview.html")
|
|
||||||
|
|
||||||
def get_context_data(self, request):
|
|
||||||
return {"loadbalancer": self.tab_group.kwargs['loadbalancer']}
|
|
||||||
|
|
||||||
|
|
||||||
class LoadBalancerDetailTabs(tabs.TabGroup):
|
|
||||||
slug = "loadbalancer_details"
|
|
||||||
tabs = (OverviewTab, )
|
|
||||||
sticky = True
|
|
@ -1,50 +0,0 @@
|
|||||||
{% load i18n sizeformat %}
|
|
||||||
|
|
||||||
<h3>{% trans "Load Balancer Overview" %}</h3>
|
|
||||||
|
|
||||||
<div class="status row-fluid detail">
|
|
||||||
<h4>{% trans "Info" %}</h4>
|
|
||||||
<hr class="header_rule">
|
|
||||||
<dl>
|
|
||||||
<dt>{% trans "Name" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.name }}</dd>
|
|
||||||
<dt>{% trans "ID" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.id }}</dd>
|
|
||||||
<dt>{% trans "Address" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.address }}</dd>
|
|
||||||
<dt>{% trans "Port" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.port }}</dd>
|
|
||||||
<dt>{% trans "Protocol" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.protocol }}</dd>
|
|
||||||
<dt>{% trans "Load Balancing Method" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.lb_method }}</dd>
|
|
||||||
<dt>{% trans "Monitor" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.pool.monitors.type }}</dd>
|
|
||||||
<dt>{% trans "Operating Status" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.operating_status }}</dd>
|
|
||||||
<dt>{% trans "Provisioning Status" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.provisioning_status }}</dd>
|
|
||||||
<dt>{% trans "Description" %}</dt>
|
|
||||||
<dd> - {{ loadbalancer.description }}</dd>
|
|
||||||
<dt>{% trans "Admin Status" %}</dt>
|
|
||||||
<dd>{{ loadbalancer.enabled|title }}</dd>
|
|
||||||
{# <dt>{% trans "Load Balancing Method" %}</dt>#}
|
|
||||||
{# <dd>{{ loadbalancer.pool.lb_method }}</dd>#}
|
|
||||||
{# <dt>{% trans "Monitor" %}</dt>#}
|
|
||||||
{# <dd>{{ loadbalancer.pool.monitor }}</dd>#}
|
|
||||||
<dt>{% trans "Certificate" %}</dt>
|
|
||||||
<dd> - {{ loadbalancer.cert_name }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="members row-fluid detail">
|
|
||||||
<h4>{% trans "Members" %}</h4>
|
|
||||||
<hr class="header_rule">
|
|
||||||
<dl>
|
|
||||||
{% for group in loadbalancer.pool.members.members %}
|
|
||||||
<dt>{{ group.id }}</dt>
|
|
||||||
<dd> <b>IP:</b> {{ group.address }}</dd>
|
|
||||||
<dd> <b>Port:</b> {{ group.protocol_port }}</dd>
|
|
||||||
{% endfor %}
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
@ -1,15 +0,0 @@
|
|||||||
{% load i18n horizon %}
|
|
||||||
|
|
||||||
<p>{% blocktrans %}This wizard will walk you through setting up a new Load Balancer. A load balancer is a logical device. It is used to distribute workloads between multiple services called ’instances', based on the criteria defined as part of its configuration.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Name</b>: Enter a unique name for your load balancer (e.g., my-demo-lb).{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Description</b>: Provide a friendly description for your records.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Load Balancer Method</b>: All load balancers utilize an algorithm that defines how traffic should be directed between instances. The following algorithms are supported: ROUND_ROBIN, LEAST_CONNECTIONS, LEAST_SESSIONS.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Load Balancer Protocol</b>: Load Balancing of applications using HTTP, HTTPS (Secure HTTP), TCP, and SSL (Secure TCP) protocols are supported.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Load Balancer Port</b>: This is automatically assigned based on the Load Balancer Protocol selection.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Instance Port</b>: The acceptable instance ports for both HTTPS/SSL and HTTP/TCP connections are 0-65535.{% endblocktrans %}</p>
|
|
@ -1,49 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
{#<table class="table-fixed" id="monitorContainer">#}
|
|
||||||
{# <tbody>#}
|
|
||||||
{# <tr>#}
|
|
||||||
{# <td class="actions">#}
|
|
||||||
{# <div id="monitorId">#}
|
|
||||||
{# {% include "horizon/common/_form_fields.html" %}#}
|
|
||||||
{# </div>#}
|
|
||||||
{# </td>#}
|
|
||||||
{# <td class="help_text">#}
|
|
||||||
{# {{ step.get_help_text }}#}
|
|
||||||
{# </td>#}
|
|
||||||
{# </tr>#}
|
|
||||||
{# </tbody>#}
|
|
||||||
{#</table>#}
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{% include "horizon/common/_form_fields.html" %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{{ step.get_help_text }}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
horizon.modals.addModalInitFunction(function (modal) {
|
|
||||||
var $monitor_type = $('#id_monitor');
|
|
||||||
var $interval = $('#id_interval');
|
|
||||||
var $timeout = $('#id_timeout');
|
|
||||||
var $send = $('#id_send');
|
|
||||||
var $receive = $('#id_receive');
|
|
||||||
|
|
||||||
$monitor_type.change(function () {
|
|
||||||
if ($monitor_type.val() == 'http-ecv') {
|
|
||||||
$interval.closest(".control-group").show();
|
|
||||||
$timeout.closest(".control-group").show();
|
|
||||||
$send.closest(".control-group").show();
|
|
||||||
$receive.closest(".control-group").show();
|
|
||||||
} else {
|
|
||||||
$interval.closest(".control-group").hide();
|
|
||||||
$timeout.closest(".control-group").hide();
|
|
||||||
$send.closest(".control-group").hide();
|
|
||||||
$receive.closest(".control-group").hide();
|
|
||||||
}
|
|
||||||
}).trigger('change');
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,10 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
<p>{% blocktrans %}When adding a load balancer, you can also specify a health check monitor to use to determine the health of your instances. Health checks routinely run against each instance within a target load balancer and the result of the health check is used to determine if the instance receives new connections.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}The following health check options are currently supported:{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>TCP</b> – Default Option – A basic TCP ping check is performed against IP Address of each instance within a target load balancer.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>HTTP</b> – A basic HTTP health check is performed against each instance within a target load balancer on the specified instance port.{% endblocktrans %}</p>
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
<p>{% blocktrans %}For secure website or application using Load Balancers to offload SSL decryption requires SSL server certificate installed on the load balancer.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}If you do not have individual SSL certificate requirements (including custom vanity domains) for your secure website or application, you can choose to use the common certificate that we provide.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}For individual SSL certificates, if you already have a SSL certificate and want to upload it; please specify the following details:{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Certificate Name</b> – Supply a certificate name (i.e. my_server_cert).{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Private Key</b> - Copy and paste the contents of the private key file in the Private Key field.{% endblocktrans %}</p>
|
|
||||||
|
|
||||||
<p>{% blocktrans %}<b>Certificate Chain</b> – Optional - Copy and paste the contents of the public key certificate chain file in the Certificate Chain field.{% endblocktrans %}</p>
|
|
@ -1,15 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
{% load i18n sizeformat %}
|
|
||||||
{% block title %}{% trans "Load Balancer Detail" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block page_header %}
|
|
||||||
{% include "horizon/common/_page_header.html" with title="Load Balancer Detail: "|add:loadbalancer.name %}
|
|
||||||
{% endblock page_header %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
<div class="row-fluid">
|
|
||||||
<div class="span12">
|
|
||||||
{{ tab_group.render }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block title %}{% trans "Load Balancers" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block page_header %}
|
|
||||||
{% include "horizon/common/_page_header.html" with title=_("Load Balancers") %}
|
|
||||||
{% endblock page_header %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
{{ table.render }}
|
|
||||||
{% endblock %}
|
|
@ -1,11 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block title %}{% trans "Launch Load Balancer" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block page_header %}
|
|
||||||
{% include "horizon/common/_page_header.html" with title=_("Launch Load Balancer") %}
|
|
||||||
{% endblock page_header %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
{% include 'horizon/common/_workflow.html' %}
|
|
||||||
{% endblock %}
|
|
@ -1,82 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
{#<table class="table-fixed" id="sslCertContainer">#}
|
|
||||||
{# <tbody>#}
|
|
||||||
{# <tr>#}
|
|
||||||
{# <td class="actions">#}
|
|
||||||
{# <div class="row">#}
|
|
||||||
{# <div class="col-sm-12">#}
|
|
||||||
{# {% include "horizon/common/_form_fields.html" %}#}
|
|
||||||
{# </div>#}
|
|
||||||
{# </div>#}
|
|
||||||
{# </td>#}
|
|
||||||
{# <td class="help_text">#}
|
|
||||||
{# {{ step.get_help_text }}#}
|
|
||||||
{# </td>#}
|
|
||||||
{# </tr>#}
|
|
||||||
{# </tbody>#}
|
|
||||||
{#</table>#}
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{% include "horizon/common/_form_fields.html" %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{{ step.get_help_text }}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
horizon.modals.addModalInitFunction(function (modal) {
|
|
||||||
var $address = $('#id_address');
|
|
||||||
var $name = $('#id_name');
|
|
||||||
var $name_label = $('label[for="id_name"]');
|
|
||||||
var $protocol_type = $('#id_protocol_type');
|
|
||||||
|
|
||||||
$address.change(function () {
|
|
||||||
var options_all = {"HTTP": "HTTP", "HTTPS": "HTTPS", "TCP": "TCP", "SSL": "SSL"};
|
|
||||||
setOptions($protocol_type, options_all);
|
|
||||||
|
|
||||||
if ($address.val() == 'new') {
|
|
||||||
$name.removeAttr('disabled');
|
|
||||||
$name.removeAttr('readonly');
|
|
||||||
$name.attr('value', '');
|
|
||||||
} else {
|
|
||||||
var key_token = $address.val().split(':');
|
|
||||||
$name.attr('value', key_token[1]);
|
|
||||||
$name.attr('readonly', 'true');
|
|
||||||
}
|
|
||||||
}).trigger('change');
|
|
||||||
|
|
||||||
function setOptions($protocol_type, newOptions) {
|
|
||||||
$("#id_" + $protocol_type.val()).closest(".control-group").hide();
|
|
||||||
$protocol_type.empty();
|
|
||||||
|
|
||||||
$.each(newOptions, function (key, value) {
|
|
||||||
$protocol_type.append($("<option></option>")
|
|
||||||
.attr("value", value).text(key));
|
|
||||||
});
|
|
||||||
refresh($protocol_type);
|
|
||||||
};
|
|
||||||
|
|
||||||
function refresh($protocol_type) {
|
|
||||||
var $this = $protocol_type,
|
|
||||||
base_type = $this.val();
|
|
||||||
$this.find("option").each(function () {
|
|
||||||
if (this.value != base_type) {
|
|
||||||
$("#id_" + this.value).closest(".control-group").hide();
|
|
||||||
} else {
|
|
||||||
$("#id_" + this.value).closest(".control-group").show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$protocol_type.on('change', function(evt){
|
|
||||||
refresh($(this));
|
|
||||||
//prevent the default handler in horizon.instances.js
|
|
||||||
evt.stopPropagation();
|
|
||||||
}).trigger('change');
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
@ -1,76 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
<noscript><h3>{{ step }}</h3></noscript>
|
|
||||||
<style>
|
|
||||||
#target input{
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<table id='target' class="table table-bordered table-striped datatable">
|
|
||||||
<thead><tr><th>From</th><th>protocol</th><th>To</th><th>Action</th></tr></thead>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<input type='text' class='numbers' name='from' />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<select name='protocol'>
|
|
||||||
<option value='http'>HTTP</option>
|
|
||||||
<option value='https'>HTTPS</option>
|
|
||||||
<option value='tcp'>TCP</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<input type='text' class='numbers' name='to' />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a class='btn btn-small' name='add'>+</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function encode_lb_rule(from, protocol, to){
|
|
||||||
return from + ':' + protocol + ',' + to;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generate_lb_rule(from, protocol, to){
|
|
||||||
var html = "<tr><td>" + from + "</td>" +
|
|
||||||
"<td>" + protocol + "</td>" +
|
|
||||||
"<td>" + to + "</td>" +
|
|
||||||
"<td><a class='btn btn-small btn-danger'>-</a>";
|
|
||||||
html = $(html);
|
|
||||||
html.on('click', 'a', function(){
|
|
||||||
$('option[value="' + encode_lb_rule(from, protocol, to) + '"]').remove();
|
|
||||||
$(this).closest('tr').remove();
|
|
||||||
});
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
horizon.modals.addModalInitFunction(function (modal) {
|
|
||||||
$("a[name='add']").on('click', function(){
|
|
||||||
var from = $("input[name='from']").val();
|
|
||||||
var protocol = $("select[name='protocol']").val();
|
|
||||||
var to = $("input[name='to']").val();
|
|
||||||
var encoded = encode_lb_rule(from, protocol, to);
|
|
||||||
if(from && to && $('option[value="'+encoded+'"]').length == 0){
|
|
||||||
$('#id_network').append($("<option></option>")
|
|
||||||
.attr("value", encoded)
|
|
||||||
.attr("selected", "selected")
|
|
||||||
.text(encoded));
|
|
||||||
generate_lb_rule(from, protocol, to).insertBefore($('#target tr:last'));
|
|
||||||
// clean up
|
|
||||||
$("input[name='from']").val('');
|
|
||||||
$("input[name='to']").val('');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('input.numbers').keyup(function () {
|
|
||||||
this.value = this.value.replace(/[^0-9\.]/g,'');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="hidden">
|
|
||||||
{% include "horizon/common/_form_fields.html" %}
|
|
||||||
</div>
|
|
@ -1,68 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
{#<table class="table-fixed" id="sslCertContainer">#}
|
|
||||||
{# <tbody>#}
|
|
||||||
{# <tr>#}
|
|
||||||
{# <td class="actions">#}
|
|
||||||
{# <div id="sslCertId">#}
|
|
||||||
{# {% include "horizon/common/_form_fields.html" %}#}
|
|
||||||
{# </div>#}
|
|
||||||
{# </td>#}
|
|
||||||
{# <td class="help_text">#}
|
|
||||||
{# {{ step.get_help_text }}#}
|
|
||||||
{# </td>#}
|
|
||||||
{# </tr>#}
|
|
||||||
{# </tbody>#}
|
|
||||||
{#</table>#}
|
|
||||||
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{% include "horizon/common/_form_fields.html" %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{{ step.get_help_text }}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
<script>
|
|
||||||
horizon.modals.addModalInitFunction(function (modal) {
|
|
||||||
var $protocol = $('#id_source_type');
|
|
||||||
var $cert_name = $('#id_cert_name');
|
|
||||||
var $cert = $('#id_cert');
|
|
||||||
var $key = $('#id_private_key');
|
|
||||||
var $intermediate = $('#id_chain_cert');
|
|
||||||
var $common_cert = $('#id_use_common_cert');
|
|
||||||
|
|
||||||
$protocol.change(function () {
|
|
||||||
if ($protocol.val() == 'HTTPS') {
|
|
||||||
$common_cert.removeAttr('disabled');
|
|
||||||
$common_cert.attr('value', 'on');
|
|
||||||
$cert_name.removeAttr('disabled');
|
|
||||||
$cert.removeAttr('disabled');
|
|
||||||
$key.removeAttr('disabled');
|
|
||||||
$intermediate.removeAttr('disabled');
|
|
||||||
} else {
|
|
||||||
$common_cert.removeAttr('checked');
|
|
||||||
$common_cert.attr('disabled', 'disabled').val('');
|
|
||||||
$cert_name.attr('disabled', 'disabled').val('');
|
|
||||||
$cert.attr('disabled', 'disabled').val('');
|
|
||||||
$key.attr('disabled', 'disabled').val('');
|
|
||||||
$intermediate.attr('disabled', 'disabled').val('');
|
|
||||||
}
|
|
||||||
}).trigger('change');
|
|
||||||
|
|
||||||
$common_cert.click(function () {
|
|
||||||
if ($common_cert.is(':checked')) {
|
|
||||||
$cert_name.attr('disabled', 'disabled').val('');
|
|
||||||
$cert.attr('disabled', 'disabled').val('');
|
|
||||||
$key.attr('disabled', 'disabled').val('');
|
|
||||||
$intermediate.attr('disabled', 'disabled').val('');
|
|
||||||
} else {
|
|
||||||
$cert_name.removeAttr('disabled');
|
|
||||||
$cert.removeAttr('disabled');
|
|
||||||
$key.removeAttr('disabled');
|
|
||||||
$intermediate.removeAttr('disabled');
|
|
||||||
}
|
|
||||||
}).trigger('change');
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,11 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block title %}{% trans "Edit Load Balancer" %}{% endblock %}
|
|
||||||
|
|
||||||
{% block page_header %}
|
|
||||||
{% include "horizon/common/_page_header.html" with title=_("Edit Load Balancer") %}
|
|
||||||
{% endblock page_header %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
{% include 'horizon/common/_workflow.html' %}
|
|
||||||
{% endblock %}
|
|
@ -1,63 +0,0 @@
|
|||||||
<noscript><h3>{{ step }}</h3></noscript>
|
|
||||||
{#<table class="table-fixed">#}
|
|
||||||
{# <tbody>#}
|
|
||||||
{# <tr>#}
|
|
||||||
{# <td class="actions">#}
|
|
||||||
{# {% include "horizon/common/_form_fields.html" %}#}
|
|
||||||
{# </td>#}
|
|
||||||
{# <td class="help_text">#}
|
|
||||||
{# {{ step.get_help_text }}#}
|
|
||||||
{# </td>#}
|
|
||||||
{# </tr>#}
|
|
||||||
{# </tbody>#}
|
|
||||||
{#</table>#}
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{% include "horizon/common/_form_fields.html" %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{{ step.get_help_text }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
horizon.modals.addModalInitFunction(function (modal) {
|
|
||||||
var $protocol_type = $('#id_source_type');
|
|
||||||
var old_value = $protocol_type.val();
|
|
||||||
|
|
||||||
if (old_value == "HTTP" || old_value == "TCP") {
|
|
||||||
var options_all = {"HTTP": "HTTP", "TCP": "TCP"};
|
|
||||||
} else {
|
|
||||||
var options_all = {"HTTPS": "HTTPS", "SSL": "SSL"};
|
|
||||||
}
|
|
||||||
|
|
||||||
setOptions($protocol_type, options_all);
|
|
||||||
|
|
||||||
function setOptions($protocol_type, newOptions) {
|
|
||||||
$("#id_" + $protocol_type.val()).closest(".control-group").hide();
|
|
||||||
$protocol_type.empty();
|
|
||||||
|
|
||||||
$.each(newOptions, function (key, value) {
|
|
||||||
$protocol_type.append($("<option></option>")
|
|
||||||
.attr("value", value).text(key));
|
|
||||||
});
|
|
||||||
$protocol_type.val(old_value);
|
|
||||||
refresh($protocol_type);
|
|
||||||
};
|
|
||||||
|
|
||||||
function refresh($protocol_type) {
|
|
||||||
var $this = $protocol_type,
|
|
||||||
base_type = $this.val();
|
|
||||||
|
|
||||||
$this.find("option").each(function () {
|
|
||||||
if (this.value != base_type) {
|
|
||||||
$("#id_" + this.value).closest(".control-group").hide();
|
|
||||||
} else {
|
|
||||||
$("#id_" + this.value).closest(".control-group").show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$this.trigger('change');
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
@ -1,91 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block main %}
|
|
||||||
{#<table class="table-fixed" id="sslCertContainer">#}
|
|
||||||
{# <tbody>#}
|
|
||||||
{# <tr>#}
|
|
||||||
{# <td class="actions">#}
|
|
||||||
{# <div id="sslCertId">#}
|
|
||||||
{# {% include "horizon/common/_form_fields.html" %}#}
|
|
||||||
{# </div>#}
|
|
||||||
{# </td>#}
|
|
||||||
{# <td class="help_text">#}
|
|
||||||
{# {{ step.get_help_text }}#}
|
|
||||||
{# </td>#}
|
|
||||||
{# </tr>#}
|
|
||||||
{# </tbody>#}
|
|
||||||
{#</table>#}
|
|
||||||
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{% include "horizon/common/_form_fields.html" %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{{ step.get_help_text }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
<script>
|
|
||||||
horizon.modals.addModalInitFunction(function (modal) {
|
|
||||||
var $protocol = $('#id_source_type');
|
|
||||||
var $cert_name = $('#id_cert_name');
|
|
||||||
var $cert = $('#id_cert');
|
|
||||||
var $key = $('#id_private_key');
|
|
||||||
var $intermediate = $('#id_chain_cert');
|
|
||||||
var $common_cert = $('#id_use_common_cert');
|
|
||||||
var $update_cert = $('#id_update_cert');
|
|
||||||
|
|
||||||
$protocol.change(function () {
|
|
||||||
if ($protocol.val() == 'HTTPS') {
|
|
||||||
$update_cert.removeAttr('disabled');
|
|
||||||
$update_cert.attr('value', 'on');
|
|
||||||
} else {
|
|
||||||
$update_cert.removeAttr('checked');
|
|
||||||
$update_cert.attr('disabled', 'disabled').val('');
|
|
||||||
}
|
|
||||||
$common_cert.attr('disabled', 'disabled');
|
|
||||||
$cert_name.attr('disabled', 'disabled');
|
|
||||||
$cert.attr('disabled', 'disabled');
|
|
||||||
$key.attr('disabled', 'disabled');
|
|
||||||
$intermediate.attr('disabled', 'disabled');
|
|
||||||
}).trigger('change');
|
|
||||||
|
|
||||||
$update_cert.click(function () {
|
|
||||||
if ($update_cert.is(':checked')) {
|
|
||||||
$common_cert.removeAttr('disabled');
|
|
||||||
$common_cert.attr('value', 'on');
|
|
||||||
if ($common_cert.is(':checked')) {
|
|
||||||
$cert_name.attr('disabled', 'disabled');
|
|
||||||
$cert.attr('disabled', 'disabled');
|
|
||||||
$key.attr('disabled', 'disabled');
|
|
||||||
$intermediate.attr('disabled', 'disabled');
|
|
||||||
} else {
|
|
||||||
$cert_name.removeAttr('disabled');
|
|
||||||
$cert.removeAttr('disabled');
|
|
||||||
$key.removeAttr('disabled');
|
|
||||||
$intermediate.removeAttr('disabled');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$common_cert.attr('disabled', 'disabled');
|
|
||||||
$cert_name.attr('disabled', 'disabled');
|
|
||||||
$cert.attr('disabled', 'disabled');
|
|
||||||
$key.attr('disabled', 'disabled');
|
|
||||||
$intermediate.attr('disabled', 'disabled');
|
|
||||||
}
|
|
||||||
}).trigger('change');
|
|
||||||
|
|
||||||
$common_cert.click(function () {
|
|
||||||
if ($common_cert.is(':checked')) {
|
|
||||||
$cert_name.attr('disabled', 'disabled');
|
|
||||||
$cert.attr('disabled', 'disabled');
|
|
||||||
$key.attr('disabled', 'disabled');
|
|
||||||
$intermediate.attr('disabled', 'disabled');
|
|
||||||
} else {
|
|
||||||
$cert_name.removeAttr('disabled');
|
|
||||||
$cert.removeAttr('disabled');
|
|
||||||
$key.removeAttr('disabled');
|
|
||||||
$intermediate.removeAttr('disabled');
|
|
||||||
}
|
|
||||||
}).trigger('change');
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,34 +0,0 @@
|
|||||||
# 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 django.conf.urls import url
|
|
||||||
|
|
||||||
from .views import DetailView # noqa
|
|
||||||
from .views import IndexView # noqa
|
|
||||||
from .views import LaunchLoadBalancerView # noqa
|
|
||||||
from .views import UpdateView # noqa
|
|
||||||
|
|
||||||
|
|
||||||
INSTANCES = r'^(?P<loadbalancer_id>[^/]+)/%s$'
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^$', IndexView.as_view(), name='index'),
|
|
||||||
url(r'^launch$',
|
|
||||||
LaunchLoadBalancerView.as_view(), name='launch'),
|
|
||||||
url(r'^(?P<loadbalancer_id>[^/]+)/$',
|
|
||||||
DetailView.as_view(), name='detail'),
|
|
||||||
url(INSTANCES %
|
|
||||||
'update', UpdateView.as_view(), name='update'),
|
|
||||||
]
|
|
@ -1,146 +0,0 @@
|
|||||||
# 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 oslo_log import log as logging
|
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.core.urlresolvers import reverse_lazy
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from horizon import exceptions
|
|
||||||
from horizon import tables
|
|
||||||
from horizon import tabs
|
|
||||||
from horizon import workflows
|
|
||||||
|
|
||||||
from octavia_dashboard import api
|
|
||||||
|
|
||||||
from .tables import LoadBalancersTable # noqa
|
|
||||||
from .tabs import LoadBalancerDetailTabs # noqa
|
|
||||||
from .workflows import LaunchLoadBalancer # noqa
|
|
||||||
from .workflows import UpdateLoadBalancer # noqa
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class IndexView(tables.DataTableView):
|
|
||||||
table_class = LoadBalancersTable
|
|
||||||
template_name = 'project/loadbalancersv2/index.html'
|
|
||||||
|
|
||||||
def get_data(self):
|
|
||||||
pools = []
|
|
||||||
try:
|
|
||||||
pools = api.lbaasv2.list_loadbalancers(self.request)
|
|
||||||
except Exception:
|
|
||||||
exceptions.handle(self.request,
|
|
||||||
_('Unable to retrieve pools list.'))
|
|
||||||
return pools
|
|
||||||
|
|
||||||
|
|
||||||
class LaunchLoadBalancerView(workflows.WorkflowView):
|
|
||||||
workflow_class = LaunchLoadBalancer
|
|
||||||
template_name = "project/loadbalancersv2/launch.html"
|
|
||||||
|
|
||||||
def get_initial(self):
|
|
||||||
initial = super(LaunchLoadBalancerView, self).get_initial()
|
|
||||||
initial['project_id'] = self.request.user.tenant_id
|
|
||||||
initial['user_id'] = self.request.user.id
|
|
||||||
return initial
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateView(workflows.WorkflowView):
|
|
||||||
workflow_class = UpdateLoadBalancer
|
|
||||||
template_name = 'project/loadbalancersv2/update.html'
|
|
||||||
success_url = reverse_lazy("horizon:project:loadbalancersv2:index")
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
|
||||||
context["loadbalancer_id"] = self.kwargs['loadbalancer_id']
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_object(self, *args, **kwargs):
|
|
||||||
if not hasattr(self, "_object"):
|
|
||||||
loadbalancer_id = self.kwargs['loadbalancer_id']
|
|
||||||
LOG.info("DEBUGGING - loadbalancer_id=%s" % loadbalancer_id)
|
|
||||||
try:
|
|
||||||
vip = api.lbaasv2.show_loadbalancer(self.request,
|
|
||||||
loadbalancer_id)
|
|
||||||
self._object = vip.readable(self.request)
|
|
||||||
except Exception as e:
|
|
||||||
redirect = reverse("horizon:project:loadbalancersv2:index")
|
|
||||||
msg = _('Unable to retrieve load balancer details. %s')\
|
|
||||||
% e.message
|
|
||||||
exceptions.handle(self.request, msg, redirect=redirect)
|
|
||||||
return self._object
|
|
||||||
|
|
||||||
def get_initial(self):
|
|
||||||
initial = super(UpdateView, self).get_initial()
|
|
||||||
|
|
||||||
initial.update({
|
|
||||||
'loadbalancer_id': self.kwargs['loadbalancer_id'],
|
|
||||||
'address': getattr(self.get_object(), 'address', ''),
|
|
||||||
'name': getattr(self.get_object(), 'name', ''),
|
|
||||||
'description': getattr(self.get_object(), 'description', ''),
|
|
||||||
'lb_method': getattr(self.get_object(), 'lb_method', ''),
|
|
||||||
'monitor': getattr(self.get_object(), 'monitor', ''),
|
|
||||||
'interval': getattr(self.get_object(), 'interval', ''),
|
|
||||||
'timeout': getattr(self.get_object(), 'timeout', ''),
|
|
||||||
'send': getattr(self.get_object(), 'send', ''),
|
|
||||||
'receive': getattr(self.get_object(), 'receive', ''),
|
|
||||||
|
|
||||||
'source_type': getattr(self.get_object(), 'protocol', ''),
|
|
||||||
'http': getattr(self.get_object(), 'port', ''),
|
|
||||||
'https': getattr(self.get_object(), 'port', ''),
|
|
||||||
'instance_port': getattr(self.get_object(), 'instance_port', ''),
|
|
||||||
'selected_members': getattr(self.get_object(), 'members', ''),
|
|
||||||
'cert_name': getattr(self.get_object(), 'cert_name', ''),
|
|
||||||
'cert': getattr(self.get_object(), 'cert', ''),
|
|
||||||
'private_key': getattr(self.get_object(), 'private_key', ''),
|
|
||||||
'chain_cert': getattr(self.get_object(), 'chain_cert', ''),
|
|
||||||
'enabled': getattr(self.get_object(), 'enabled', ''),
|
|
||||||
'use_common_cert': getattr(self.get_object(),
|
|
||||||
'use_common_cert', ''),
|
|
||||||
'port': getattr(self.get_object(), 'port', ''),
|
|
||||||
})
|
|
||||||
return initial
|
|
||||||
|
|
||||||
|
|
||||||
class DetailView(tabs.TabView):
|
|
||||||
tab_group_class = LoadBalancerDetailTabs
|
|
||||||
template_name = 'project/loadbalancersv2/detail.html'
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(DetailView, self).get_context_data(**kwargs)
|
|
||||||
context["loadbalancer"] = self.get_data()
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_data(self):
|
|
||||||
if not hasattr(self, "_loadbalancer"):
|
|
||||||
try:
|
|
||||||
loadbalancer_id = self.kwargs['loadbalancer_id']
|
|
||||||
loadbalancer = api.lbaasv2.show_loadbalancer(self.request,
|
|
||||||
loadbalancer_id)
|
|
||||||
except Exception:
|
|
||||||
redirect = reverse('horizon:project:loadbalancersv2:index')
|
|
||||||
exceptions.handle(self.request,
|
|
||||||
_('Unable to retrieve details for '
|
|
||||||
'loadbalancer "%s".') % loadbalancer_id,
|
|
||||||
redirect=redirect)
|
|
||||||
self._loadbalancer = loadbalancer
|
|
||||||
return self._loadbalancer.readable(self.request)
|
|
||||||
|
|
||||||
def get_tabs(self, request, *args, **kwargs):
|
|
||||||
loadbalancer = self.get_data()
|
|
||||||
return self.tab_group_class(request, loadbalancer=loadbalancer,
|
|
||||||
**kwargs)
|
|
@ -1,16 +0,0 @@
|
|||||||
# 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 . create_lb import * # noqa
|
|
||||||
from . update_lb import * # noqa
|
|
@ -1,460 +0,0 @@
|
|||||||
# 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 django.utils.translation import ugettext_lazy as _
|
|
||||||
from horizon import exceptions
|
|
||||||
from horizon import forms
|
|
||||||
from horizon import workflows
|
|
||||||
|
|
||||||
from openstack_dashboard.api import nova
|
|
||||||
|
|
||||||
from octavia_dashboard import api
|
|
||||||
|
|
||||||
__create_new__ = "Create New"
|
|
||||||
|
|
||||||
|
|
||||||
class SetLBDetailsAction(workflows.Action):
|
|
||||||
|
|
||||||
address = forms.ChoiceField(label=_("IP"),
|
|
||||||
help_text=_("Select from existing VIP IPs"))
|
|
||||||
|
|
||||||
name = forms.CharField(max_length=80, label=_("Name"),
|
|
||||||
required=True)
|
|
||||||
|
|
||||||
description = forms.CharField(widget=forms.Textarea(attrs={'rows': 2}),
|
|
||||||
label=_(
|
|
||||||
"Load Balancer Description"),
|
|
||||||
required=False,
|
|
||||||
help_text=_("Provide Load Balancer "
|
|
||||||
"Description."))
|
|
||||||
|
|
||||||
all_vips = None
|
|
||||||
is_update = False
|
|
||||||
|
|
||||||
LOAD_BALANCING_CHOICES = (
|
|
||||||
("RoundRobin", _("Round Robin")),
|
|
||||||
("LeastConnection", _("Least Connection")),
|
|
||||||
("LeastSessions", _("Least Sessions"))
|
|
||||||
)
|
|
||||||
lb_method = forms.ChoiceField(label=_("Load Balancing Method"),
|
|
||||||
choices=LOAD_BALANCING_CHOICES)
|
|
||||||
|
|
||||||
PROTOCOL_CHOICES = (
|
|
||||||
("HTTP", _("HTTP")),
|
|
||||||
("HTTPS", _("HTTPS")),
|
|
||||||
("TCP", _("TCP")),
|
|
||||||
("SSL", _("SSL")),
|
|
||||||
)
|
|
||||||
|
|
||||||
protocol_type = forms.ChoiceField(
|
|
||||||
label=_("LB Protocol"), choices=PROTOCOL_CHOICES)
|
|
||||||
|
|
||||||
port = forms.IntegerField(label=_("LB Port"),
|
|
||||||
required=False,
|
|
||||||
min_value=1,
|
|
||||||
max_value=65535,
|
|
||||||
help_text=_("LB Port on which "
|
|
||||||
"LB is listening."))
|
|
||||||
|
|
||||||
instance_port = forms.IntegerField(label=_("Instance Port"),
|
|
||||||
required=False,
|
|
||||||
min_value=1,
|
|
||||||
max_value=65535,
|
|
||||||
help_text=_("Instance Port on which "
|
|
||||||
"service is running."))
|
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
|
||||||
super(SetLBDetailsAction, self).__init__(request, *args, **kwargs)
|
|
||||||
self.all_vips = []
|
|
||||||
try:
|
|
||||||
# todo - this should be obtained in view via an initial method
|
|
||||||
self.all_vips = api.lbaasv2.list_loadbalancers(request)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if len(self.fields['address'].choices) == 0:
|
|
||||||
del self.fields['address']
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = _("LB Details")
|
|
||||||
help_text_template = ("project/loadbalancersv2/_launch_lb_help.html")
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
cleaned_data = super(SetLBDetailsAction, self).clean()
|
|
||||||
|
|
||||||
lb_method = cleaned_data['lb_method']
|
|
||||||
if not (lb_method == 'RoundRobin'
|
|
||||||
or lb_method == 'LeastConnection'
|
|
||||||
or lb_method == 'LeastSessions'):
|
|
||||||
raise forms.ValidationError(_("Please select an option for "
|
|
||||||
"the load balancing method."))
|
|
||||||
|
|
||||||
if not self.is_update:
|
|
||||||
all_vips = self.all_vips
|
|
||||||
ipPortCombo = []
|
|
||||||
for vip in all_vips:
|
|
||||||
vip = vip.readable()
|
|
||||||
ipPortCombo.append('%s:%s' % (vip.address, vip.port))
|
|
||||||
|
|
||||||
data = self.data
|
|
||||||
if 'address' in data \
|
|
||||||
and data['address'] != 'new' \
|
|
||||||
and data['address'] != '':
|
|
||||||
address = data['address']
|
|
||||||
selected_lb_port = data['port']
|
|
||||||
selected_ip_port_combo = '%s:%s' % (address.split(':')[0],
|
|
||||||
selected_lb_port)
|
|
||||||
if selected_ip_port_combo in ipPortCombo:
|
|
||||||
raise forms.ValidationError(_('Requested IP and port '
|
|
||||||
'combination already '
|
|
||||||
'exists %s ') %
|
|
||||||
selected_ip_port_combo)
|
|
||||||
|
|
||||||
instance_port = cleaned_data.get('instance_port', None)
|
|
||||||
if not instance_port:
|
|
||||||
raise forms.ValidationError(
|
|
||||||
_('Please provide instance port'))
|
|
||||||
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
def populate_address_choices(self, request, context):
|
|
||||||
if self.is_update:
|
|
||||||
return []
|
|
||||||
try:
|
|
||||||
vips = api.lbaasv2.list_loadbalancers(request)
|
|
||||||
if len(vips) == 0:
|
|
||||||
return []
|
|
||||||
|
|
||||||
distict_ips = set()
|
|
||||||
for vip in vips:
|
|
||||||
vip = vip.readable()
|
|
||||||
distict_ips.add(vip.address)
|
|
||||||
|
|
||||||
existing = []
|
|
||||||
for vip in vips:
|
|
||||||
vip = vip.readable()
|
|
||||||
if vip.address in distict_ips:
|
|
||||||
item = ("%s:%s:%s" %
|
|
||||||
(vip.address, vip.name, 443),
|
|
||||||
"%s" % vip.address)
|
|
||||||
existing.append(item)
|
|
||||||
distict_ips.remove(vip.address)
|
|
||||||
|
|
||||||
vip_list = []
|
|
||||||
if len(existing) > 0:
|
|
||||||
vip_list.append(('new', __create_new__))
|
|
||||||
vip_list.append(('Select Existing', existing))
|
|
||||||
return vip_list
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
exceptions.handle(request,
|
|
||||||
_('Unable to retrieve vips.'))
|
|
||||||
return []
|
|
||||||
|
|
||||||
def get_help_text(self):
|
|
||||||
extra = {}
|
|
||||||
return super(SetLBDetailsAction, self).get_help_text(extra)
|
|
||||||
|
|
||||||
|
|
||||||
class SetLBDetails(workflows.Step):
|
|
||||||
action_class = SetLBDetailsAction
|
|
||||||
contributes = ("name", "description", "lb_method", "protocol_type", "port",
|
|
||||||
"source_id", "instance_port", "address", "monitor")
|
|
||||||
|
|
||||||
def contribute(self, data, context):
|
|
||||||
context = super(SetLBDetails, self).contribute(data, context)
|
|
||||||
return context
|
|
||||||
|
|
||||||
template_name = "project/loadbalancersv2/launch_lb.html"
|
|
||||||
|
|
||||||
|
|
||||||
class UploadSSLAction(workflows.Action):
|
|
||||||
update_cert = forms.BooleanField(label='Update SSL Certificate',
|
|
||||||
required=False,
|
|
||||||
widget=forms.HiddenInput())
|
|
||||||
|
|
||||||
cert_name = forms.CharField(max_length=80,
|
|
||||||
label=_("Certificate Name"),
|
|
||||||
required=False)
|
|
||||||
|
|
||||||
cert = forms.CharField(widget=forms.Textarea(attrs={'rows': 3}),
|
|
||||||
label=_("Certificate"),
|
|
||||||
required=False,
|
|
||||||
help_text=_("Certificate"))
|
|
||||||
|
|
||||||
private_key = forms.CharField(widget=forms.Textarea(attrs={'rows': 3}),
|
|
||||||
label=_("Private Key"),
|
|
||||||
required=False,
|
|
||||||
help_text=_("Private Key"))
|
|
||||||
|
|
||||||
chain_cert = forms.CharField(widget=forms.Textarea(attrs={'rows': 3}),
|
|
||||||
label=_("Certificate Chain (Optional)"),
|
|
||||||
required=False,
|
|
||||||
help_text=_("Intermediate Chain"
|
|
||||||
" Certificates"))
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
cleaned_data = super(UploadSSLAction, self).clean()
|
|
||||||
data = self.data
|
|
||||||
protocol = data.get('source_type')
|
|
||||||
if protocol == 'HTTPS':
|
|
||||||
use_common_cert = data.get('use_common_cert')
|
|
||||||
if not use_common_cert:
|
|
||||||
# check to see if ssl cert is provided
|
|
||||||
cert_name = data.get('cert_name')
|
|
||||||
cert = data.get('cert')
|
|
||||||
private_key = data.get('private_key')
|
|
||||||
|
|
||||||
if (not cert_name) \
|
|
||||||
or (not cert) \
|
|
||||||
or (not private_key):
|
|
||||||
raise forms.ValidationError(
|
|
||||||
_('Please provide all certificate parameters.'))
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = _("SSL Certificate")
|
|
||||||
help_text_template = ("project/loadbalancersv2/_ssl_cert_help.html")
|
|
||||||
|
|
||||||
|
|
||||||
class UploadSSLStep(workflows.Step):
|
|
||||||
action_class = UploadSSLAction
|
|
||||||
contributes = ("cert_name", "cert",
|
|
||||||
"private_key", "chain_cert", 'use_common_cert')
|
|
||||||
template_name = "project/loadbalancersv2/ssl_cert.html"
|
|
||||||
|
|
||||||
def contribute(self, data, context):
|
|
||||||
post = self.workflow.request.POST
|
|
||||||
context['cert_name'] = post['cert_name'] if 'cert_name' in post else ''
|
|
||||||
context['cert'] = post['cert'] if 'cert' in post else ''
|
|
||||||
context['private_key'] = post[
|
|
||||||
'private_key'] if 'private_key' in post else ''
|
|
||||||
context['chain_cert'] = post[
|
|
||||||
'chain_cert'] if 'chain_cert' in post else ''
|
|
||||||
context['use_common_cert'] = post[
|
|
||||||
'use_common_cert'] if 'use_common_cert' in post else ''
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class SelectInstancesAction(workflows.MembershipAction):
|
|
||||||
instance_details = {}
|
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
|
||||||
super(SelectInstancesAction, self).__init__(request, *args, **kwargs)
|
|
||||||
err_msg = _('Unable to retrieve members list. '
|
|
||||||
'Please try again later.')
|
|
||||||
|
|
||||||
default_role_field_name = self.get_default_role_field_name()
|
|
||||||
self.fields[default_role_field_name] = forms.CharField(required=False,
|
|
||||||
label='')
|
|
||||||
self.fields[default_role_field_name].initial = 'member'
|
|
||||||
|
|
||||||
role_member_field_name = self.get_member_field_name('member')
|
|
||||||
self.fields[role_member_field_name] = forms.MultipleChoiceField(
|
|
||||||
required=False, label='')
|
|
||||||
|
|
||||||
# Get list of available instances
|
|
||||||
all_instances = []
|
|
||||||
try:
|
|
||||||
all_instances, has_more_data = nova.server_list(request)
|
|
||||||
except Exception:
|
|
||||||
exceptions.handle(request, err_msg)
|
|
||||||
|
|
||||||
available_instances = []
|
|
||||||
for instance in all_instances:
|
|
||||||
# skip shutoff instances
|
|
||||||
# if instance.status == 'SHUTOFF':
|
|
||||||
# continue
|
|
||||||
instance_ip = self.get_ip(instance)
|
|
||||||
# skip instances which has no network
|
|
||||||
if not instance_ip:
|
|
||||||
continue
|
|
||||||
key = instance_ip
|
|
||||||
value = instance.name + ' (' + self.get_ip(instance) + ')'
|
|
||||||
available_instances.append((key, value))
|
|
||||||
self.instance_details[instance_ip] = (instance.name, instance.id)
|
|
||||||
|
|
||||||
self.fields[self.get_member_field_name('member')].\
|
|
||||||
choices = available_instances
|
|
||||||
|
|
||||||
def get_ip(self, instance):
|
|
||||||
ipaddress = None
|
|
||||||
for networks in instance.addresses.itervalues():
|
|
||||||
for ip in networks:
|
|
||||||
# only one IP present
|
|
||||||
ipaddress = ip
|
|
||||||
break
|
|
||||||
if ipaddress is not None:
|
|
||||||
addr = ipaddress["addr"]
|
|
||||||
else:
|
|
||||||
addr = None # '10.10.10.10'
|
|
||||||
return addr
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
cleaned_data = super(SelectInstancesAction, self).clean()
|
|
||||||
members = cleaned_data.get(self.get_member_field_name('member'), None)
|
|
||||||
if not members:
|
|
||||||
raise forms.ValidationError(
|
|
||||||
_('Please select at least one member'))
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = _("Instances")
|
|
||||||
slug = "select_instances"
|
|
||||||
|
|
||||||
|
|
||||||
class SelectInstancesStep(workflows.UpdateMembersStep):
|
|
||||||
action_class = SelectInstancesAction
|
|
||||||
help_text = _("Please select a list of instances that should handle"
|
|
||||||
" traffic for this target load balancer. All instances "
|
|
||||||
"must reside in the same Project as the target load "
|
|
||||||
"balancer.")
|
|
||||||
available_list_title = _("All Instances")
|
|
||||||
members_list_title = _("Selected Instances")
|
|
||||||
no_available_text = _("No instances found.")
|
|
||||||
no_members_text = _("No members enabled.")
|
|
||||||
show_roles = False
|
|
||||||
contributes = (
|
|
||||||
"wanted_members", "instances_details", "monitor", "instance_port")
|
|
||||||
template_name = "horizon/common/_workflow_step_update_members.html"
|
|
||||||
|
|
||||||
def contribute(self, data, context):
|
|
||||||
request = self.workflow.request
|
|
||||||
if data:
|
|
||||||
context["wanted_members"] = request.POST.getlist(
|
|
||||||
self.get_member_field_name('member'))
|
|
||||||
context["instances_details"] = self.action.instance_details
|
|
||||||
context["monitor"] = request.POST.get("monitor")
|
|
||||||
context["instance_port"] = request.POST.get("instance_port")
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class SelectMonitorAction(workflows.Action):
|
|
||||||
MONITOR_CHOICES = (
|
|
||||||
("tcp", _("TCP")),
|
|
||||||
("ping", _("PING")),
|
|
||||||
("http", _("HTTP")),
|
|
||||||
)
|
|
||||||
monitor = forms.ChoiceField(label=_("Monitor"),
|
|
||||||
choices=MONITOR_CHOICES)
|
|
||||||
|
|
||||||
interval = forms.IntegerField(label=_("Health Check Interval"
|
|
||||||
" (in seconds)"),
|
|
||||||
required=False,
|
|
||||||
min_value=1,
|
|
||||||
max_value=600,
|
|
||||||
help_text=_("Health Check Interval"
|
|
||||||
" (in seconds)"))
|
|
||||||
|
|
||||||
timeout = forms.IntegerField(label=_("Retry count before markdown"),
|
|
||||||
required=False,
|
|
||||||
min_value=1,
|
|
||||||
max_value=100,
|
|
||||||
help_text=_("Number of times health check "
|
|
||||||
"should be attempted before "
|
|
||||||
"marking down a member"))
|
|
||||||
|
|
||||||
send = forms.CharField(widget=forms.Textarea(attrs={'rows': 1}),
|
|
||||||
label=_("Send String"),
|
|
||||||
required=False,
|
|
||||||
help_text=_("Send String"))
|
|
||||||
|
|
||||||
receive = forms.CharField(widget=forms.Textarea(attrs={'rows': 1}),
|
|
||||||
label=_("Receive String"),
|
|
||||||
required=False,
|
|
||||||
help_text=_("Receive String"))
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = _("Monitor")
|
|
||||||
help_text_template = ("project/loadbalancersv2/_monitor_help.html")
|
|
||||||
|
|
||||||
|
|
||||||
class SelectMonitorStep(workflows.Step):
|
|
||||||
action_class = SelectMonitorAction
|
|
||||||
contributes = ("monitor", "interval", "timeout", "send", "receive")
|
|
||||||
template_name = "project/loadbalancersv2/_monitor_create.html"
|
|
||||||
|
|
||||||
def contribute(self, data, context):
|
|
||||||
post = self.workflow.request.POST
|
|
||||||
|
|
||||||
context['interval'] = post['interval'] if 'interval' in post else ''
|
|
||||||
context['timeout'] = post['timeout'] if 'timeout' in post else ''
|
|
||||||
context['send'] = post['send'] if 'send' in post else ''
|
|
||||||
context['receive'] = post['receive'] if 'receive' in post else ''
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class LaunchLoadBalancer(workflows.Workflow):
|
|
||||||
slug = "launch_loadbalancer"
|
|
||||||
name = _("Launch Load Balancer")
|
|
||||||
finalize_button_name = _("Launch")
|
|
||||||
success_message = _('Launched %(count)s named "%(name)s".')
|
|
||||||
failure_message = _('Unable to launch %(count)s named "%(name)s".')
|
|
||||||
success_url = "horizon:project:loadbalancersv2:index"
|
|
||||||
default_steps = (SetLBDetails,
|
|
||||||
UploadSSLStep,
|
|
||||||
SelectMonitorStep,
|
|
||||||
SelectInstancesStep,
|
|
||||||
)
|
|
||||||
attrs = {'data-help-text': 'LB creation may take a few minutes'}
|
|
||||||
|
|
||||||
def format_status_message(self, message):
|
|
||||||
name = self.context.get('name', 'unknown loadbalancer')
|
|
||||||
count = self.context.get('count', 1)
|
|
||||||
if int(count) > 1:
|
|
||||||
return message % {"count": _("%s loadbalancers") % count,
|
|
||||||
"name": name}
|
|
||||||
else:
|
|
||||||
return message % {"count": _("loadbalancer"), "name": name}
|
|
||||||
|
|
||||||
def handle(self, request, context):
|
|
||||||
try:
|
|
||||||
protocol = context['source_type']
|
|
||||||
address = context['address']
|
|
||||||
if not address\
|
|
||||||
or address == "new":
|
|
||||||
address = ''
|
|
||||||
else:
|
|
||||||
tokens = address.split(':')
|
|
||||||
address = tokens[0]
|
|
||||||
|
|
||||||
api.lbaasv2.\
|
|
||||||
create_loadbalancer_full(request,
|
|
||||||
address=address,
|
|
||||||
name=context['name'],
|
|
||||||
description=context['description'],
|
|
||||||
lb_method=context['lb_method'],
|
|
||||||
monitor=context['monitor'],
|
|
||||||
protocol=protocol,
|
|
||||||
port=context[protocol],
|
|
||||||
instance_port=context['instance_port'], # noqa
|
|
||||||
wanted_members=context['wanted_members'], # noqa
|
|
||||||
instances_details=context['instances_details'], # noqa
|
|
||||||
cert_name=context['cert_name'],
|
|
||||||
cert=context['cert'],
|
|
||||||
private_key=context['private_key'],
|
|
||||||
chain_cert=context['chain_cert'],
|
|
||||||
use_common_cert=True if
|
|
||||||
context['use_common_cert'] == 'on'
|
|
||||||
else False,
|
|
||||||
interval=context['interval'],
|
|
||||||
timeout=context['timeout'],
|
|
||||||
send=context['send'],
|
|
||||||
receive=context['receive'],
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
exceptions.handle(request, e.message, ignore=False)
|
|
||||||
return False
|
|
@ -1,191 +0,0 @@
|
|||||||
# 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 django.utils.translation import ugettext as _
|
|
||||||
from octavia_dashboard import api
|
|
||||||
from . create_lb import * # noqa
|
|
||||||
|
|
||||||
INDEX_URL = "horizon:projects:loadbalancersv2:index"
|
|
||||||
|
|
||||||
|
|
||||||
READ_ONLY = {'readonly': 'readonly'}
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateLBDetailsAction(SetLBDetailsAction):
|
|
||||||
address = forms.CharField(widget=forms.widgets.Input(attrs=READ_ONLY),
|
|
||||||
label=_('IP'),
|
|
||||||
required=True)
|
|
||||||
|
|
||||||
name = forms.CharField(widget=forms.widgets.Input(attrs=READ_ONLY),
|
|
||||||
label=_('Name'),
|
|
||||||
required=False)
|
|
||||||
|
|
||||||
port = forms.IntegerField(widget=forms.widgets.Input(attrs=READ_ONLY),
|
|
||||||
label=_("LB Port"),
|
|
||||||
required=False,
|
|
||||||
min_value=1,
|
|
||||||
max_value=65535,
|
|
||||||
help_text=_("LB Port on which "
|
|
||||||
"LB is listening."))
|
|
||||||
|
|
||||||
is_update = True
|
|
||||||
|
|
||||||
def __init__(self, request, context, *args, **kwargs):
|
|
||||||
super(UpdateLBDetailsAction, self).__init__(request, context, *args,
|
|
||||||
**kwargs)
|
|
||||||
self.fields['address'].initial = context['address']
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = _("LB Details")
|
|
||||||
help_text_template = ("project/loadbalancersv2/"
|
|
||||||
"_launch_lb_help.html")
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateLBDetails(SetLBDetails):
|
|
||||||
action_class = UpdateLBDetailsAction
|
|
||||||
template_name = "project/loadbalancersv2/update_lb_step.html"
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateSSLAction(UploadSSLAction):
|
|
||||||
|
|
||||||
update_cert = forms.BooleanField(label='Update SSL Certificate',
|
|
||||||
required=False,
|
|
||||||
widget=forms.CheckboxInput())
|
|
||||||
|
|
||||||
# def clean(self):
|
|
||||||
# cleaned_data = super(UploadSSLAction, self).clean()
|
|
||||||
# data = self.data
|
|
||||||
# protocol = data.get('source_type')
|
|
||||||
# if protocol == 'HTTPS':
|
|
||||||
# update_cert = data.get('update_cert')
|
|
||||||
# if update_cert:
|
|
||||||
# use_common_cert = data.get('use_common_cert')
|
|
||||||
# if not use_common_cert:
|
|
||||||
# # check to see if ssl cert is provided
|
|
||||||
# cert_name = data.get('cert_name')
|
|
||||||
# cert = data.get('cert')
|
|
||||||
# private_key = data.get('private_key')
|
|
||||||
#
|
|
||||||
# if (not cert_name) \
|
|
||||||
# or (not cert) \
|
|
||||||
# or (not private_key):
|
|
||||||
# raise forms.ValidationError(
|
|
||||||
# _('Please provide all certificate parameters.'))
|
|
||||||
# return cleaned_data
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = _("SSL Certificate")
|
|
||||||
help_text_template = ("project/loadbalancersv2/_ssl_cert_help.html")
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateSSLStep(UploadSSLStep):
|
|
||||||
action_class = UpdateSSLAction
|
|
||||||
contributes = ("cert_name", "cert", "private_key",
|
|
||||||
"chain_cert", 'use_common_cert', "update_cert")
|
|
||||||
template_name = "project/loadbalancersv2/update_ssl_cert.html"
|
|
||||||
|
|
||||||
def contribute(self, data, context):
|
|
||||||
post = self.workflow.request.POST
|
|
||||||
context['cert_name'] = post['cert_name'] if 'cert_name' in post else ''
|
|
||||||
context['cert'] = post['cert'] if 'cert' in post else ''
|
|
||||||
context['private_key'] = post[
|
|
||||||
'private_key'] if 'private_key' in post else ''
|
|
||||||
context['chain_cert'] = post[
|
|
||||||
'chain_cert'] if 'chain_cert' in post else ''
|
|
||||||
context['use_common_cert'] = post[
|
|
||||||
'use_common_cert'] if 'use_common_cert' in post else ''
|
|
||||||
context['update_cert'] = post[
|
|
||||||
'update_cert'] if 'update_cert' in post else ''
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateInstancesAction(SelectInstancesAction):
|
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
|
||||||
super(UpdateInstancesAction, self).__init__(request, *args, **kwargs)
|
|
||||||
err_msg = _('Unable to retrieve members list. '
|
|
||||||
'Please try again later.')
|
|
||||||
|
|
||||||
pre_selectd = []
|
|
||||||
try:
|
|
||||||
pre_selectd = args[0]['selected_members']
|
|
||||||
except Exception:
|
|
||||||
exceptions.handle(request, err_msg)
|
|
||||||
self.fields[self.get_member_field_name('member')].initial = pre_selectd
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = _("Instances")
|
|
||||||
slug = "select_instances"
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateInstancesStep(SelectInstancesStep):
|
|
||||||
action_class = UpdateInstancesAction
|
|
||||||
depends_on = ("loadbalancer_id",)
|
|
||||||
contributes = ("wanted_members", "selected_members",
|
|
||||||
"loadbalancer_id", "instances_details",
|
|
||||||
"monitor", "instance_port")
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateLoadBalancer(LaunchLoadBalancer):
|
|
||||||
slug = "update_loadbalancer"
|
|
||||||
name = _("Edit Load Balancer")
|
|
||||||
finalize_button_name = _("Update")
|
|
||||||
success_message = _('Updated load balancer "%s".')
|
|
||||||
failure_message = _('Unable to modify load balancer "%s".')
|
|
||||||
success_url = "horizon:project:loadbalancersv2:index"
|
|
||||||
default_steps = (UpdateLBDetails,
|
|
||||||
UpdateSSLStep,
|
|
||||||
SelectMonitorStep,
|
|
||||||
UpdateInstancesStep)
|
|
||||||
attrs = {'data-help-text': 'Updating LB may take a few minutes'}
|
|
||||||
|
|
||||||
def format_status_message(self, message):
|
|
||||||
return message % self.context.get('name', 'unknown load balancer')
|
|
||||||
|
|
||||||
def handle(self, request, context):
|
|
||||||
|
|
||||||
try:
|
|
||||||
protocol = context['source_type']
|
|
||||||
|
|
||||||
api.lbui.vip_create(request,
|
|
||||||
update=True,
|
|
||||||
loadbalancer_id=context['loadbalancer_id'],
|
|
||||||
address=context['address'],
|
|
||||||
name=context['name'],
|
|
||||||
description=context['description'],
|
|
||||||
lb_method=context['lb_method'],
|
|
||||||
monitor=context['monitor'],
|
|
||||||
protocol=protocol,
|
|
||||||
port=context['port'],
|
|
||||||
instance_port=context['instance_port'],
|
|
||||||
wanted_members=context['wanted_members'],
|
|
||||||
instances_details=context['instances_details'],
|
|
||||||
cert_name=context['cert_name'],
|
|
||||||
cert=context['cert'],
|
|
||||||
private_key=context['private_key'],
|
|
||||||
chain_cert=context['chain_cert'],
|
|
||||||
use_common_cert=True if context[
|
|
||||||
'use_common_cert'] == 'on' else False,
|
|
||||||
update_cert=True if context[
|
|
||||||
'update_cert'] == 'on' else False,
|
|
||||||
interval=context['interval'],
|
|
||||||
timeout=context['timeout'],
|
|
||||||
send=context['send'],
|
|
||||||
receive=context['receive'],
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
exceptions.handle(request, e.message, ignore=False)
|
|
||||||
return False
|
|
@ -1,23 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
|
||||||
PANEL = 'loadbalancersv2'
|
|
||||||
# The slug of the dashboard the PANEL associated with. Required.
|
|
||||||
PANEL_DASHBOARD = 'project'
|
|
||||||
# The slug of the panel group the PANEL is associated with.
|
|
||||||
PANEL_GROUP = 'network'
|
|
||||||
|
|
||||||
# Python panel class of the PANEL to be added.
|
|
||||||
ADD_PANEL = (
|
|
||||||
'octavia_dashboard.dashboards.project.loadbalancersv2.panel'
|
|
||||||
'.LoadBalancersUI')
|
|
@ -101,15 +101,15 @@ settings.update_dashboards(dashboard_modules, HORIZON_CONFIG, INSTALLED_APPS)
|
|||||||
HORIZON_IMAGES_ALLOW_UPLOAD = True
|
HORIZON_IMAGES_ALLOW_UPLOAD = True
|
||||||
|
|
||||||
AVAILABLE_REGIONS = [
|
AVAILABLE_REGIONS = [
|
||||||
('http://localhost:5000/v2.0', 'local'),
|
('http://localhost/identity', 'local'),
|
||||||
('http://remote:5000/v2.0', 'remote'),
|
('http://remote/identity', 'remote'),
|
||||||
]
|
]
|
||||||
|
|
||||||
OPENSTACK_API_VERSIONS = {
|
OPENSTACK_API_VERSIONS = {
|
||||||
"identity": 3
|
"identity": 3
|
||||||
}
|
}
|
||||||
|
|
||||||
OPENSTACK_KEYSTONE_URL = "http://localhost:5000/v2.0"
|
OPENSTACK_KEYSTONE_URL = "http://localhost/identity"
|
||||||
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_"
|
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_"
|
||||||
|
|
||||||
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True
|
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True
|
||||||
|
@ -15,6 +15,8 @@ classifier =
|
|||||||
Programming Language :: Python
|
Programming Language :: Python
|
||||||
Programming Language :: Python :: 2
|
Programming Language :: Python :: 2
|
||||||
Programming Language :: Python :: 2.7
|
Programming Language :: Python :: 2.7
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
Programming Language :: Python :: 3.5
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
packages =
|
packages =
|
||||||
|
Loading…
Reference in New Issue
Block a user