# Copyright 2015 Rackspace. # # 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 neutron.common import exceptions as n_exc from neutron.extensions import portbindings from neutron.i18n import _LW from neutron.plugins.common import constants from oslo_log import log as logging import oslo_messaging as messaging from neutron_lbaas.db.loadbalancer import loadbalancer_dbv2 from neutron_lbaas.db.loadbalancer import models as db_models from neutron_lbaas.services.loadbalancer import data_models LOG = logging.getLogger(__name__) class LoadBalancerCallbacks(object): # history # 1.0 Initial version target = messaging.Target(version='1.0') def __init__(self, plugin): super(LoadBalancerCallbacks, self).__init__() self.plugin = plugin def get_ready_devices(self, context, host=None): with context.session.begin(subtransactions=True): agents = self.plugin.db.get_lbaas_agents( context, filters={'host': [host]}) if not agents: return [] elif len(agents) > 1: LOG.warning(_LW('Multiple lbaas agents found on host %s'), host) loadbalancers = self.plugin.db.list_loadbalancers_on_lbaas_agent( context, agents[0].id) loadbalancer_ids = [ l.id for l in loadbalancers] qry = context.session.query( loadbalancer_dbv2.models.LoadBalancer.id) qry = qry.filter( loadbalancer_dbv2.models.LoadBalancer.id.in_( loadbalancer_ids)) qry = qry.filter( loadbalancer_dbv2.models.LoadBalancer.provisioning_status.in_( constants.ACTIVE_PENDING_STATUSES)) up = True # makes pep8 and sqlalchemy happy qry = qry.filter( loadbalancer_dbv2.models.LoadBalancer.admin_state_up == up) return [id for id, in qry] def get_loadbalancer(self, context, loadbalancer_id=None): lb_model = self.plugin.db.get_loadbalancer(context, loadbalancer_id) if lb_model.vip_port and lb_model.vip_port.fixed_ips: for fixed_ip in lb_model.vip_port.fixed_ips: subnet_dict = self.plugin.db._core_plugin.get_subnet( context, fixed_ip.subnet_id ) setattr(fixed_ip, 'subnet', data_models.Subnet.from_dict( subnet_dict)) if lb_model.provider: device_driver = self.plugin.drivers[ lb_model.provider.provider_name].device_driver setattr(lb_model.provider, 'device_driver', device_driver) lb_dict = lb_model.to_dict(stats=False) return lb_dict def loadbalancer_deployed(self, context, loadbalancer_id): with context.session.begin(subtransactions=True): qry = context.session.query(db_models.LoadBalancer) qry = qry.filter_by(id=loadbalancer_id) loadbalancer = qry.one() # set all resources to active if (loadbalancer.provisioning_status in constants.ACTIVE_PENDING_STATUSES): loadbalancer.provisioning_status = constants.ACTIVE if loadbalancer.listeners: for l in loadbalancer.listeners: if (l.provisioning_status in constants.ACTIVE_PENDING_STATUSES): l.provisioning_status = constants.ACTIVE if (l.default_pool and l.default_pool.provisioning_status in constants.ACTIVE_PENDING_STATUSES): l.default_pool.provisioning_status = constants.ACTIVE if l.default_pool.members: for m in l.default_pool.members: if (m.provisioning_status in constants.ACTIVE_PENDING_STATUSES): m.provisioning_status = constants.ACTIVE if l.default_pool.healthmonitor: hm = l.default_pool.healthmonitor ps = hm.provisioning_status if ps in constants.ACTIVE_PENDING_STATUSES: (l.default_pool.healthmonitor .provisioning_status) = constants.ACTIVE def update_status(self, context, obj_type, obj_id, provisioning_status=None, operating_status=None): if not provisioning_status and not operating_status: LOG.warning(_LW('update_status for %(obj_type)s %(obj_id)s called ' 'without specifying provisioning_status or ' 'operating_status') % {'obj_type': obj_type, 'obj_id': obj_id}) return model_mapping = { 'loadbalancer': db_models.LoadBalancer, 'pool': db_models.PoolV2, 'listener': db_models.Listener, 'member': db_models.MemberV2, 'healthmonitor': db_models.HealthMonitorV2 } if obj_type not in model_mapping: raise n_exc.Invalid(_('Unknown object type: %s') % obj_type) try: self.plugin.db.update_status( context, model_mapping[obj_type], obj_id, provisioning_status=provisioning_status, operating_status=operating_status) except n_exc.NotFound: # update_status may come from agent on an object which was # already deleted from db with other request LOG.warning(_LW('Cannot update status: %(obj_type)s %(obj_id)s ' 'not found in the DB, it was probably deleted ' 'concurrently'), {'obj_type': obj_type, 'obj_id': obj_id}) def loadbalancer_destroyed(self, context, loadbalancer_id=None): """Agent confirmation hook that a load balancer has been destroyed. This method exists for subclasses to change the deletion behavior. """ pass def plug_vip_port(self, context, port_id=None, host=None): if not port_id: return try: port = self.plugin.db._core_plugin.get_port( context, port_id ) except n_exc.PortNotFound: LOG.debug('Unable to find port %s to plug.', port_id) return port['admin_state_up'] = True port[portbindings.HOST_ID] = host self.plugin.db._core_plugin.update_port( context, port_id, {'port': port} ) def unplug_vip_port(self, context, port_id=None, host=None): if not port_id: return try: port = self.plugin.db._core_plugin.get_port( context, port_id ) except n_exc.PortNotFound: LOG.debug('Unable to find port %s to unplug. This can occur when ' 'the Vip has been deleted first.', port_id) return port['admin_state_up'] = False port['device_owner'] = '' port['device_id'] = '' try: self.plugin.db._core_plugin.update_port( context, port_id, {'port': port} ) except n_exc.PortNotFound: LOG.debug('Unable to find port %s to unplug. This can occur when ' 'the Vip has been deleted first.', port_id) def update_loadbalancer_stats(self, context, loadbalancer_id=None, stats=None): self.plugin.db.update_loadbalancer_stats(context, loadbalancer_id, stats)