178 lines
7.3 KiB
Python
178 lines
7.3 KiB
Python
# Copyright 2016 Huawei Technologies India Pvt. Ltd.
|
|
# 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.
|
|
|
|
from oslo_config import cfg
|
|
from oslo_db import exception as db_exc
|
|
from oslo_log import log as logging
|
|
import sqlalchemy as sa
|
|
from sqlalchemy import orm
|
|
|
|
from neutron._i18n import _
|
|
from neutron._i18n import _LW
|
|
from neutron.db import agents_db
|
|
from neutron.db import agentschedulers_db as as_db
|
|
from neutron.db import model_base
|
|
from neutron.extensions import bgp_dragentscheduler as bgp_dras_ext
|
|
from neutron.services.bgp.common import constants as bgp_consts
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
BGP_DRAGENT_SCHEDULER_OPTS = [
|
|
cfg.StrOpt(
|
|
'bgp_drscheduler_driver',
|
|
default='neutron.services.bgp.scheduler'
|
|
'.bgp_dragent_scheduler.ChanceScheduler',
|
|
help=_('Driver used for scheduling BGP speakers to BGP DrAgent')),
|
|
]
|
|
|
|
cfg.CONF.register_opts(BGP_DRAGENT_SCHEDULER_OPTS)
|
|
|
|
|
|
class BgpSpeakerDrAgentBinding(model_base.BASEV2):
|
|
"""Represents a mapping between BGP speaker and BGP DRAgent"""
|
|
|
|
__tablename__ = 'bgp_speaker_dragent_bindings'
|
|
|
|
bgp_speaker_id = sa.Column(sa.String(length=36),
|
|
sa.ForeignKey("bgp_speakers.id",
|
|
ondelete='CASCADE'),
|
|
nullable=False)
|
|
dragent = orm.relation(agents_db.Agent)
|
|
agent_id = sa.Column(sa.String(length=36),
|
|
sa.ForeignKey("agents.id",
|
|
ondelete='CASCADE'),
|
|
primary_key=True)
|
|
|
|
|
|
class BgpDrAgentSchedulerDbMixin(bgp_dras_ext.BgpDrSchedulerPluginBase,
|
|
as_db.AgentSchedulerDbMixin):
|
|
|
|
bgp_drscheduler = None
|
|
|
|
def schedule_unscheduled_bgp_speakers(self, context, host):
|
|
if self.bgp_drscheduler:
|
|
return self.bgp_drscheduler.schedule_unscheduled_bgp_speakers(
|
|
context, host)
|
|
else:
|
|
LOG.warning(_LW("Cannot schedule BgpSpeaker to DrAgent. "
|
|
"Reason: No scheduler registered."))
|
|
|
|
def schedule_bgp_speaker(self, context, created_bgp_speaker):
|
|
if self.bgp_drscheduler:
|
|
self.bgp_drscheduler.schedule(context, created_bgp_speaker)
|
|
else:
|
|
LOG.warning(_LW("Cannot schedule BgpSpeaker to DrAgent. "
|
|
"Reason: No scheduler registered."))
|
|
|
|
def add_bgp_speaker_to_dragent(self, context, agent_id, speaker_id):
|
|
"""Associate a BgpDrAgent with a BgpSpeaker."""
|
|
try:
|
|
self._save_bgp_speaker_dragent_binding(context,
|
|
agent_id,
|
|
speaker_id)
|
|
except db_exc.DBDuplicateEntry:
|
|
raise bgp_dras_ext.DrAgentAssociationError(
|
|
agent_id=agent_id)
|
|
|
|
LOG.debug('BgpSpeaker %(bgp_speaker_id)s added to '
|
|
'BgpDrAgent %(agent_id)s',
|
|
{'bgp_speaker_id': speaker_id, 'agent_id': agent_id})
|
|
|
|
def _save_bgp_speaker_dragent_binding(self, context,
|
|
agent_id, speaker_id):
|
|
with context.session.begin(subtransactions=True):
|
|
agent_db = self._get_agent(context, agent_id)
|
|
agent_up = agent_db['admin_state_up']
|
|
is_agent_bgp = (agent_db['agent_type'] ==
|
|
bgp_consts.AGENT_TYPE_BGP_ROUTING)
|
|
if not is_agent_bgp or not agent_up:
|
|
raise bgp_dras_ext.DrAgentInvalid(id=agent_id)
|
|
|
|
binding = BgpSpeakerDrAgentBinding()
|
|
binding.bgp_speaker_id = speaker_id
|
|
binding.agent_id = agent_id
|
|
context.session.add(binding)
|
|
|
|
def remove_bgp_speaker_from_dragent(self, context, agent_id, speaker_id):
|
|
with context.session.begin(subtransactions=True):
|
|
agent_db = self._get_agent(context, agent_id)
|
|
is_agent_bgp = (agent_db['agent_type'] ==
|
|
bgp_consts.AGENT_TYPE_BGP_ROUTING)
|
|
if not is_agent_bgp:
|
|
raise bgp_dras_ext.DrAgentInvalid(id=agent_id)
|
|
|
|
query = context.session.query(BgpSpeakerDrAgentBinding)
|
|
query = query.filter_by(bgp_speaker_id=speaker_id,
|
|
agent_id=agent_id)
|
|
|
|
num_deleted = query.delete()
|
|
if not num_deleted:
|
|
raise bgp_dras_ext.DrAgentNotHostingBgpSpeaker(
|
|
bgp_speaker_id=speaker_id,
|
|
agent_id=agent_id)
|
|
LOG.debug('BgpSpeaker %(bgp_speaker_id)s removed from '
|
|
'BgpDrAgent %(agent_id)s',
|
|
{'bgp_speaker_id': speaker_id,
|
|
'agent_id': agent_id})
|
|
|
|
def get_dragents_hosting_bgp_speakers(self, context, bgp_speaker_ids,
|
|
active=None, admin_state_up=None):
|
|
query = context.session.query(BgpSpeakerDrAgentBinding)
|
|
query = query.options(orm.contains_eager(
|
|
BgpSpeakerDrAgentBinding.dragent))
|
|
query = query.join(BgpSpeakerDrAgentBinding.dragent)
|
|
|
|
if len(bgp_speaker_ids) == 1:
|
|
query = query.filter(
|
|
BgpSpeakerDrAgentBinding.bgp_speaker_id == (
|
|
bgp_speaker_ids[0]))
|
|
elif bgp_speaker_ids:
|
|
query = query.filter(
|
|
BgpSpeakerDrAgentBinding.bgp_speaker_id in bgp_speaker_ids)
|
|
if admin_state_up is not None:
|
|
query = query.filter(agents_db.Agent.admin_state_up ==
|
|
admin_state_up)
|
|
|
|
return [binding.dragent
|
|
for binding in query
|
|
if as_db.AgentSchedulerDbMixin.is_eligible_agent(
|
|
active, binding.dragent)]
|
|
|
|
def get_dragent_bgp_speaker_bindings(self, context):
|
|
return context.session.query(BgpSpeakerDrAgentBinding).all()
|
|
|
|
def list_dragent_hosting_bgp_speaker(self, context, speaker_id):
|
|
dragents = self.get_dragents_hosting_bgp_speakers(context,
|
|
[speaker_id])
|
|
agent_ids = [dragent.id for dragent in dragents]
|
|
if not agent_ids:
|
|
return {'agents': []}
|
|
return {'agents': self.get_agents(context, filters={'id': agent_ids})}
|
|
|
|
def list_bgp_speaker_on_dragent(self, context, agent_id):
|
|
query = context.session.query(BgpSpeakerDrAgentBinding.bgp_speaker_id)
|
|
query = query.filter_by(agent_id=agent_id)
|
|
|
|
bgp_speaker_ids = [item[0] for item in query]
|
|
if not bgp_speaker_ids:
|
|
# Exception will be thrown if the requested agent does not exist.
|
|
self._get_agent(context, agent_id)
|
|
return {'bgp_speakers': []}
|
|
return {'bgp_speakers':
|
|
self.get_bgp_speakers(context,
|
|
filters={'id': bgp_speaker_ids})}
|