"Fossies" - the Fresh Open Source Software Archive

Member "octavia-8.0.0/octavia/common/data_models.py" (14 Apr 2021, 34583 Bytes) of package /linux/misc/openstack/octavia-8.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "data_models.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 7.1.1_vs_8.0.0.

    1 #    Copyright (c) 2014 Rackspace
    2 #    Copyright (c) 2016 Blue Box, an IBM Company
    3 #    All Rights Reserved.
    4 #
    5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    6 #    not use this file except in compliance with the License. You may obtain
    7 #    a copy of the License at
    8 #
    9 #         http://www.apache.org/licenses/LICENSE-2.0
   10 #
   11 #    Unless required by applicable law or agreed to in writing, software
   12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   14 #    License for the specific language governing permissions and limitations
   15 #    under the License.
   16 
   17 import datetime
   18 import re
   19 
   20 from oslo_log import log as logging
   21 from sqlalchemy.orm import collections
   22 
   23 from octavia.common import constants
   24 
   25 LOG = logging.getLogger(__name__)
   26 
   27 
   28 class BaseDataModel(object):
   29     def to_dict(self, calling_classes=None, recurse=False, **kwargs):
   30         """Converts a data model to a dictionary."""
   31         calling_classes = calling_classes or []
   32         ret = {}
   33         for attr in self.__dict__:
   34             if attr.startswith('_') or not kwargs.get(attr, True):
   35                 continue
   36             value = self.__dict__[attr]
   37             if attr == 'tags':
   38                 # tags is a list, it doesn't need recurse
   39                 ret[attr] = value
   40                 continue
   41             # We need to have json convertible data for storing it in
   42             # persistence jobboard backend.
   43             if isinstance(value, datetime.datetime):
   44                 ret[attr] = value.isoformat()
   45                 continue
   46             if isinstance(value, bytes):
   47                 ret[attr] = value.decode()
   48                 continue
   49             if recurse:
   50                 if isinstance(getattr(self, attr), list):
   51                     ret[attr] = []
   52                     for item in value:
   53                         if isinstance(item, BaseDataModel):
   54                             if type(self) not in calling_classes:
   55                                 ret[attr].append(
   56                                     item.to_dict(calling_classes=(
   57                                         calling_classes + [type(self)]),
   58                                         recurse=recurse))
   59                             else:
   60                                 # TODO(rm_work): Is the idea that if this list
   61                                 #  contains ANY BaseDataModel, that all of them
   62                                 #  are data models, and we may as well quit?
   63                                 #  Or, were we supposed to append a `None` for
   64                                 #  each one? I assume the former?
   65                                 ret[attr] = None
   66                                 break
   67                         else:
   68                             ret[attr].append(item)
   69                 elif isinstance(getattr(self, attr), BaseDataModel):
   70                     if type(self) not in calling_classes:
   71                         ret[attr] = value.to_dict(
   72                             calling_classes=calling_classes + [type(self)],
   73                             recurse=recurse)
   74                     else:
   75                         ret[attr] = None
   76                 else:
   77                     ret[attr] = value
   78             else:
   79                 if isinstance(getattr(self, attr), BaseDataModel):
   80                     ret[attr] = None
   81                 elif isinstance(getattr(self, attr), list):
   82                     ret[attr] = []
   83                 else:
   84                     ret[attr] = value
   85 
   86         return ret
   87 
   88     def __eq__(self, other):
   89         if isinstance(other, self.__class__):
   90             return self.to_dict() == other.to_dict()
   91         return False
   92 
   93     def __ne__(self, other):
   94         return not self.__eq__(other)
   95 
   96     @classmethod
   97     def from_dict(cls, dict):
   98         return cls(**dict)
   99 
  100     @classmethod
  101     def _name(cls):
  102         """Returns class name in a more human readable form."""
  103         # Split the class name up by capitalized words
  104         return ' '.join(re.findall('[A-Z][^A-Z]*', cls.__name__))
  105 
  106     def _get_unique_key(self, obj=None):
  107         """Returns a unique key for passed object for data model building."""
  108         obj = obj or self
  109         # First handle all objects with their own ID, then handle subordinate
  110         # objects.
  111         if obj.__class__.__name__ in ['Member', 'Pool', 'LoadBalancer',
  112                                       'Listener', 'Amphora', 'L7Policy',
  113                                       'L7Rule']:
  114             return obj.__class__.__name__ + obj.id
  115         if obj.__class__.__name__ in ['SessionPersistence', 'HealthMonitor']:
  116             return obj.__class__.__name__ + obj.pool_id
  117         if obj.__class__.__name__ in ['ListenerStatistics']:
  118             return obj.__class__.__name__ + obj.listener_id + obj.amphora_id
  119         if obj.__class__.__name__ in ['ListenerCidr']:
  120             return obj.__class__.__name__ + obj.listener_id + obj.cidr
  121         if obj.__class__.__name__ in ['VRRPGroup', 'Vip']:
  122             return obj.__class__.__name__ + obj.load_balancer_id
  123         if obj.__class__.__name__ in ['AmphoraHealth']:
  124             return obj.__class__.__name__ + obj.amphora_id
  125         if obj.__class__.__name__ in ['SNI']:
  126             return (obj.__class__.__name__ +
  127                     obj.listener_id + obj.tls_container_id)
  128         raise NotImplementedError
  129 
  130     def _find_in_graph(self, key, _visited_nodes=None):
  131         """Locates an object with the given unique key in the current
  132 
  133         object graph and returns a reference to it.
  134         """
  135         _visited_nodes = _visited_nodes or []
  136         mykey = self._get_unique_key()
  137         if mykey in _visited_nodes:
  138             # Seen this node already, don't traverse further
  139             return None
  140         if mykey == key:
  141             return self
  142         _visited_nodes.append(mykey)
  143         attr_names = [attr_name for attr_name in dir(self)
  144                       if not attr_name.startswith('_')]
  145         for attr_name in attr_names:
  146             attr = getattr(self, attr_name)
  147             if isinstance(attr, BaseDataModel):
  148                 result = attr._find_in_graph(
  149                     key, _visited_nodes=_visited_nodes)
  150                 if result is not None:
  151                     return result
  152             elif isinstance(attr, (collections.InstrumentedList, list)):
  153                 for item in attr:
  154                     if isinstance(item, BaseDataModel):
  155                         result = item._find_in_graph(
  156                             key, _visited_nodes=_visited_nodes)
  157                         if result is not None:
  158                             return result
  159         # If we are here we didn't find it.
  160         return None
  161 
  162     def update(self, update_dict):
  163         """Generic update method which works for simple,
  164 
  165         non-relational attributes.
  166         """
  167         for key, value in update_dict.items():
  168             setattr(self, key, value)
  169 
  170 
  171 class SessionPersistence(BaseDataModel):
  172 
  173     def __init__(self, pool_id=None, type=None, cookie_name=None,
  174                  pool=None, persistence_timeout=None,
  175                  persistence_granularity=None):
  176         self.pool_id = pool_id
  177         self.type = type
  178         self.cookie_name = cookie_name
  179         self.pool = pool
  180         self.persistence_timeout = persistence_timeout
  181         self.persistence_granularity = persistence_granularity
  182 
  183     def delete(self):
  184         self.pool.session_persistence = None
  185 
  186 
  187 class ListenerStatistics(BaseDataModel):
  188 
  189     def __init__(self, listener_id=None, amphora_id=None, bytes_in=0,
  190                  bytes_out=0, active_connections=0,
  191                  total_connections=0, request_errors=0, received_time=0.0):
  192         self.listener_id = listener_id
  193         self.amphora_id = amphora_id
  194         self.bytes_in = bytes_in
  195         self.bytes_out = bytes_out
  196         self.active_connections = active_connections
  197         self.total_connections = total_connections
  198         self.request_errors = request_errors
  199         self.received_time = received_time
  200 
  201     def get_stats(self):
  202         stats = {
  203             'bytes_in': self.bytes_in,
  204             'bytes_out': self.bytes_out,
  205             'active_connections': self.active_connections,
  206             'total_connections': self.total_connections,
  207             'request_errors': self.request_errors,
  208         }
  209         return stats
  210 
  211     def db_fields(self):
  212         fields = self.to_dict()
  213         fields.pop('received_time')
  214         return fields
  215 
  216     def __iadd__(self, other):
  217         if isinstance(other, ListenerStatistics):
  218             self.bytes_in += other.bytes_in
  219             self.bytes_out += other.bytes_out
  220             self.request_errors += other.request_errors
  221             self.total_connections += other.total_connections
  222         else:
  223             raise TypeError(  # noqa: O342
  224                 "unsupported operand type(s) for +=: '{0}' and '{1}'".format(
  225                     type(self), type(other)))
  226 
  227         return self
  228 
  229 
  230 class LoadBalancerStatistics(BaseDataModel):
  231 
  232     def __init__(self, bytes_in=0, bytes_out=0, active_connections=0,
  233                  total_connections=0, request_errors=0, listeners=None):
  234         self.bytes_in = bytes_in
  235         self.bytes_out = bytes_out
  236         self.active_connections = active_connections
  237         self.total_connections = total_connections
  238         self.request_errors = request_errors
  239         self.listeners = listeners or []
  240 
  241     def get_stats(self):
  242         stats = {
  243             'bytes_in': self.bytes_in,
  244             'bytes_out': self.bytes_out,
  245             'active_connections': self.active_connections,
  246             'total_connections': self.total_connections,
  247             'request_errors': self.request_errors,
  248         }
  249         return stats
  250 
  251 
  252 class HealthMonitor(BaseDataModel):
  253 
  254     def __init__(self, id=None, project_id=None, pool_id=None, type=None,
  255                  delay=None, timeout=None, fall_threshold=None,
  256                  rise_threshold=None, http_method=None, url_path=None,
  257                  expected_codes=None, enabled=None, pool=None, name=None,
  258                  provisioning_status=None, operating_status=None,
  259                  created_at=None, updated_at=None, tags=None,
  260                  http_version=None, domain_name=None):
  261         self.id = id
  262         self.project_id = project_id
  263         self.pool_id = pool_id
  264         self.type = type
  265         self.delay = delay
  266         self.timeout = timeout
  267         self.fall_threshold = fall_threshold
  268         self.rise_threshold = rise_threshold
  269         self.http_method = http_method
  270         self.url_path = url_path
  271         self.expected_codes = expected_codes
  272         self.enabled = enabled
  273         self.pool = pool
  274         self.provisioning_status = provisioning_status
  275         self.operating_status = operating_status
  276         self.name = name
  277         self.created_at = created_at
  278         self.updated_at = updated_at
  279         self.tags = tags
  280         self.http_version = http_version
  281         self.domain_name = domain_name
  282 
  283     def delete(self):
  284         self.pool.health_monitor = None
  285 
  286 
  287 class Pool(BaseDataModel):
  288     def __init__(self, id=None, project_id=None, name=None, description=None,
  289                  protocol=None, lb_algorithm=None, enabled=None,
  290                  operating_status=None, members=None, health_monitor=None,
  291                  session_persistence=None, load_balancer_id=None,
  292                  load_balancer=None, listeners=None, l7policies=None,
  293                  created_at=None, updated_at=None, provisioning_status=None,
  294                  tags=None, tls_certificate_id=None,
  295                  ca_tls_certificate_id=None, crl_container_id=None,
  296                  tls_enabled=None, tls_ciphers=None, tls_versions=None,
  297                  alpn_protocols=None):
  298         self.id = id
  299         self.project_id = project_id
  300         self.name = name
  301         self.description = description
  302         self.load_balancer_id = load_balancer_id
  303         self.load_balancer = load_balancer
  304         self.protocol = protocol
  305         self.lb_algorithm = lb_algorithm
  306         self.enabled = enabled
  307         self.operating_status = operating_status
  308         self.members = members or []
  309         self.health_monitor = health_monitor
  310         self.session_persistence = session_persistence
  311         self.listeners = listeners or []
  312         self.l7policies = l7policies or []
  313         self.created_at = created_at
  314         self.updated_at = updated_at
  315         self.provisioning_status = provisioning_status
  316         self.tags = tags
  317         self.tls_certificate_id = tls_certificate_id
  318         self.ca_tls_certificate_id = ca_tls_certificate_id
  319         self.crl_container_id = crl_container_id
  320         self.tls_enabled = tls_enabled
  321         self.tls_ciphers = tls_ciphers
  322         self.tls_versions = tls_versions
  323         self.alpn_protocols = alpn_protocols
  324 
  325     def update(self, update_dict):
  326         for key, value in update_dict.items():
  327             if key == 'session_persistence':
  328                 if value is None or value == {}:
  329                     if self.session_persistence is not None:
  330                         self.session_persistence.delete()
  331                 elif self.session_persistence is not None:
  332                     self.session_persistence.update(value)
  333                 else:
  334                     value.update({'pool_id': self.id})
  335                     self.session_persistence = SessionPersistence(**value)
  336             else:
  337                 setattr(self, key, value)
  338 
  339     def delete(self):
  340         for listener in self.listeners:
  341             if listener.default_pool_id == self.id:
  342                 listener.default_pool = None
  343                 listener.default_pool_id = None
  344             for pool in listener.pools:
  345                 if pool.id == self.id:
  346                     listener.pools.remove(pool)
  347                     break
  348         for pool in self.load_balancer.pools:
  349             if pool.id == self.id:
  350                 try:
  351                     self.load_balancer.pools.remove(pool)
  352                 except ValueError:
  353                     LOG.debug("Pool %s has already been removed from load "
  354                               "balancer pools list.", pool.id)
  355                 break
  356         for l7policy in self.l7policies:
  357             if l7policy.redirect_pool_id == self.id:
  358                 # Technically this should never happen, as we block deletion
  359                 # of pools in use by L7Policies at the API. However, we should
  360                 # probably keep this here in case the data model gets
  361                 # manipulated in some other way in the future.
  362                 l7policy.action = constants.L7POLICY_ACTION_REJECT
  363                 l7policy.redirect_pool = None
  364                 l7policy.redirect_pool_id = None
  365 
  366 
  367 class Member(BaseDataModel):
  368 
  369     def __init__(self, id=None, project_id=None, pool_id=None, ip_address=None,
  370                  protocol_port=None, weight=None, backup=None, enabled=None,
  371                  subnet_id=None, operating_status=None, pool=None,
  372                  created_at=None, updated_at=None, provisioning_status=None,
  373                  name=None, monitor_address=None, monitor_port=None,
  374                  tags=None):
  375         self.id = id
  376         self.project_id = project_id
  377         self.pool_id = pool_id
  378         self.ip_address = ip_address
  379         self.protocol_port = protocol_port
  380         self.weight = weight
  381         self.backup = backup
  382         self.enabled = enabled
  383         self.subnet_id = subnet_id
  384         self.operating_status = operating_status
  385         self.pool = pool
  386         self.created_at = created_at
  387         self.updated_at = updated_at
  388         self.provisioning_status = provisioning_status
  389         self.name = name
  390         self.monitor_address = monitor_address
  391         self.monitor_port = monitor_port
  392         self.tags = tags
  393 
  394     def delete(self):
  395         for mem in self.pool.members:
  396             if mem.id == self.id:
  397                 self.pool.members.remove(mem)
  398                 break
  399 
  400 
  401 class Listener(BaseDataModel):
  402 
  403     def __init__(self, id=None, project_id=None, name=None, description=None,
  404                  default_pool_id=None, load_balancer_id=None, protocol=None,
  405                  protocol_port=None, connection_limit=None,
  406                  enabled=None, provisioning_status=None, operating_status=None,
  407                  tls_certificate_id=None, stats=None, default_pool=None,
  408                  load_balancer=None, sni_containers=None, peer_port=None,
  409                  l7policies=None, pools=None, insert_headers=None,
  410                  created_at=None, updated_at=None,
  411                  timeout_client_data=None, timeout_member_connect=None,
  412                  timeout_member_data=None, timeout_tcp_inspect=None,
  413                  tags=None, client_ca_tls_certificate_id=None,
  414                  client_authentication=None, client_crl_container_id=None,
  415                  allowed_cidrs=None, tls_ciphers=None, tls_versions=None,
  416                  alpn_protocols=None):
  417         self.id = id
  418         self.project_id = project_id
  419         self.name = name
  420         self.description = description
  421         self.default_pool_id = default_pool_id
  422         self.load_balancer_id = load_balancer_id
  423         self.protocol = protocol
  424         self.protocol_port = protocol_port
  425         self.connection_limit = connection_limit
  426         self.enabled = enabled
  427         self.provisioning_status = provisioning_status
  428         self.operating_status = operating_status
  429         self.tls_certificate_id = tls_certificate_id
  430         self.stats = stats
  431         self.default_pool = default_pool
  432         self.load_balancer = load_balancer
  433         self.sni_containers = sni_containers or []
  434         self.peer_port = peer_port
  435         self.l7policies = l7policies or []
  436         self.insert_headers = insert_headers or {}
  437         self.pools = pools or []
  438         self.created_at = created_at
  439         self.updated_at = updated_at
  440         self.timeout_client_data = timeout_client_data
  441         self.timeout_member_connect = timeout_member_connect
  442         self.timeout_member_data = timeout_member_data
  443         self.timeout_tcp_inspect = timeout_tcp_inspect
  444         self.tags = tags
  445         self.client_ca_tls_certificate_id = client_ca_tls_certificate_id
  446         self.client_authentication = client_authentication
  447         self.client_crl_container_id = client_crl_container_id
  448         self.allowed_cidrs = allowed_cidrs or []
  449         self.tls_ciphers = tls_ciphers
  450         self.tls_versions = tls_versions
  451         self.alpn_protocols = alpn_protocols
  452 
  453     def update(self, update_dict):
  454         for key, value in update_dict.items():
  455             setattr(self, key, value)
  456             if key == 'default_pool_id':
  457                 if self.default_pool is not None:
  458                     l7_pool_ids = [p.redirect_pool_id for p in self.l7policies
  459                                    if p.redirect_pool_id is not None and
  460                                    p.l7rules and p.enabled is True]
  461                     old_pool = self.default_pool
  462                     if old_pool.id not in l7_pool_ids:
  463                         if old_pool in self.pools:
  464                             self.pools.remove(old_pool)
  465                         if self in old_pool.listeners:
  466                             old_pool.listeners.remove(self)
  467                 if value is not None:
  468                     pool = self._find_in_graph('Pool' + value)
  469                     if pool not in self.pools:
  470                         self.pools.append(pool)
  471                     if self not in pool.listeners:
  472                         pool.listeners.append(self)
  473                 else:
  474                     pool = None
  475                 setattr(self, 'default_pool', pool)
  476 
  477     def delete(self):
  478         for listener in self.load_balancer.listeners:
  479             if listener.id == self.id:
  480                 self.load_balancer.listeners.remove(listener)
  481                 break
  482         for pool in self.pools:
  483             pool.listeners.remove(self)
  484 
  485 
  486 class LoadBalancer(BaseDataModel):
  487 
  488     def __init__(self, id=None, project_id=None, name=None, description=None,
  489                  provisioning_status=None, operating_status=None, enabled=None,
  490                  topology=None, vip=None, listeners=None, amphorae=None,
  491                  pools=None, vrrp_group=None, server_group_id=None,
  492                  created_at=None, updated_at=None, provider=None, tags=None,
  493                  flavor_id=None, availability_zone=None):
  494 
  495         self.id = id
  496         self.project_id = project_id
  497         self.name = name
  498         self.description = description
  499         self.provisioning_status = provisioning_status
  500         self.operating_status = operating_status
  501         self.enabled = enabled
  502         self.vip = vip
  503         self.vrrp_group = vrrp_group
  504         self.topology = topology
  505         self.listeners = listeners or []
  506         self.amphorae = amphorae or []
  507         self.pools = pools or []
  508         self.server_group_id = server_group_id
  509         self.created_at = created_at
  510         self.updated_at = updated_at
  511         self.provider = provider
  512         self.tags = tags or []
  513         self.flavor_id = flavor_id
  514         self.availability_zone = availability_zone
  515 
  516     def update(self, update_dict):
  517         for key, value in update_dict.items():
  518             if key == 'vip':
  519                 if self.vip is not None:
  520                     self.vip.update(value)
  521                 else:
  522                     value.update({'load_balancer_id': self.id})
  523                     self.vip = Vip(**value)
  524             else:
  525                 setattr(self, key, value)
  526 
  527 
  528 class VRRPGroup(BaseDataModel):
  529 
  530     def __init__(self, load_balancer_id=None, vrrp_group_name=None,
  531                  vrrp_auth_type=None, vrrp_auth_pass=None, advert_int=None,
  532                  smtp_server=None, smtp_connect_timeout=None,
  533                  load_balancer=None):
  534         self.load_balancer_id = load_balancer_id
  535         self.vrrp_group_name = vrrp_group_name
  536         self.vrrp_auth_type = vrrp_auth_type
  537         self.vrrp_auth_pass = vrrp_auth_pass
  538         self.advert_int = advert_int
  539         self.load_balancer = load_balancer
  540 
  541 
  542 class Vip(BaseDataModel):
  543 
  544     def __init__(self, load_balancer_id=None, ip_address=None,
  545                  subnet_id=None, network_id=None, port_id=None,
  546                  load_balancer=None, qos_policy_id=None, octavia_owned=None):
  547         self.load_balancer_id = load_balancer_id
  548         self.ip_address = ip_address
  549         self.subnet_id = subnet_id
  550         self.network_id = network_id
  551         self.port_id = port_id
  552         self.load_balancer = load_balancer
  553         self.qos_policy_id = qos_policy_id
  554         self.octavia_owned = octavia_owned
  555 
  556 
  557 class SNI(BaseDataModel):
  558 
  559     def __init__(self, listener_id=None, position=None, listener=None,
  560                  tls_container_id=None):
  561         self.listener_id = listener_id
  562         self.position = position
  563         self.listener = listener
  564         self.tls_container_id = tls_container_id
  565 
  566     # SQLAlchemy kindly attaches the whole listener object so
  567     # let's keep this simple by overriding the to_dict for this
  568     # object. Otherwise we recurse down the "ghost" listener object.
  569     def to_dict(self, **kwargs):
  570         return {'tls_container_id': self.tls_container_id,
  571                 'listener_id': self.listener_id,
  572                 'position': self.position}
  573 
  574 
  575 class TLSContainer(BaseDataModel):
  576 
  577     def __init__(self, id=None, primary_cn=None, certificate=None,
  578                  private_key=None, passphrase=None, intermediates=None):
  579         self.id = id
  580         self.primary_cn = primary_cn
  581         self.certificate = certificate
  582         self.private_key = private_key
  583         self.passphrase = passphrase
  584         self.intermediates = intermediates or []
  585 
  586 
  587 class Amphora(BaseDataModel):
  588 
  589     def __init__(self, id=None, load_balancer_id=None, compute_id=None,
  590                  status=None, lb_network_ip=None, vrrp_ip=None,
  591                  ha_ip=None, vrrp_port_id=None, ha_port_id=None,
  592                  load_balancer=None, role=None, cert_expiration=None,
  593                  cert_busy=False, vrrp_interface=None, vrrp_id=None,
  594                  vrrp_priority=None, cached_zone=None, created_at=None,
  595                  updated_at=None, image_id=None, compute_flavor=None):
  596         self.id = id
  597         self.load_balancer_id = load_balancer_id
  598         self.compute_id = compute_id
  599         self.status = status
  600         self.lb_network_ip = lb_network_ip
  601         self.vrrp_ip = vrrp_ip
  602         self.ha_ip = ha_ip
  603         self.vrrp_port_id = vrrp_port_id
  604         self.ha_port_id = ha_port_id
  605         self.role = role
  606         self.vrrp_interface = vrrp_interface
  607         self.vrrp_id = vrrp_id
  608         self.vrrp_priority = vrrp_priority
  609         self.load_balancer = load_balancer
  610         self.cert_expiration = cert_expiration
  611         self.cert_busy = cert_busy
  612         self.cached_zone = cached_zone
  613         self.created_at = created_at
  614         self.updated_at = updated_at
  615         self.image_id = image_id
  616         self.compute_flavor = compute_flavor
  617 
  618     def delete(self):
  619         for amphora in self.load_balancer.amphorae:
  620             if amphora.id == self.id:
  621                 self.load_balancer.amphorae.remove(amphora)
  622                 break
  623 
  624 
  625 class AmphoraHealth(BaseDataModel):
  626 
  627     def __init__(self, amphora_id=None, last_update=None, busy=False):
  628         self.amphora_id = amphora_id
  629         self.last_update = last_update
  630         self.busy = busy
  631 
  632 
  633 class L7Rule(BaseDataModel):
  634 
  635     def __init__(self, id=None, l7policy_id=None, type=None, enabled=None,
  636                  compare_type=None, key=None, value=None, l7policy=None,
  637                  invert=False, provisioning_status=None, operating_status=None,
  638                  project_id=None, created_at=None, updated_at=None, tags=None):
  639         self.id = id
  640         self.l7policy_id = l7policy_id
  641         self.type = type
  642         self.compare_type = compare_type
  643         self.key = key
  644         self.value = value
  645         self.l7policy = l7policy
  646         self.invert = invert
  647         self.provisioning_status = provisioning_status
  648         self.operating_status = operating_status
  649         self.project_id = project_id
  650         self.created_at = created_at
  651         self.updated_at = updated_at
  652         self.enabled = enabled
  653         self.tags = tags
  654 
  655     def delete(self):
  656         if len(self.l7policy.l7rules) == 1:
  657             # l7policy should disappear from pool and listener lists. Since
  658             # we are operating only on the data model, we can fake this by
  659             # calling the policy's delete method.
  660             self.l7policy.delete()
  661         for r in self.l7policy.l7rules:
  662             if r.id == self.id:
  663                 self.l7policy.l7rules.remove(r)
  664                 break
  665 
  666 
  667 class L7Policy(BaseDataModel):
  668 
  669     def __init__(self, id=None, name=None, description=None, listener_id=None,
  670                  action=None, redirect_pool_id=None, redirect_url=None,
  671                  position=None, listener=None, redirect_pool=None,
  672                  enabled=None, l7rules=None, provisioning_status=None,
  673                  operating_status=None, project_id=None, created_at=None,
  674                  updated_at=None, redirect_prefix=None, tags=None,
  675                  redirect_http_code=None):
  676         self.id = id
  677         self.name = name
  678         self.description = description
  679         self.listener_id = listener_id
  680         self.action = action
  681         self.redirect_pool_id = redirect_pool_id
  682         self.redirect_url = redirect_url
  683         self.position = position
  684         self.listener = listener
  685         self.redirect_pool = redirect_pool
  686         self.enabled = enabled
  687         self.l7rules = l7rules or []
  688         self.provisioning_status = provisioning_status
  689         self.operating_status = operating_status
  690         self.project_id = project_id
  691         self.created_at = created_at
  692         self.updated_at = updated_at
  693         self.redirect_prefix = redirect_prefix
  694         self.tags = tags
  695         self.redirect_http_code = redirect_http_code
  696 
  697     def _conditionally_remove_pool_links(self, pool):
  698         """Removes links to the given pool from parent objects.
  699 
  700         Note this only happens if our listener isn't referencing the pool
  701         via its default_pool or another active l7policy's redirect_pool_id.
  702         """
  703         if (self.listener.default_pool is not None and
  704                 pool is not None and
  705                 pool.id != self.listener.default_pool.id and
  706                 pool in self.listener.pools):
  707             listener_l7pools = [
  708                 p.redirect_pool for p in self.listener.l7policies
  709                 if p.redirect_pool is not None and
  710                 p.l7rules and p.enabled is True and
  711                 p.id != self.id]
  712             if pool not in listener_l7pools:
  713                 self.listener.pools.remove(pool)
  714                 pool.listeners.remove(self.listener)
  715 
  716     def update(self, update_dict):
  717         for key, value in update_dict.items():
  718             if key == 'redirect_pool_id' and value is not None:
  719                 self._conditionally_remove_pool_links(self.redirect_pool)
  720                 self.action = constants.L7POLICY_ACTION_REDIRECT_TO_POOL
  721                 self.redirect_url = None
  722                 self.redirect_http_code = None
  723                 pool = self._find_in_graph('Pool' + value)
  724                 self.redirect_pool = pool
  725                 if self.l7rules and (self.enabled is True or (
  726                         'enabled' in update_dict.keys() and
  727                         update_dict['enabled'] is True)):
  728                     if pool not in self.listener.pools:
  729                         self.listener.pools.append(pool)
  730                     if self.listener not in pool.listeners:
  731                         pool.listeners.append(self.listener)
  732             elif key == 'redirect_url' and value is not None:
  733                 self.action = constants.L7POLICY_ACTION_REDIRECT_TO_URL
  734                 self._conditionally_remove_pool_links(self.redirect_pool)
  735                 self.redirect_pool = None
  736                 self.redirect_pool_id = None
  737             elif key == 'action' and value == constants.L7POLICY_ACTION_REJECT:
  738                 self.redirect_url = None
  739                 self._conditionally_remove_pool_links(self.redirect_pool)
  740                 self.redirect_pool = None
  741                 self.redirect_pool_id = None
  742                 self.redirect_http_code = None
  743             elif key == 'position':
  744                 self.listener.l7policies.remove(self)
  745                 self.listener.l7policies.insert(value - 1, self)
  746             elif key == 'enabled':
  747                 if (value is True and self.action ==
  748                         constants.L7POLICY_ACTION_REDIRECT_TO_POOL and
  749                         self.redirect_pool is not None and
  750                         self.l7rules and
  751                         self.redirect_pool not in self.listener.pools):
  752                     self.listener.pools.append(self.redirect_pool)
  753                     self.redirect_pool.listeners.append(self.listener)
  754                 elif (value is False and self.action ==
  755                         constants.L7POLICY_ACTION_REDIRECT_TO_POOL and
  756                         self.redirect_pool is not None):
  757                     self._conditionally_remove_pool_links(
  758                         self.redirect_pool)
  759             setattr(self, key, value)
  760 
  761     def delete(self):
  762         self._conditionally_remove_pool_links(self.redirect_pool)
  763         if self.redirect_pool:
  764             for p in self.redirect_pool.l7policies:
  765                 if p.id == self.id:
  766                     self.redirect_pool.l7policies.remove(p)
  767         for p in self.listener.l7policies:
  768             if p.id == self.id:
  769                 self.listener.l7policies.remove(p)
  770                 break
  771 
  772 
  773 class Quotas(BaseDataModel):
  774 
  775     def __init__(self,
  776                  project_id=None,
  777                  load_balancer=None,
  778                  listener=None,
  779                  pool=None,
  780                  health_monitor=None,
  781                  member=None,
  782                  l7policy=None,
  783                  l7rule=None,
  784                  in_use_health_monitor=None,
  785                  in_use_listener=None,
  786                  in_use_load_balancer=None,
  787                  in_use_member=None,
  788                  in_use_pool=None,
  789                  in_use_l7policy=None,
  790                  in_use_l7rule=None):
  791         self.project_id = project_id
  792         self.health_monitor = health_monitor
  793         self.listener = listener
  794         self.load_balancer = load_balancer
  795         self.pool = pool
  796         self.member = member
  797         self.l7policy = l7policy
  798         self.l7rule = l7rule
  799         self.in_use_health_monitor = in_use_health_monitor
  800         self.in_use_listener = in_use_listener
  801         self.in_use_load_balancer = in_use_load_balancer
  802         self.in_use_member = in_use_member
  803         self.in_use_pool = in_use_pool
  804         self.in_use_l7policy = in_use_l7policy
  805         self.in_use_l7rule = in_use_l7rule
  806 
  807 
  808 class Flavor(BaseDataModel):
  809 
  810     def __init__(self, id=None, name=None,
  811                  description=None, enabled=None,
  812                  flavor_profile_id=None):
  813         self.id = id
  814         self.name = name
  815         self.description = description
  816         self.enabled = enabled
  817         self.flavor_profile_id = flavor_profile_id
  818 
  819 
  820 class FlavorProfile(BaseDataModel):
  821 
  822     def __init__(self, id=None, name=None, provider_name=None,
  823                  flavor_data=None):
  824         self.id = id
  825         self.name = name
  826         self.provider_name = provider_name
  827         self.flavor_data = flavor_data
  828 
  829 
  830 class AvailabilityZone(BaseDataModel):
  831 
  832     def __init__(self, name=None, description=None, enabled=None,
  833                  availability_zone_profile_id=None):
  834         self.name = name
  835         self.description = description
  836         self.enabled = enabled
  837         self.availability_zone_profile_id = availability_zone_profile_id
  838 
  839 
  840 class AvailabilityZoneProfile(BaseDataModel):
  841 
  842     def __init__(self, id=None, name=None, provider_name=None,
  843                  availability_zone_data=None):
  844         self.id = id
  845         self.name = name
  846         self.provider_name = provider_name
  847         self.availability_zone_data = availability_zone_data
  848 
  849 
  850 class ListenerCidr(BaseDataModel):
  851 
  852     def __init__(self, listener_id=None, cidr=None):
  853         self.listener_id = listener_id
  854         self.cidr = cidr
  855 
  856     # SQLAlchemy kindly attaches the whole listener object so
  857     # let's keep this simple by overriding the to_dict for this
  858     # object. Otherwise we recurse down the "ghost" listener object.
  859     def to_dict(self, **kwargs):
  860         return {'cidr': self.cidr, 'listener_id': self.listener_id}