Skip to content
This repository was archived by the owner on Jul 9, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 203 additions & 3 deletions lib/charm/openstack/adapters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
"""Adapter classes and utilities for use with Reactive interfaces"""

from charmhelpers.core import hookenv
import charms.reactive.bus as reactive_bus
import charmhelpers.contrib.hahelpers.cluster as ch_cluster
import charmhelpers.contrib.network.ip as ch_ip
import charmhelpers.contrib.openstack.utils as ch_utils
import charmhelpers.core.hookenv as hookenv

ADDRESS_TYPES = ['admin', 'internal', 'public']


class OpenStackRelationAdapter(object):
Expand Down Expand Up @@ -82,6 +88,49 @@ def hosts(self):
return None


class PeerHARelationAdapter(OpenStackRelationAdapter):
"""
Adapter for cluster relation of nodes of the same service
"""

interface_type = "cluster"

def __init__(self, relation):
super(PeerHARelationAdapter, self).__init__(relation)
self.config = hookenv.config()
self.local_address = APIConfigurationAdapter().local_address
self.local_unit_name = APIConfigurationAdapter().local_unit_name
self.cluster_hosts = {}
self.add_network_split_addresses()
self.add_default_addresses()

def add_network_split_addresses(self):
"""Populate cluster_hosts with addresses of peers on a given network if
this node is also on that network"""
for addr_type in ADDRESS_TYPES:
cfg_opt = 'os-{}-network'.format(addr_type)
laddr = ch_ip.get_address_in_network(self.config.get(cfg_opt))
if laddr:
netmask = ch_ip.get_netmask_for_address(laddr)
self.cluster_hosts[laddr] = {
'network': "{}/{}".format(laddr, netmask),
'backends': {self.local_unit_name: laddr}}
key = '{}-address'.format(addr_type)
for _unit, _laddr in self.relation.ip_map(address_key=key):
self.cluster_hosts[laddr]['backends'][_unit] = _laddr

def add_default_addresses(self):
"""Populate cluster_hosts with addresses supplied by private-address
"""
self.cluster_hosts[self.local_address] = {}
netmask = ch_ip.get_netmask_for_address(self.local_address)
self.cluster_hosts[self.local_address] = {
'network': "{}/{}".format(self.local_address, netmask),
'backends': {self.local_unit_name: self.local_address}}
for _unit, _laddr in self.relation.ip_map():
self.cluster_hosts[self.local_address]['backends'][_unit] = _laddr


class DatabaseRelationAdapter(OpenStackRelationAdapter):
"""
Adapter for the Database relation interface.
Expand Down Expand Up @@ -148,6 +197,153 @@ def __init__(self):
setattr(self, k, v)


class APIConfigurationAdapter(ConfigurationAdapter):
"""This configuration adapter extends the base class and adds properties
common accross most OpenstackAPI services"""

def __init__(self, port_map=None):
super(APIConfigurationAdapter, self).__init__()
self.port_map = port_map
self.config = hookenv.config()

@property
def ipv6_mode(self):
"""Return if charm should enable IPv6

@return True if user has requested ipv6 support otherwise False
"""
return self.config.get('prefer-ipv6', False)

@property
def local_address(self):
"""Return remotely accessible address of charm (not localhost)

@return True if user has requested ipv6 support otherwise False
"""
if self.ipv6_mode:
addr = ch_ip.get_ipv6_addr(exc_list=[self.config('vip')])[0]
else:
addr = ch_utils.get_host_ip(hookenv.unit_get('private-address'))
return addr

@property
def local_unit_name(self):
"""
@return local unit name
"""
return hookenv.local_unit().replace('/', '-')

@property
def local_host(self):
"""Return localhost address depending on whether IPv6 is enabled

@return localhost ip address
"""
return 'ip6-localhost' if self.ipv6_mode else '127.0.0.1'

@property
def haproxy_host(self):
"""Return haproxy bind address depending on whether IPv6 is enabled

@return address
"""
return '::' if self.ipv6_mode else '0.0.0.0'

@property
def haproxy_stat_port(self):
"""Port to listen on to access haproxy statistics

@return port
"""
return '8888'

@property
def haproxy_stat_password(self):
"""Password for accessing haproxy statistics

@return password
"""
return reactive_bus.get_state('haproxy.stat.password')

@property
def service_ports(self):
"""Dict of service names and the ports they listen on

@return {'svc1': 'portA', 'svc2': 'portB', ...}
"""
service_ports = {}
if self.port_map:
for service in self.port_map.keys():
service_ports[service] = [
self.port_map[service]['admin'],
ch_cluster.determine_apache_port(
self.port_map[service]['admin'],
singlenode_mode=True)]
return service_ports

@property
def service_listen_info(self):
"""Dict of service names and attributes for backend to listen on

@return {
'svc1': {
'proto': 'http',
'ip': '10.0.0.10',
'port': '8080',
'url': 'http://10.0.0.10:8080},
'svc2': {
'proto': 'https',
'ip': '10.0.0.20',
'port': '8443',
'url': 'https://10.0.0.20:8443},
...

"""
info = {}
if self.port_map:
for service in self.port_map.keys():
key = service.replace('-', '_')
info[key] = {
'proto': 'http',
'ip': self.local_address,
'port': ch_cluster.determine_apache_port(
self.port_map[service]['admin'],
singlenode_mode=True)}
info[key]['url'] = '{proto}://{ip}:{port}'.format(**info[key])
return info

@property
def external_endpoints(self):
"""Dict of service names and attributes that clients use to connect

@return {
'svc1': {
'proto': 'http',
'ip': '10.0.0.10',
'port': '8080',
'url': 'http://10.0.0.10:8080},
'svc2': {
'proto': 'https',
'ip': '10.0.0.20',
'port': '8443',
'url': 'https://10.0.0.20:8443},
...

"""
info = {}
info = {}
ip = self.config.get('vip', self.local_address)
if self.port_map:
for service in self.port_map.keys():
key = service.replace('-', '_')
info[key] = {
'proto': 'http',
'ip': ip,
'port': self.port_map[service]['admin']}
info[key]['url'] = '{proto}://{ip}:{port}'.format(**info[key])
return info


class OpenStackRelationAdapters(object):
"""
Base adapters class for OpenStack Charms, used to aggregate
Expand All @@ -171,13 +367,17 @@ class OpenStackRelationAdapters(object):
_adapters = {
'amqp': RabbitMQRelationAdapter,
'shared_db': DatabaseRelationAdapter,
'cluster': PeerHARelationAdapter,
}
"""
Default adapter mappings; may be overridden by relation adapters
in subclasses.

Additional kwargs can be passed to the configuration adapterwhich has been
specified via the options parameter
"""

def __init__(self, relations, options=ConfigurationAdapter):
def __init__(self, relations, options=ConfigurationAdapter, **kwargs):
self._adapters.update(self.relation_adapters)
self._relations = []
for relation in relations:
Expand All @@ -188,7 +388,7 @@ def __init__(self, relations, options=ConfigurationAdapter):
relation_value = OpenStackRelationAdapter(relation)
setattr(self, relation_name, relation_value)
self._relations.append(relation_name)
self.options = options()
self.options = options(**kwargs)
self._relations.append('options')

def __iter__(self):
Expand Down
Loading