octavia.common.data_models

Source code for octavia.common.data_models

#    Copyright (c) 2014 Rackspace
#    Copyright (c) 2016 Blue Box, an IBM Company
#    All Rights Reserved.
#
#    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
import six

from sqlalchemy.orm import collections

from octavia.common import constants


[docs]class BaseDataModel(object):
[docs] def to_dict(self, calling_classes=None, recurse=False, **kwargs): """Converts a data model to a dictionary.""" calling_classes = calling_classes or [] ret = {} for attr in self.__dict__: if attr.startswith('_') or not kwargs.get(attr, True): continue value = self.__dict__[attr] if recurse: if isinstance(getattr(self, attr), list): ret[attr] = [] for item in value: if isinstance(item, BaseDataModel): if type(self) not in calling_classes: ret[attr].append( item.to_dict(calling_classes=( calling_classes + [type(self)]))) else: ret[attr] = None else: ret[attr] = item elif isinstance(getattr(self, attr), BaseDataModel): if type(self) not in calling_classes: ret[attr] = value.to_dict( calling_classes=calling_classes + [type(self)]) else: ret[attr] = None elif six.PY2 and isinstance(value, six.text_type): ret[attr.encode('utf8')] = value.encode('utf8') else: ret[attr] = value else: if isinstance(getattr(self, attr), (BaseDataModel, list)): ret[attr] = None else: ret[attr] = value return ret
def __eq__(self, other): if isinstance(other, self.__class__): return self.to_dict() == other.to_dict() return False def __ne__(self, other): return not self.__eq__(other)
[docs] @classmethod def from_dict(cls, dict): return cls(**dict)
@classmethod def _name(cls): """Returns class name in a more human readable form.""" # Split the class name up by capitalized words return ' '.join(re.findall('[A-Z][^A-Z]*', cls.__name__)) def _get_unique_key(self, obj=None): """Returns a unique key for passed object for data model building.""" obj = obj or self # First handle all objects with their own ID, then handle subordinate # objects. if obj.__class__.__name__ in ['Member', 'Pool', 'LoadBalancer', 'Listener', 'Amphora', 'L7Policy', 'L7Rule']: return obj.__class__.__name__ + obj.id elif obj.__class__.__name__ in ['SessionPersistence', 'HealthMonitor']: return obj.__class__.__name__ + obj.pool_id elif obj.__class__.__name__ in ['ListenerStatistics']: return obj.__class__.__name__ + obj.listener_id + obj.amphora_id elif obj.__class__.__name__ in ['VRRPGroup', 'Vip']: return obj.__class__.__name__ + obj.load_balancer_id elif obj.__class__.__name__ in ['AmphoraHealth']: return obj.__class__.__name__ + obj.amphora_id elif obj.__class__.__name__ in ['SNI']: return (obj.__class__.__name__ + obj.listener_id + obj.tls_container_id) else: raise NotImplementedError def _find_in_graph(self, key, _visited_nodes=None): """Locates an object with the given unique key in the current object graph and returns a reference to it. """ _visited_nodes = _visited_nodes or [] mykey = self._get_unique_key() if mykey in _visited_nodes: # Seen this node already, don't traverse further return None elif mykey == key: return self else: _visited_nodes.append(mykey) attr_names = [attr_name for attr_name in dir(self) if not attr_name.startswith('_')] for attr_name in attr_names: attr = getattr(self, attr_name) if isinstance(attr, BaseDataModel): result = attr._find_in_graph( key, _visited_nodes=_visited_nodes) if result is not None: return result elif isinstance(attr, (collections.InstrumentedList, list)): for item in attr: if isinstance(item, BaseDataModel): result = item._find_in_graph( key, _visited_nodes=_visited_nodes) if result is not None: return result # If we are here we didn't find it. return None
[docs] def update(self, update_dict): """Generic update method which works for simple, non-relational attributes. """ for key, value in update_dict.items(): setattr(self, key, value)
[docs]class SessionPersistence(BaseDataModel): def __init__(self, pool_id=None, type=None, cookie_name=None, pool=None): self.pool_id = pool_id self.type = type self.cookie_name = cookie_name self.pool = pool
[docs] def delete(self): self.pool.session_persistence = None
[docs]class ListenerStatistics(BaseDataModel): def __init__(self, listener_id=None, amphora_id=None, bytes_in=0, bytes_out=0, active_connections=0, total_connections=0, request_errors=0): self.listener_id = listener_id self.amphora_id = amphora_id self.bytes_in = bytes_in self.bytes_out = bytes_out self.active_connections = active_connections self.total_connections = total_connections self.request_errors = request_errors
[docs] def get_stats(self): stats = { 'bytes_in': self.bytes_in, 'bytes_out': self.bytes_out, 'active_connections': self.active_connections, 'total_connections': self.total_connections, 'request_errors': self.request_errors, } return stats
def __iadd__(self, other): if isinstance(other, ListenerStatistics): self.bytes_in += other.bytes_in self.bytes_out += other.bytes_out self.request_errors += other.request_errors self.total_connections += other.total_connections return self
[docs]class LoadBalancerStatistics(BaseDataModel): def __init__(self, bytes_in=0, bytes_out=0, active_connections=0, total_connections=0, request_errors=0, listeners=None): self.bytes_in = bytes_in self.bytes_out = bytes_out self.active_connections = active_connections self.total_connections = total_connections self.request_errors = request_errors self.listeners = listeners or []
[docs] def get_stats(self): stats = { 'bytes_in': self.bytes_in, 'bytes_out': self.bytes_out, 'active_connections': self.active_connections, 'total_connections': self.total_connections, 'request_errors': self.request_errors, } return stats
[docs]class HealthMonitor(BaseDataModel): def __init__(self, id=None, project_id=None, pool_id=None, type=None, delay=None, timeout=None, fall_threshold=None, rise_threshold=None, http_method=None, url_path=None, expected_codes=None, enabled=None, pool=None, name=None, provisioning_status=None, operating_status=None, created_at=None, updated_at=None): self.id = id self.project_id = project_id self.pool_id = pool_id self.type = type self.delay = delay self.timeout = timeout self.fall_threshold = fall_threshold self.rise_threshold = rise_threshold self.http_method = http_method self.url_path = url_path self.expected_codes = expected_codes self.enabled = enabled self.pool = pool self.provisioning_status = provisioning_status self.operating_status = operating_status self.name = name self.created_at = created_at self.updated_at = updated_at
[docs] def delete(self): self.pool.health_monitor = None
[docs]class Pool(BaseDataModel): def __init__(self, id=None, project_id=None, name=None, description=None, protocol=None, lb_algorithm=None, enabled=None, operating_status=None, members=None, health_monitor=None, session_persistence=None, load_balancer_id=None, load_balancer=None, listeners=None, l7policies=None, created_at=None, updated_at=None, provisioning_status=None): self.id = id self.project_id = project_id self.name = name self.description = description self.load_balancer_id = load_balancer_id self.load_balancer = load_balancer self.protocol = protocol self.lb_algorithm = lb_algorithm self.enabled = enabled self.operating_status = operating_status self.members = members or [] self.health_monitor = health_monitor self.session_persistence = session_persistence self.listeners = listeners or [] self.l7policies = l7policies or [] self.created_at = created_at self.updated_at = updated_at self.provisioning_status = provisioning_status
[docs] def update(self, update_dict): for key, value in update_dict.items(): if key == 'session_persistence': if value is None or value == {}: if self.session_persistence is not None: self.session_persistence.delete() elif self.session_persistence is not None: self.session_persistence.update(value) else: value.update({'pool_id': self.id}) self.session_persistence = SessionPersistence(**value) else: setattr(self, key, value)
[docs] def delete(self): for listener in self.listeners: if listener.default_pool_id == self.id: listener.default_pool = None listener.default_pool_id = None for pool in listener.pools: if pool.id == self.id: listener.pools.remove(pool) break for pool in self.load_balancer.pools: if pool.id == self.id: self.load_balancer.pools.remove(pool) break for l7policy in self.l7policies: if l7policy.redirect_pool_id == self.id: # Technically this should never happen, as we block deletion # of pools in use by L7Policies at the API. However, we should # probably keep this here in case the data model gets # manipulated in some other way in the future. l7policy.action = constants.L7POLICY_ACTION_REJECT l7policy.redirect_pool = None l7policy.redirect_pool_id = None
[docs]class Member(BaseDataModel): def __init__(self, id=None, project_id=None, pool_id=None, ip_address=None, protocol_port=None, weight=None, enabled=None, subnet_id=None, operating_status=None, pool=None, created_at=None, updated_at=None, provisioning_status=None, name=None, monitor_address=None, monitor_port=None): self.id = id self.project_id = project_id self.pool_id = pool_id self.ip_address = ip_address self.protocol_port = protocol_port self.weight = weight self.enabled = enabled self.subnet_id = subnet_id self.operating_status = operating_status self.pool = pool self.created_at = created_at self.updated_at = updated_at self.provisioning_status = provisioning_status self.name = name self.monitor_address = monitor_address self.monitor_port = monitor_port
[docs] def delete(self): for mem in self.pool.members: if mem.id == self.id: self.pool.members.remove(mem) break
[docs]class Listener(BaseDataModel): def __init__(self, id=None, project_id=None, name=None, description=None, default_pool_id=None, load_balancer_id=None, protocol=None, protocol_port=None, connection_limit=None, enabled=None, provisioning_status=None, operating_status=None, tls_certificate_id=None, stats=None, default_pool=None, load_balancer=None, sni_containers=None, peer_port=None, l7policies=None, pools=None, insert_headers=None, created_at=None, updated_at=None): self.id = id self.project_id = project_id self.name = name self.description = description self.default_pool_id = default_pool_id self.load_balancer_id = load_balancer_id self.protocol = protocol self.protocol_port = protocol_port self.connection_limit = connection_limit self.enabled = enabled self.provisioning_status = provisioning_status self.operating_status = operating_status self.tls_certificate_id = tls_certificate_id self.stats = stats self.default_pool = default_pool self.load_balancer = load_balancer self.sni_containers = sni_containers or [] self.peer_port = peer_port self.l7policies = l7policies or [] self.insert_headers = insert_headers or {} self.pools = pools or [] self.created_at = created_at self.updated_at = updated_at
[docs] def update(self, update_dict): for key, value in update_dict.items(): setattr(self, key, value) if key == 'default_pool_id': if self.default_pool is not None: l7_pool_ids = [p.redirect_pool_id for p in self.l7policies if p.redirect_pool_id is not None and len(p.l7rules) > 0 and p.enabled is True] old_pool = self.default_pool if old_pool.id not in l7_pool_ids: self.pools.remove(old_pool) old_pool.listeners.remove(self) if value is not None: pool = self._find_in_graph('Pool' + value) if pool not in self.pools: self.pools.append(pool) if self not in pool.listeners: pool.listeners.append(self) else: pool = None setattr(self, 'default_pool', pool)
[docs] def delete(self): for listener in self.load_balancer.listeners: if listener.id == self.id: self.load_balancer.listeners.remove(listener) break for pool in self.pools: pool.listeners.remove(self)
[docs]class LoadBalancer(BaseDataModel): def __init__(self, id=None, project_id=None, name=None, description=None, provisioning_status=None, operating_status=None, enabled=None, topology=None, vip=None, listeners=None, amphorae=None, pools=None, vrrp_group=None, server_group_id=None, created_at=None, updated_at=None): self.id = id self.project_id = project_id self.name = name self.description = description self.provisioning_status = provisioning_status self.operating_status = operating_status self.enabled = enabled self.vip = vip self.vrrp_group = vrrp_group self.topology = topology self.listeners = listeners or [] self.amphorae = amphorae or [] self.pools = pools or [] self.server_group_id = server_group_id self.created_at = created_at self.updated_at = updated_at
[docs]class VRRPGroup(BaseDataModel): def __init__(self, load_balancer_id=None, vrrp_group_name=None, vrrp_auth_type=None, vrrp_auth_pass=None, advert_int=None, smtp_server=None, smtp_connect_timeout=None, load_balancer=None): self.load_balancer_id = load_balancer_id self.vrrp_group_name = vrrp_group_name self.vrrp_auth_type = vrrp_auth_type self.vrrp_auth_pass = vrrp_auth_pass self.advert_int = advert_int self.load_balancer = load_balancer
[docs]class Vip(BaseDataModel): def __init__(self, load_balancer_id=None, ip_address=None, subnet_id=None, network_id=None, port_id=None, load_balancer=None): self.load_balancer_id = load_balancer_id self.ip_address = ip_address self.subnet_id = subnet_id self.network_id = network_id self.port_id = port_id self.load_balancer = load_balancer
[docs]class SNI(BaseDataModel): def __init__(self, listener_id=None, position=None, listener=None, tls_container_id=None): self.listener_id = listener_id self.position = position self.listener = listener self.tls_container_id = tls_container_id
[docs]class TLSContainer(BaseDataModel): def __init__(self, id=None, primary_cn=None, certificate=None, private_key=None, passphrase=None, intermediates=None): self.id = id self.primary_cn = primary_cn self.certificate = certificate self.private_key = private_key self.passphrase = passphrase self.intermediates = intermediates or []
[docs]class Amphora(BaseDataModel): def __init__(self, id=None, load_balancer_id=None, compute_id=None, status=None, lb_network_ip=None, vrrp_ip=None, ha_ip=None, vrrp_port_id=None, ha_port_id=None, load_balancer=None, role=None, cert_expiration=None, cert_busy=False, vrrp_interface=None, vrrp_id=None, vrrp_priority=None): self.id = id self.load_balancer_id = load_balancer_id self.compute_id = compute_id self.status = status self.lb_network_ip = lb_network_ip self.vrrp_ip = vrrp_ip self.ha_ip = ha_ip self.vrrp_port_id = vrrp_port_id self.ha_port_id = ha_port_id self.role = role self.vrrp_interface = vrrp_interface self.vrrp_id = vrrp_id self.vrrp_priority = vrrp_priority self.load_balancer = load_balancer self.cert_expiration = cert_expiration self.cert_busy = cert_busy
[docs] def delete(self): for amphora in self.load_balancer.amphorae: if amphora.id == self.id: self.load_balancer.amphorae.remove(amphora) break
[docs]class AmphoraHealth(BaseDataModel): def __init__(self, amphora_id=None, last_update=None, busy=False): self.amphora_id = amphora_id self.last_update = last_update self.busy = busy
[docs]class L7Rule(BaseDataModel): def __init__(self, id=None, l7policy_id=None, type=None, enabled=None, compare_type=None, key=None, value=None, l7policy=None, invert=False, provisioning_status=None, operating_status=None, project_id=None, created_at=None, updated_at=None): self.id = id self.l7policy_id = l7policy_id self.type = type self.compare_type = compare_type self.key = key self.value = value self.l7policy = l7policy self.invert = invert self.provisioning_status = provisioning_status self.operating_status = operating_status self.project_id = project_id self.created_at = created_at self.updated_at = updated_at self.enabled = enabled
[docs] def delete(self): if len(self.l7policy.l7rules) == 1: # l7policy should disappear from pool and listener lists. Since # we are operating only on the data model, we can fake this by # calling the policy's delete method. self.l7policy.delete() for r in self.l7policy.l7rules: if r.id == self.id: self.l7policy.l7rules.remove(r) break
[docs]class L7Policy(BaseDataModel): def __init__(self, id=None, name=None, description=None, listener_id=None, action=None, redirect_pool_id=None, redirect_url=None, position=None, listener=None, redirect_pool=None, enabled=None, l7rules=None, provisioning_status=None, operating_status=None, project_id=None, created_at=None, updated_at=None): self.id = id self.name = name self.description = description self.listener_id = listener_id self.action = action self.redirect_pool_id = redirect_pool_id self.redirect_url = redirect_url self.position = position self.listener = listener self.redirect_pool = redirect_pool self.enabled = enabled self.l7rules = l7rules or [] self.provisioning_status = provisioning_status self.operating_status = operating_status self.project_id = project_id self.created_at = created_at self.updated_at = updated_at def _conditionally_remove_pool_links(self, pool): """Removes links to the given pool from parent objects. Note this only happens if our listener isn't referencing the pool via its default_pool or another active l7policy's redirect_pool_id. """ if (self.listener.default_pool is not None and pool is not None and pool.id != self.listener.default_pool.id and pool in self.listener.pools): listener_l7pools = [ p.redirect_pool for p in self.listener.l7policies if p.redirect_pool is not None and len(p.l7rules) > 0 and p.enabled is True and p.id != self.id] if pool not in listener_l7pools: self.listener.pools.remove(pool) pool.listeners.remove(self.listener)
[docs] def update(self, update_dict): for key, value in update_dict.items(): if key == 'redirect_pool_id' and value is not None: self._conditionally_remove_pool_links(self.redirect_pool) self.action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL self.redirect_url = None pool = self._find_in_graph('Pool' + value) self.redirect_pool = pool if len(self.l7rules) > 0 and (self.enabled is True or ( 'enabled' in update_dict.keys() and update_dict['enabled'] is True)): if pool not in self.listener.pools: self.listener.pools.append(pool) if self.listener not in pool.listeners: pool.listeners.append(self.listener) elif key == 'redirect_url' and value is not None: self.action = constants.L7POLICY_ACTION_REDIRECT_TO_URL self._conditionally_remove_pool_links(self.redirect_pool) self.redirect_pool = None self.redirect_pool_id = None elif key == 'action' and value == constants.L7POLICY_ACTION_REJECT: self.redirect_url = None self._conditionally_remove_pool_links(self.redirect_pool) self.redirect_pool = None self.redirect_pool_id = None elif key == 'position': self.listener.l7policies.remove(self) self.listener.l7policies.insert(value - 1, self) elif key == 'enabled': if (value is True and self.action == constants.L7POLICY_ACTION_REDIRECT_TO_POOL and self.redirect_pool is not None and len(self.l7rules) > 0 and self.redirect_pool not in self.listener.pools): self.listener.pools.append(self.redirect_pool) self.redirect_pool.listeners.append(self.listener) elif (value is False and self.action == constants.L7POLICY_ACTION_REDIRECT_TO_POOL and self.redirect_pool is not None): self._conditionally_remove_pool_links( self.redirect_pool) setattr(self, key, value)
[docs] def delete(self): self._conditionally_remove_pool_links(self.redirect_pool) if self.redirect_pool: for p in self.redirect_pool.l7policies: if p.id == self.id: self.redirect_pool.l7policies.remove(p) for p in self.listener.l7policies: if p.id == self.id: self.listener.l7policies.remove(p) break
[docs]class Quotas(BaseDataModel): def __init__(self, project_id=None, load_balancer=None, listener=None, pool=None, health_monitor=None, member=None, in_use_health_monitor=None, in_use_listener=None, in_use_load_balancer=None, in_use_member=None, in_use_pool=None): self.project_id = project_id self.health_monitor = health_monitor self.listener = listener self.load_balancer = load_balancer self.pool = pool self.member = member self.in_use_health_monitor = in_use_health_monitor self.in_use_listener = in_use_listener self.in_use_load_balancer = in_use_load_balancer self.in_use_member = in_use_member self.in_use_pool = in_use_pool
Creative Commons Attribution 3.0 License

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.