"Fossies" - the Fresh Open Source Software Archive

Member "octavia-8.0.0/octavia/api/drivers/driver_agent/driver_updater.py" (14 Apr 2021, 9846 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 "driver_updater.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 2018 Rackspace, US Inc.
    2 #
    3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    4 #    not use this file except in compliance with the License. You may obtain
    5 #    a copy of the License at
    6 #
    7 #         http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 #    Unless required by applicable law or agreed to in writing, software
   10 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   12 #    License for the specific language governing permissions and limitations
   13 #    under the License.
   14 
   15 import time
   16 
   17 from octavia_lib.api.drivers import exceptions as driver_exceptions
   18 from octavia_lib.common import constants as lib_consts
   19 from oslo_log import log as logging
   20 from oslo_utils import excutils
   21 
   22 from octavia.common import constants as consts
   23 from octavia.common import data_models
   24 from octavia.common import utils
   25 from octavia.db import api as db_apis
   26 from octavia.db import repositories as repo
   27 from octavia.statistics import stats_base
   28 
   29 LOG = logging.getLogger(__name__)
   30 
   31 
   32 class DriverUpdater(object):
   33 
   34     def __init__(self, **kwargs):
   35         self.repos = repo.Repositories()
   36         self.loadbalancer_repo = repo.LoadBalancerRepository()
   37         self.listener_repo = repo.ListenerRepository()
   38         self.pool_repo = repo.PoolRepository()
   39         self.health_mon_repo = repo.HealthMonitorRepository()
   40         self.member_repo = repo.MemberRepository()
   41         self.l7policy_repo = repo.L7PolicyRepository()
   42         self.l7rule_repo = repo.L7RuleRepository()
   43         self.listener_stats_repo = repo.ListenerStatisticsRepository()
   44 
   45         self.db_session = db_apis.get_session()
   46         super().__init__(**kwargs)
   47 
   48     def _check_for_lb_vip_deallocate(self, repo, lb_id):
   49         lb = repo.get(self.db_session, id=lb_id)
   50         if lb.vip.octavia_owned:
   51             vip = lb.vip
   52             # We need a backreference
   53             vip.load_balancer = lb
   54             # Only lookup the network driver if we have a VIP to deallocate
   55             network_driver = utils.get_network_driver()
   56             network_driver.deallocate_vip(vip)
   57 
   58     def _decrement_quota(self, repo, object_name, record_id):
   59         lock_session = db_apis.get_session(autocommit=False)
   60         db_object = repo.get(lock_session, id=record_id)
   61         try:
   62             if db_object.provisioning_status == consts.DELETED:
   63                 LOG.info('%(name)s with ID of %(id)s is already in the '
   64                          'DELETED state. Skipping quota update.',
   65                          {'name': object_name, 'id': record_id})
   66                 lock_session.rollback()
   67                 return
   68             self.repos.decrement_quota(lock_session,
   69                                        repo.model_class.__data_model__,
   70                                        db_object.project_id)
   71             lock_session.commit()
   72         except Exception:
   73             with excutils.save_and_reraise_exception():
   74                 LOG.error('Failed to decrement %(name)s quota for '
   75                           'project: %(proj)s the project may have excess '
   76                           'quota in use.', {'proj': db_object.project_id,
   77                                             'name': object_name})
   78                 lock_session.rollback()
   79 
   80     def _process_status_update(self, repo, object_name, record,
   81                                delete_record=False):
   82         # Zero it out so that if the ID is missing from a record we do not
   83         # report the last LB as the failed record in the exception
   84         record_id = None
   85         try:
   86             record_id = record['id']
   87             record_kwargs = {}
   88             prov_status = record.get(consts.PROVISIONING_STATUS, None)
   89             if prov_status:
   90                 if prov_status == consts.DELETED:
   91                     if object_name == consts.LOADBALANCERS:
   92                         self._check_for_lb_vip_deallocate(repo, record_id)
   93 
   94                     self._decrement_quota(repo, object_name, record_id)
   95 
   96                     if delete_record and object_name != consts.LOADBALANCERS:
   97                         repo.delete(self.db_session, id=record_id)
   98                         return
   99 
  100                 record_kwargs[consts.PROVISIONING_STATUS] = prov_status
  101             op_status = record.get(consts.OPERATING_STATUS, None)
  102             if op_status:
  103                 record_kwargs[consts.OPERATING_STATUS] = op_status
  104             if prov_status or op_status:
  105                 repo.update(self.db_session, record_id, **record_kwargs)
  106         except Exception as e:
  107             # We need to raise a failure here to notify the driver it is
  108             # sending bad status data.
  109             raise driver_exceptions.UpdateStatusError(
  110                 fault_string=str(e), status_object_id=record_id,
  111                 status_object=object_name)
  112 
  113     def update_loadbalancer_status(self, status):
  114         """Update load balancer status.
  115 
  116         :param status: dictionary defining the provisioning status and
  117             operating status for load balancer objects, including pools,
  118             members, listeners, L7 policies, and L7 rules.
  119             iod (string): ID for the object.
  120             provisioning_status (string): Provisioning status for the object.
  121             operating_status (string): Operating status for the object.
  122         :type status: dict
  123         :raises: UpdateStatusError
  124         :returns: None
  125         """
  126         try:
  127             members = status.pop(consts.MEMBERS, [])
  128             for member in members:
  129                 self._process_status_update(self.member_repo, consts.MEMBERS,
  130                                             member, delete_record=True)
  131 
  132             health_mons = status.pop(consts.HEALTHMONITORS, [])
  133             for health_mon in health_mons:
  134                 self._process_status_update(
  135                     self.health_mon_repo, consts.HEALTHMONITORS, health_mon,
  136                     delete_record=True)
  137 
  138             pools = status.pop(consts.POOLS, [])
  139             for pool in pools:
  140                 self._process_status_update(self.pool_repo, consts.POOLS,
  141                                             pool, delete_record=True)
  142 
  143             l7rules = status.pop(consts.L7RULES, [])
  144             for l7rule in l7rules:
  145                 self._process_status_update(self.l7rule_repo, consts.L7RULES,
  146                                             l7rule, delete_record=True)
  147 
  148             l7policies = status.pop(consts.L7POLICIES, [])
  149             for l7policy in l7policies:
  150                 self._process_status_update(
  151                     self.l7policy_repo, consts.L7POLICIES, l7policy,
  152                     delete_record=True)
  153 
  154             listeners = status.pop(lib_consts.LISTENERS, [])
  155             for listener in listeners:
  156                 self._process_status_update(
  157                     self.listener_repo, lib_consts.LISTENERS, listener,
  158                     delete_record=True)
  159 
  160             lbs = status.pop(consts.LOADBALANCERS, [])
  161             for lb in lbs:
  162                 self._process_status_update(self.loadbalancer_repo,
  163                                             consts.LOADBALANCERS, lb)
  164         except driver_exceptions.UpdateStatusError as e:
  165             return {lib_consts.STATUS_CODE: lib_consts.DRVR_STATUS_CODE_FAILED,
  166                     lib_consts.FAULT_STRING: e.fault_string,
  167                     lib_consts.STATUS_OBJECT: e.status_object,
  168                     lib_consts.STATUS_OBJECT_ID: e.status_object_id}
  169         except Exception as e:
  170             return {lib_consts.STATUS_CODE: lib_consts.DRVR_STATUS_CODE_FAILED,
  171                     lib_consts.FAULT_STRING: str(e)}
  172         return {lib_consts.STATUS_CODE: lib_consts.DRVR_STATUS_CODE_OK}
  173 
  174     def update_listener_statistics(self, statistics):
  175         """Update listener statistics.
  176 
  177         :param statistics: Statistics for listeners:
  178               id (string): ID for listener.
  179               active_connections (int): Number of currently active connections.
  180               bytes_in (int): Total bytes received.
  181               bytes_out (int): Total bytes sent.
  182               request_errors (int): Total requests not fulfilled.
  183               total_connections (int): The total connections handled.
  184         :type statistics: dict
  185         :raises: UpdateStatisticsError
  186         :returns: None
  187         """
  188         listener_stats = statistics.get(lib_consts.LISTENERS, [])
  189         stats_objects = []
  190         for stat in listener_stats:
  191             try:
  192                 stats_obj = data_models.ListenerStatistics(
  193                     listener_id=stat['id'],
  194                     bytes_in=stat['bytes_in'],
  195                     bytes_out=stat['bytes_out'],
  196                     active_connections=stat['active_connections'],
  197                     total_connections=stat['total_connections'],
  198                     request_errors=stat['request_errors'],
  199                     received_time=time.time()
  200                 )
  201                 stats_objects.append(stats_obj)
  202             except Exception as e:
  203                 return {
  204                     lib_consts.STATUS_CODE: lib_consts.DRVR_STATUS_CODE_FAILED,
  205                     lib_consts.FAULT_STRING: str(e),
  206                     lib_consts.STATS_OBJECT: lib_consts.LISTENERS}
  207 
  208         # Provider drivers other than the amphora driver do not have
  209         # an amphora ID, use the listener ID again here to meet the
  210         # constraint requirement.
  211         try:
  212             if stats_objects:
  213                 stats_base.update_stats_via_driver(stats_objects)
  214         except Exception as e:
  215             return {
  216                 lib_consts.STATUS_CODE: lib_consts.DRVR_STATUS_CODE_FAILED,
  217                 lib_consts.FAULT_STRING: str(e),
  218                 lib_consts.STATS_OBJECT: lib_consts.LISTENERS}
  219         return {lib_consts.STATUS_CODE: lib_consts.DRVR_STATUS_CODE_OK}