diff --git a/devstack/lib/bgp b/devstack/lib/bgp deleted file mode 100644 index a0257ed0dae..00000000000 --- a/devstack/lib/bgp +++ /dev/null @@ -1,29 +0,0 @@ -function configure_bgp_service_plugin { - _neutron_service_plugin_class_add "bgp" -} - -function configure_bgp { - configure_bgp_service_plugin -} - -function configure_bgp_dragent { - cp $NEUTRON_DIR/etc/bgp_dragent.ini.sample $Q_BGP_DRAGENT_CONF_FILE - - iniset $Q_BGP_DRAGENT_CONF_FILE DEFAULT verbose True - iniset $Q_BGP_DRAGENT_CONF_FILE DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - if [ -n "$BGP_ROUTER_ID" ]; then - iniset $Q_BGP_DRAGENT_CONF_FILE BGP bgp_router_id $BGP_ROUTER_ID - fi - if [ -z "$BGP_SPEAKER_DRIVER" ]; then - BGP_SPEAKER_DRIVER=$RYU_BGP_SPEAKER_DRIVER - fi - iniset $Q_BGP_DRAGENT_CONF_FILE BGP bgp_speaker_driver $BGP_SPEAKER_DRIVER -} - -function start_bgp_dragent { - run_process q-bgp-agt "$AGENT_BGP_BINARY --config-file $NEUTRON_CONF --config-file /$Q_BGP_DRAGENT_CONF_FILE" -} - -function stop_bgp_dragent { - stop_process q-bgp-agt -} diff --git a/devstack/plugin.sh b/devstack/plugin.sh index fe97c9c4ee5..e401c233563 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -1,6 +1,5 @@ LIBDIR=$DEST/neutron/devstack/lib -source $LIBDIR/bgp source $LIBDIR/flavors source $LIBDIR/l2_agent source $LIBDIR/l2_agent_sriovnicswitch @@ -19,9 +18,6 @@ if [[ "$1" == "stack" ]]; then if is_service_enabled q-qos; then configure_qos fi - if is_service_enabled q-bgp; then - configure_bgp - fi if [[ "$Q_AGENT" == "openvswitch" ]] && \ [[ "$Q_BUILD_OVS_FROM_GIT" == "True" ]]; then remove_ovs_packages @@ -33,9 +29,6 @@ if [[ "$1" == "stack" ]]; then if is_service_enabled q-agt; then configure_l2_agent fi - if is_service_enabled q-bgp && is_service_enabled q-bgp-agt; then - configure_bgp_dragent - fi #Note: sriov agent should run with OVS or linux bridge agent #because they are the mechanisms that bind the DHCP and router ports. #Currently devstack lacks the option to run two agents on the same node. @@ -51,16 +44,10 @@ if [[ "$1" == "stack" ]]; then if is_service_enabled q-sriov-agt; then start_l2_agent_sriov fi - if is_service_enabled q-bgp && is_service_enabled q-bgp-agt; then - start_bgp_dragent - fi ;; esac elif [[ "$1" == "unstack" ]]; then if is_service_enabled q-sriov-agt; then stop_l2_agent_sriov fi - if is_service_enabled q-bgp && is_service_enabled q-bgp-agt; then - stop_bgp_dragent - fi fi diff --git a/devstack/settings b/devstack/settings index c9deeecbd5a..b452f883145 100644 --- a/devstack/settings +++ b/devstack/settings @@ -1,8 +1 @@ L2_AGENT_EXTENSIONS=${L2_AGENT_EXTENSIONS:-} - -#BGP binary and config information -AGENT_BGP_BINARY=${AGENT_BGP_BINARY:-"$NEUTRON_BIN_DIR/neutron-bgp-dragent"} -Q_BGP_DRAGENT_CONF_FILE=${Q_BGP_DRAGENT_CONF_FILE:-"$NEUTRON_CONF_DIR/bgp_dragent.ini"} -BGP_ROUTER_ID=${BGP_ROUTER_ID:-} - -RYU_BGP_SPEAKER_DRIVER="neutron.services.bgp.driver.ryu.driver.RyuBgpDriver" diff --git a/etc/oslo-config-generator/bgp_dragent.ini b/etc/oslo-config-generator/bgp_dragent.ini deleted file mode 100644 index 0cf2a2f0d58..00000000000 --- a/etc/oslo-config-generator/bgp_dragent.ini +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -output_file = etc/bgp_dragent.ini.sample -wrap_width = 79 - -namespace = neutron.base.agent -namespace = neutron.bgp.agent -namespace = oslo.log diff --git a/etc/policy.json b/etc/policy.json index 148b756b594..8c9d3fedd74 100644 --- a/etc/policy.json +++ b/etc/policy.json @@ -213,26 +213,8 @@ "get_flavor_service_profile": "rule:regular_user", "get_auto_allocated_topology": "rule:admin_or_owner", - "get_bgp_speaker": "rule:admin_only", - "create_bgp_speaker": "rule:admin_only", - "update_bgp_speaker": "rule:admin_only", - "delete_bgp_speaker": "rule:admin_only", - - "get_bgp_peer": "rule:admin_only", - "create_bgp_peer": "rule:admin_only", - "update_bgp_peer": "rule:admin_only", - "delete_bgp_peer": "rule:admin_only", - - "add_bgp_peer": "rule:admin_only", - "remove_bgp_peer": "rule:admin_only", - "add_gateway_network": "rule:admin_only", "remove_gateway_network": "rule:admin_only", - "get_advertised_routes":"rule:admin_only", - - "add_bgp_speaker_to_dragent": "rule:admin_only", - "remove_bgp_speaker_from_dragent": "rule:admin_only", - "list_bgp_speaker_on_dragent": "rule:admin_only", - "list_dragent_hosting_bgp_speaker": "rule:admin_only" + "get_advertised_routes":"rule:admin_only" } diff --git a/neutron/api/rpc/agentnotifiers/bgp_dr_rpc_agent_api.py b/neutron/api/rpc/agentnotifiers/bgp_dr_rpc_agent_api.py deleted file mode 100644 index de7e1ccbde3..00000000000 --- a/neutron/api/rpc/agentnotifiers/bgp_dr_rpc_agent_api.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 oslo_messaging - -from neutron.common import rpc as n_rpc -from neutron.services.bgp.common import constants as bgp_consts - - -class BgpDrAgentNotifyApi(object): - """API for plugin to notify BGP DrAgent. - - This class implements the client side of an rpc interface. The server side - is neutron.services.bgp_speaker.agent.bgp_dragent.BgpDrAgent. For more - information about rpc interfaces, please see doc/source/devref/rpc_api.rst. - """ - - def __init__(self, topic=bgp_consts.BGP_DRAGENT): - target = oslo_messaging.Target(topic=topic, version='1.0') - self.client = n_rpc.get_client(target) - self.topic = topic - - def bgp_routes_advertisement(self, context, bgp_speaker_id, - routes, host): - """Tell BgpDrAgent to begin advertising the given route. - - Invoked on FIP association, adding router port to a tenant network, - and new DVR port-host bindings, and subnet creation(?). - """ - self._notification_host_cast(context, 'bgp_routes_advertisement_end', - {'advertise_routes': {'speaker_id': bgp_speaker_id, - 'routes': routes}}, host) - - def bgp_routes_withdrawal(self, context, bgp_speaker_id, - routes, host): - """Tell BgpDrAgent to stop advertising the given route. - - Invoked on FIP disassociation, removal of a router port on a - network, and removal of DVR port-host binding, and subnet delete(?). - """ - self._notification_host_cast(context, 'bgp_routes_withdrawal_end', - {'withdraw_routes': {'speaker_id': bgp_speaker_id, - 'routes': routes}}, host) - - def bgp_peer_disassociated(self, context, bgp_speaker_id, - bgp_peer_ip, host): - """Tell BgpDrAgent about a new BGP Peer association. - - This effectively tells the BgpDrAgent to stop a peering session. - """ - self._notification_host_cast(context, 'bgp_peer_disassociation_end', - {'bgp_peer': {'speaker_id': bgp_speaker_id, - 'peer_ip': bgp_peer_ip}}, host) - - def bgp_peer_associated(self, context, bgp_speaker_id, - bgp_peer_id, host): - """Tell BgpDrAgent about a BGP Peer disassociation. - - This effectively tells the bgp_dragent to open a peering session. - """ - self._notification_host_cast(context, 'bgp_peer_association_end', - {'bgp_peer': {'speaker_id': bgp_speaker_id, - 'peer_id': bgp_peer_id}}, host) - - def bgp_speaker_created(self, context, bgp_speaker_id, host): - """Tell BgpDrAgent about the creation of a BGP Speaker. - - Because a BGP Speaker can be created with BgpPeer binding in place, - we need to inform the BgpDrAgent of a new BGP Speaker in case a - peering session needs to opened immediately. - """ - self._notification_host_cast(context, 'bgp_speaker_create_end', - {'bgp_speaker': {'id': bgp_speaker_id}}, host) - - def bgp_speaker_removed(self, context, bgp_speaker_id, host): - """Tell BgpDrAgent about the removal of a BGP Speaker. - - Because a BGP Speaker can be removed with BGP Peer binding in - place, we need to inform the BgpDrAgent of the removal of a - BGP Speaker in case peering sessions need to be stopped. - """ - self._notification_host_cast(context, 'bgp_speaker_remove_end', - {'bgp_speaker': {'id': bgp_speaker_id}}, host) - - def _notification_host_cast(self, context, method, payload, host): - """Send payload to BgpDrAgent in the cast mode""" - cctxt = self.client.prepare(topic=self.topic, server=host) - cctxt.cast(context, method, payload=payload) - - def _notification_host_call(self, context, method, payload, host): - """Send payload to BgpDrAgent in the call mode""" - cctxt = self.client.prepare(topic=self.topic, server=host) - cctxt.call(context, method, payload=payload) diff --git a/neutron/api/rpc/handlers/bgp_speaker_rpc.py b/neutron/api/rpc/handlers/bgp_speaker_rpc.py deleted file mode 100644 index ac71cdf55f2..00000000000 --- a/neutron/api/rpc/handlers/bgp_speaker_rpc.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 oslo_messaging - -from neutron.extensions import bgp as bgp_ext -from neutron import manager - - -class BgpSpeakerRpcCallback(object): - """BgpDrAgent RPC callback in plugin implementations. - - This class implements the server side of an RPC interface. - The client side of this interface can be found in - neutron.services.bgp_speaker.agent.bgp_dragent.BgpDrPluginApi. - For more information about changing RPC interfaces, - see doc/source/devref/rpc_api.rst. - """ - - # API version history: - # 1.0 BGPDRPluginApi BASE_RPC_API_VERSION - target = oslo_messaging.Target(version='1.0') - - @property - def plugin(self): - if not hasattr(self, '_plugin'): - self._plugin = manager.NeutronManager.get_service_plugins().get( - bgp_ext.BGP_EXT_ALIAS) - return self._plugin - - def get_bgp_speaker_info(self, context, bgp_speaker_id): - """Return BGP Speaker details such as peer list and local_as. - - Invoked by the BgpDrAgent to lookup the details of a BGP Speaker. - """ - return self.plugin.get_bgp_speaker_with_advertised_routes( - context, bgp_speaker_id) - - def get_bgp_peer_info(self, context, bgp_peer_id): - """Return BgpPeer details such as IP, remote_as, and credentials. - - Invoked by the BgpDrAgent to lookup the details of a BGP peer. - """ - return self.plugin.get_bgp_peer(context, bgp_peer_id, - ['peer_ip', 'remote_as', - 'auth_type', 'password']) - - def get_bgp_speakers(self, context, host=None, **kwargs): - """Returns the list of all BgpSpeakers. - - Typically invoked by the BgpDrAgent as part of its bootstrap process. - """ - return self.plugin.get_bgp_speakers_for_agent_host(context, host) diff --git a/neutron/cmd/eventlet/agents/bgp_dragent.py b/neutron/cmd/eventlet/agents/bgp_dragent.py deleted file mode 100644 index 924452abe56..00000000000 --- a/neutron/cmd/eventlet/agents/bgp_dragent.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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.services.bgp.agent import entry as bgp_dragent - - -def main(): - bgp_dragent.main() diff --git a/neutron/db/bgp_db.py b/neutron/db/bgp_db.py deleted file mode 100644 index f5760e51b79..00000000000 --- a/neutron/db/bgp_db.py +++ /dev/null @@ -1,1009 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development Company LP -# -# 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 itertools - -from neutron_lib import constants as lib_consts -from neutron_lib import exceptions as n_exc -from oslo_db import exception as oslo_db_exc -from oslo_log import log as logging -from oslo_utils import uuidutils -import sqlalchemy as sa -from sqlalchemy import and_ -from sqlalchemy import orm -from sqlalchemy.orm import aliased -from sqlalchemy.orm import exc as sa_exc - -from neutron._i18n import _ -from neutron.api.v2 import attributes as attr -from neutron.db import address_scope_db -from neutron.db import common_db_mixin as common_db -from neutron.db import l3_attrs_db -from neutron.db import l3_db -from neutron.db import model_base -from neutron.db import models_v2 -from neutron.extensions import bgp as bgp_ext -from neutron.plugins.ml2 import models as ml2_models - - -LOG = logging.getLogger(__name__) -DEVICE_OWNER_ROUTER_GW = lib_consts.DEVICE_OWNER_ROUTER_GW -DEVICE_OWNER_ROUTER_INTF = lib_consts.DEVICE_OWNER_ROUTER_INTF - - -class BgpSpeakerPeerBinding(model_base.BASEV2): - - """Represents a mapping between BGP speaker and BGP peer""" - - __tablename__ = 'bgp_speaker_peer_bindings' - - bgp_speaker_id = sa.Column(sa.String(length=36), - sa.ForeignKey('bgp_speakers.id', - ondelete='CASCADE'), - nullable=False, - primary_key=True) - bgp_peer_id = sa.Column(sa.String(length=36), - sa.ForeignKey('bgp_peers.id', - ondelete='CASCADE'), - nullable=False, - primary_key=True) - - -class BgpSpeakerNetworkBinding(model_base.BASEV2): - - """Represents a mapping between a network and BGP speaker""" - - __tablename__ = 'bgp_speaker_network_bindings' - - bgp_speaker_id = sa.Column(sa.String(length=36), - sa.ForeignKey('bgp_speakers.id', - ondelete='CASCADE'), - nullable=False, - primary_key=True) - network_id = sa.Column(sa.String(length=36), - sa.ForeignKey('networks.id', - ondelete='CASCADE'), - nullable=False, - primary_key=True) - ip_version = sa.Column(sa.Integer, nullable=False, autoincrement=False, - primary_key=True) - - -class BgpSpeaker(model_base.BASEV2, - model_base.HasId, - model_base.HasTenant): - - """Represents a BGP speaker""" - - __tablename__ = 'bgp_speakers' - - name = sa.Column(sa.String(attr.NAME_MAX_LEN), nullable=False) - local_as = sa.Column(sa.Integer, nullable=False, autoincrement=False) - advertise_floating_ip_host_routes = sa.Column(sa.Boolean, nullable=False) - advertise_tenant_networks = sa.Column(sa.Boolean, nullable=False) - peers = orm.relationship(BgpSpeakerPeerBinding, - backref='bgp_speaker_peer_bindings', - cascade='all, delete, delete-orphan', - lazy='joined') - networks = orm.relationship(BgpSpeakerNetworkBinding, - backref='bgp_speaker_network_bindings', - cascade='all, delete, delete-orphan', - lazy='joined') - ip_version = sa.Column(sa.Integer, nullable=False, autoincrement=False) - - -class BgpPeer(model_base.BASEV2, - model_base.HasId, - model_base.HasTenant): - - """Represents a BGP routing peer.""" - - __tablename__ = 'bgp_peers' - - name = sa.Column(sa.String(attr.NAME_MAX_LEN), nullable=False) - peer_ip = sa.Column(sa.String(64), - nullable=False) - remote_as = sa.Column(sa.Integer, nullable=False, autoincrement=False) - auth_type = sa.Column(sa.String(16), nullable=False) - password = sa.Column(sa.String(255), nullable=True) - - -class BgpDbMixin(common_db.CommonDbMixin): - - def create_bgp_speaker(self, context, bgp_speaker): - uuid = uuidutils.generate_uuid() - self._save_bgp_speaker(context, bgp_speaker, uuid) - return self.get_bgp_speaker(context, uuid) - - def get_bgp_speakers(self, context, filters=None, fields=None, - sorts=None, limit=None, marker=None, - page_reverse=False): - with context.session.begin(subtransactions=True): - return self._get_collection(context, BgpSpeaker, - self._make_bgp_speaker_dict, - filters=filters, fields=fields, - sorts=sorts, limit=limit, - page_reverse=page_reverse) - - def get_bgp_speaker(self, context, bgp_speaker_id, fields=None): - with context.session.begin(subtransactions=True): - bgp_speaker = self._get_bgp_speaker(context, bgp_speaker_id) - return self._make_bgp_speaker_dict(bgp_speaker, fields) - - def get_bgp_speaker_with_advertised_routes(self, context, - bgp_speaker_id): - bgp_speaker_attrs = ['id', 'local_as', 'tenant_id'] - bgp_peer_attrs = ['peer_ip', 'remote_as', 'password'] - with context.session.begin(subtransactions=True): - bgp_speaker = self.get_bgp_speaker(context, bgp_speaker_id, - fields=bgp_speaker_attrs) - res = dict((k, bgp_speaker[k]) for k in bgp_speaker_attrs) - res['peers'] = self.get_bgp_peers_by_bgp_speaker(context, - bgp_speaker['id'], - fields=bgp_peer_attrs) - res['advertised_routes'] = self.get_routes_by_bgp_speaker_id( - context, - bgp_speaker_id) - return res - - def update_bgp_speaker(self, context, bgp_speaker_id, bgp_speaker): - bp = bgp_speaker[bgp_ext.BGP_SPEAKER_BODY_KEY_NAME] - with context.session.begin(subtransactions=True): - bgp_speaker_db = self._get_bgp_speaker(context, bgp_speaker_id) - bgp_speaker_db.update(bp) - - bgp_speaker_dict = self._make_bgp_speaker_dict(bgp_speaker_db) - return bgp_speaker_dict - - def _save_bgp_speaker(self, context, bgp_speaker, uuid): - ri = bgp_speaker[bgp_ext.BGP_SPEAKER_BODY_KEY_NAME] - ri['tenant_id'] = context.tenant_id - with context.session.begin(subtransactions=True): - res_keys = ['local_as', 'tenant_id', 'name', 'ip_version', - 'advertise_floating_ip_host_routes', - 'advertise_tenant_networks'] - res = dict((k, ri[k]) for k in res_keys) - res['id'] = uuid - bgp_speaker_db = BgpSpeaker(**res) - context.session.add(bgp_speaker_db) - - def add_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info): - bgp_peer_id = self._get_id_for(bgp_peer_info, 'bgp_peer_id') - self._save_bgp_speaker_peer_binding(context, - bgp_speaker_id, - bgp_peer_id) - return {'bgp_peer_id': bgp_peer_id} - - def remove_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info): - bgp_peer_id = self._get_id_for(bgp_peer_info, 'bgp_peer_id') - self._remove_bgp_speaker_peer_binding(context, - bgp_speaker_id, - bgp_peer_id) - return {'bgp_peer_id': bgp_peer_id} - - def add_gateway_network(self, context, bgp_speaker_id, network_info): - network_id = self._get_id_for(network_info, 'network_id') - with context.session.begin(subtransactions=True): - try: - self._save_bgp_speaker_network_binding(context, - bgp_speaker_id, - network_id) - except oslo_db_exc.DBDuplicateEntry: - raise bgp_ext.BgpSpeakerNetworkBindingError( - network_id=network_id, - bgp_speaker_id=bgp_speaker_id) - return {'network_id': network_id} - - def remove_gateway_network(self, context, bgp_speaker_id, network_info): - with context.session.begin(subtransactions=True): - network_id = self._get_id_for(network_info, 'network_id') - self._remove_bgp_speaker_network_binding(context, - bgp_speaker_id, - network_id) - return {'network_id': network_id} - - def delete_bgp_speaker(self, context, bgp_speaker_id): - with context.session.begin(subtransactions=True): - bgp_speaker_db = self._get_bgp_speaker(context, bgp_speaker_id) - context.session.delete(bgp_speaker_db) - - def create_bgp_peer(self, context, bgp_peer): - ri = bgp_peer[bgp_ext.BGP_PEER_BODY_KEY_NAME] - auth_type = ri.get('auth_type') - password = ri.get('password') - if auth_type == 'md5' and not password: - raise bgp_ext.InvalidBgpPeerMd5Authentication() - - with context.session.begin(subtransactions=True): - res_keys = ['tenant_id', 'name', 'remote_as', 'peer_ip', - 'auth_type', 'password'] - res = dict((k, ri[k]) for k in res_keys) - res['id'] = uuidutils.generate_uuid() - bgp_peer_db = BgpPeer(**res) - context.session.add(bgp_peer_db) - peer = self._make_bgp_peer_dict(bgp_peer_db) - peer.pop('password') - return peer - - def get_bgp_peers(self, context, fields=None, filters=None, sorts=None, - limit=None, marker=None, page_reverse=False): - return self._get_collection(context, BgpPeer, - self._make_bgp_peer_dict, - filters=filters, fields=fields, - sorts=sorts, limit=limit, - page_reverse=page_reverse) - - def get_bgp_peers_by_bgp_speaker(self, context, - bgp_speaker_id, fields=None): - filters = [BgpSpeakerPeerBinding.bgp_speaker_id == bgp_speaker_id, - BgpSpeakerPeerBinding.bgp_peer_id == BgpPeer.id] - with context.session.begin(subtransactions=True): - query = context.session.query(BgpPeer) - query = query.filter(*filters) - return [self._make_bgp_peer_dict(x) for x in query.all()] - - def get_bgp_peer(self, context, bgp_peer_id, fields=None): - bgp_peer_db = self._get_bgp_peer(context, bgp_peer_id) - return self._make_bgp_peer_dict(bgp_peer_db, fields=fields) - - def delete_bgp_peer(self, context, bgp_peer_id): - with context.session.begin(subtransactions=True): - bgp_peer_db = self._get_bgp_peer(context, bgp_peer_id) - context.session.delete(bgp_peer_db) - - def update_bgp_peer(self, context, bgp_peer_id, bgp_peer): - bp = bgp_peer[bgp_ext.BGP_PEER_BODY_KEY_NAME] - with context.session.begin(subtransactions=True): - bgp_peer_db = self._get_bgp_peer(context, bgp_peer_id) - if ((bp['password'] is not None) and - (bgp_peer_db['auth_type'] == 'none')): - raise bgp_ext.BgpPeerNotAuthenticated(bgp_peer_id=bgp_peer_id) - bgp_peer_db.update(bp) - - bgp_peer_dict = self._make_bgp_peer_dict(bgp_peer_db) - return bgp_peer_dict - - def _get_bgp_speaker(self, context, bgp_speaker_id): - try: - return self._get_by_id(context, BgpSpeaker, - bgp_speaker_id) - except sa_exc.NoResultFound: - raise bgp_ext.BgpSpeakerNotFound(id=bgp_speaker_id) - - def _get_bgp_speaker_ids_by_router(self, context, router_id): - with context.session.begin(subtransactions=True): - network_binding = aliased(BgpSpeakerNetworkBinding) - r_port = aliased(l3_db.RouterPort) - query = context.session.query(network_binding.bgp_speaker_id) - query = query.filter( - r_port.router_id == router_id, - r_port.port_type == lib_consts.DEVICE_OWNER_ROUTER_GW, - r_port.port_id == models_v2.Port.id, - models_v2.Port.network_id == network_binding.network_id) - - return [binding.bgp_speaker_id for binding in query.all()] - - def _get_bgp_speaker_ids_by_binding_network(self, context, network_id): - with context.session.begin(subtransactions=True): - query = context.session.query( - BgpSpeakerNetworkBinding.bgp_speaker_id) - query = query.filter( - BgpSpeakerNetworkBinding.network_id == network_id) - return query.all() - - def get_advertised_routes(self, context, bgp_speaker_id): - routes = self.get_routes_by_bgp_speaker_id(context, bgp_speaker_id) - return self._make_advertised_routes_dict(routes) - - def _get_id_for(self, resource, id_name): - try: - return resource.get(id_name) - except AttributeError: - msg = _("%s must be specified") % id_name - raise n_exc.BadRequest(resource=bgp_ext.BGP_SPEAKER_RESOURCE_NAME, - msg=msg) - - def _get_bgp_peers_by_bgp_speaker_binding(self, context, bgp_speaker_id): - with context.session.begin(subtransactions=True): - query = context.session.query(BgpPeer) - query = query.filter( - BgpSpeakerPeerBinding.bgp_speaker_id == bgp_speaker_id, - BgpSpeakerPeerBinding.bgp_peer_id == BgpPeer.id) - return query.all() - - def _save_bgp_speaker_peer_binding(self, context, bgp_speaker_id, - bgp_peer_id): - with context.session.begin(subtransactions=True): - try: - bgp_speaker = self._get_by_id(context, BgpSpeaker, - bgp_speaker_id) - except sa_exc.NoResultFound: - raise bgp_ext.BgpSpeakerNotFound(id=bgp_speaker_id) - - try: - bgp_peer = self._get_by_id(context, BgpPeer, - bgp_peer_id) - except sa_exc.NoResultFound: - raise bgp_ext.BgpPeerNotFound(id=bgp_peer_id) - - peers = self._get_bgp_peers_by_bgp_speaker_binding(context, - bgp_speaker_id) - self._validate_peer_ips(bgp_speaker_id, peers, bgp_peer) - binding = BgpSpeakerPeerBinding(bgp_speaker_id=bgp_speaker.id, - bgp_peer_id=bgp_peer.id) - context.session.add(binding) - - def _validate_peer_ips(self, bgp_speaker_id, current_peers, new_peer): - for peer in current_peers: - if peer.peer_ip == new_peer.peer_ip: - raise bgp_ext.DuplicateBgpPeerIpException( - bgp_peer_id=new_peer.id, - peer_ip=new_peer.peer_ip, - bgp_speaker_id=bgp_speaker_id) - - def _remove_bgp_speaker_peer_binding(self, context, bgp_speaker_id, - bgp_peer_id): - with context.session.begin(subtransactions=True): - - try: - binding = self._get_bgp_speaker_peer_binding(context, - bgp_speaker_id, - bgp_peer_id) - except sa_exc.NoResultFound: - raise bgp_ext.BgpSpeakerPeerNotAssociated( - bgp_peer_id=bgp_peer_id, - bgp_speaker_id=bgp_speaker_id) - context.session.delete(binding) - - def _save_bgp_speaker_network_binding(self, - context, - bgp_speaker_id, - network_id): - with context.session.begin(subtransactions=True): - try: - bgp_speaker = self._get_by_id(context, BgpSpeaker, - bgp_speaker_id) - except sa_exc.NoResultFound: - raise bgp_ext.BgpSpeakerNotFound(id=bgp_speaker_id) - - try: - network = self._get_by_id(context, models_v2.Network, - network_id) - except sa_exc.NoResultFound: - raise n_exc.NetworkNotFound(net_id=network_id) - - binding = BgpSpeakerNetworkBinding( - bgp_speaker_id=bgp_speaker.id, - network_id=network.id, - ip_version=bgp_speaker.ip_version) - context.session.add(binding) - - def _remove_bgp_speaker_network_binding(self, context, - bgp_speaker_id, network_id): - with context.session.begin(subtransactions=True): - - try: - binding = self._get_bgp_speaker_network_binding( - context, - bgp_speaker_id, - network_id) - except sa_exc.NoResultFound: - raise bgp_ext.BgpSpeakerNetworkNotAssociated( - network_id=network_id, - bgp_speaker_id=bgp_speaker_id) - context.session.delete(binding) - - def _make_bgp_speaker_dict(self, bgp_speaker, fields=None): - attrs = {'id', 'local_as', 'tenant_id', 'name', 'ip_version', - 'advertise_floating_ip_host_routes', - 'advertise_tenant_networks'} - peer_bindings = bgp_speaker['peers'] - network_bindings = bgp_speaker['networks'] - res = dict((k, bgp_speaker[k]) for k in attrs) - res['peers'] = [x.bgp_peer_id for x in peer_bindings] - res['networks'] = [x.network_id for x in network_bindings] - return self._fields(res, fields) - - def _make_advertised_routes_dict(self, routes): - return {'advertised_routes': list(routes)} - - def _get_bgp_peer(self, context, bgp_peer_id): - try: - return self._get_by_id(context, BgpPeer, bgp_peer_id) - except sa_exc.NoResultFound: - raise bgp_ext.BgpPeerNotFound(id=bgp_peer_id) - - def _get_bgp_speaker_peer_binding(self, context, - bgp_speaker_id, bgp_peer_id): - query = self._model_query(context, BgpSpeakerPeerBinding) - return query.filter( - BgpSpeakerPeerBinding.bgp_speaker_id == bgp_speaker_id, - BgpSpeakerPeerBinding.bgp_peer_id == bgp_peer_id).one() - - def _get_bgp_speaker_network_binding(self, context, - bgp_speaker_id, network_id): - query = self._model_query(context, BgpSpeakerNetworkBinding) - return query.filter(bgp_speaker_id == bgp_speaker_id, - network_id == network_id).one() - - def _make_bgp_peer_dict(self, bgp_peer, fields=None): - attrs = ['tenant_id', 'id', 'name', 'peer_ip', 'remote_as', - 'auth_type', 'password'] - res = dict((k, bgp_peer[k]) for k in attrs) - return self._fields(res, fields) - - def _get_address_scope_ids_for_bgp_speaker(self, context, bgp_speaker_id): - with context.session.begin(subtransactions=True): - binding = aliased(BgpSpeakerNetworkBinding) - address_scope = aliased(address_scope_db.AddressScope) - query = context.session.query(address_scope) - query = query.filter( - binding.bgp_speaker_id == bgp_speaker_id, - models_v2.Subnet.ip_version == binding.ip_version, - models_v2.Subnet.network_id == binding.network_id, - models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id, - models_v2.SubnetPool.address_scope_id == address_scope.id) - return [scope.id for scope in query.all()] - - def get_routes_by_bgp_speaker_id(self, context, bgp_speaker_id): - """Get all routes that should be advertised by a BgpSpeaker.""" - with context.session.begin(subtransactions=True): - net_routes = self._get_tenant_network_routes_by_bgp_speaker( - context, - bgp_speaker_id) - fip_routes = self._get_central_fip_host_routes_by_bgp_speaker( - context, - bgp_speaker_id) - dvr_fip_routes = self._get_dvr_fip_host_routes_by_bgp_speaker( - context, - bgp_speaker_id) - return itertools.chain(fip_routes, net_routes, dvr_fip_routes) - - def get_routes_by_bgp_speaker_binding(self, context, - bgp_speaker_id, network_id): - """Get all routes for the given bgp_speaker binding.""" - with context.session.begin(subtransactions=True): - fip_routes = self._get_central_fip_host_routes_by_binding( - context, - network_id, - bgp_speaker_id) - net_routes = self._get_tenant_network_routes_by_binding( - context, - network_id, - bgp_speaker_id) - dvr_fip_routes = self._get_dvr_fip_host_routes_by_binding( - context, - network_id, - bgp_speaker_id) - return itertools.chain(fip_routes, net_routes, dvr_fip_routes) - - def _get_routes_by_router(self, context, router_id): - bgp_speaker_ids = self._get_bgp_speaker_ids_by_router(context, - router_id) - route_dict = {} - for bgp_speaker_id in bgp_speaker_ids: - fip_routes = self._get_central_fip_host_routes_by_router( - context, - router_id, - bgp_speaker_id) - net_routes = self._get_tenant_network_routes_by_router( - context, - router_id, - bgp_speaker_id) - dvr_fip_routes = self._get_dvr_fip_host_routes_by_router( - context, - router_id, - bgp_speaker_id) - routes = itertools.chain(fip_routes, net_routes, dvr_fip_routes) - route_dict[bgp_speaker_id] = list(routes) - return route_dict - - def _get_central_fip_host_routes_by_router(self, context, router_id, - bgp_speaker_id): - """Get floating IP host routes with the given router as nexthop.""" - with context.session.begin(subtransactions=True): - dest_alias = aliased(l3_db.FloatingIP, - name='destination') - next_hop_alias = aliased(models_v2.IPAllocation, - name='next_hop') - binding_alias = aliased(BgpSpeakerNetworkBinding, - name='binding') - router_attrs = aliased(l3_attrs_db.RouterExtraAttributes, - name='router_attrs') - query = context.session.query(dest_alias.floating_ip_address, - next_hop_alias.ip_address) - query = query.join( - next_hop_alias, - next_hop_alias.network_id == dest_alias.floating_network_id) - query = query.join(l3_db.Router, - dest_alias.router_id == l3_db.Router.id) - query = query.filter( - l3_db.Router.id == router_id, - dest_alias.router_id == l3_db.Router.id, - l3_db.Router.id == router_attrs.router_id, - router_attrs.distributed == sa.sql.false(), - l3_db.Router.gw_port_id == next_hop_alias.port_id, - next_hop_alias.subnet_id == models_v2.Subnet.id, - models_v2.Subnet.ip_version == 4, - binding_alias.network_id == models_v2.Subnet.network_id, - binding_alias.bgp_speaker_id == bgp_speaker_id, - binding_alias.ip_version == 4, - BgpSpeaker.advertise_floating_ip_host_routes == sa.sql.true()) - query = query.outerjoin(router_attrs, - l3_db.Router.id == router_attrs.router_id) - query = query.filter(router_attrs.distributed != sa.sql.true()) - return self._host_route_list_from_tuples(query.all()) - - def _get_dvr_fip_host_routes_by_router(self, context, bgp_speaker_id, - router_id): - with context.session.begin(subtransactions=True): - gw_query = self._get_gateway_query(context, bgp_speaker_id) - - fip_query = self._get_fip_query(context, bgp_speaker_id) - fip_query.filter(l3_db.FloatingIP.router_id == router_id) - - #Create the join query - join_query = self._join_fip_by_host_binding_to_agent_gateway( - context, - fip_query.subquery(), - gw_query.subquery()) - return self._host_route_list_from_tuples(join_query.all()) - - def _get_central_fip_host_routes_by_binding(self, context, - network_id, bgp_speaker_id): - """Get all floating IP host routes for the given network binding.""" - with context.session.begin(subtransactions=True): - # Query the DB for floating IP's and the IP address of the - # gateway port - dest_alias = aliased(l3_db.FloatingIP, - name='destination') - next_hop_alias = aliased(models_v2.IPAllocation, - name='next_hop') - binding_alias = aliased(BgpSpeakerNetworkBinding, - name='binding') - router_attrs = aliased(l3_attrs_db.RouterExtraAttributes, - name='router_attrs') - query = context.session.query(dest_alias.floating_ip_address, - next_hop_alias.ip_address) - query = query.join( - next_hop_alias, - next_hop_alias.network_id == dest_alias.floating_network_id) - query = query.join( - binding_alias, - binding_alias.network_id == dest_alias.floating_network_id) - query = query.join(l3_db.Router, - dest_alias.router_id == l3_db.Router.id) - query = query.filter( - dest_alias.floating_network_id == network_id, - dest_alias.router_id == l3_db.Router.id, - l3_db.Router.gw_port_id == next_hop_alias.port_id, - next_hop_alias.subnet_id == models_v2.Subnet.id, - models_v2.Subnet.ip_version == 4, - binding_alias.network_id == models_v2.Subnet.network_id, - binding_alias.bgp_speaker_id == BgpSpeaker.id, - BgpSpeaker.id == bgp_speaker_id, - BgpSpeaker.advertise_floating_ip_host_routes == sa.sql.true()) - query = query.outerjoin(router_attrs, - l3_db.Router.id == router_attrs.router_id) - query = query.filter(router_attrs.distributed != sa.sql.true()) - return self._host_route_list_from_tuples(query.all()) - - def _get_dvr_fip_host_routes_by_binding(self, context, network_id, - bgp_speaker_id): - with context.session.begin(subtransactions=True): - BgpBinding = BgpSpeakerNetworkBinding - - gw_query = self._get_gateway_query(context, bgp_speaker_id) - gw_query.filter(BgpBinding.network_id == network_id) - - fip_query = self._get_fip_query(context, bgp_speaker_id) - fip_query.filter(BgpBinding.network_id == network_id) - - #Create the join query - join_query = self._join_fip_by_host_binding_to_agent_gateway( - context, - fip_query.subquery(), - gw_query.subquery()) - return self._host_route_list_from_tuples(join_query.all()) - - def _get_central_fip_host_routes_by_bgp_speaker(self, context, - bgp_speaker_id): - """Get all the floating IP host routes advertised by a BgpSpeaker.""" - with context.session.begin(subtransactions=True): - dest_alias = aliased(l3_db.FloatingIP, - name='destination') - next_hop_alias = aliased(models_v2.IPAllocation, - name='next_hop') - speaker_binding = aliased(BgpSpeakerNetworkBinding, - name="speaker_network_mapping") - router_attrs = aliased(l3_attrs_db.RouterExtraAttributes, - name='router_attrs') - query = context.session.query(dest_alias.floating_ip_address, - next_hop_alias.ip_address) - query = query.select_from(dest_alias, - BgpSpeaker, - l3_db.Router, - models_v2.Subnet) - query = query.join( - next_hop_alias, - next_hop_alias.network_id == dest_alias.floating_network_id) - query = query.join( - speaker_binding, - speaker_binding.network_id == dest_alias.floating_network_id) - query = query.join(l3_db.Router, - dest_alias.router_id == l3_db.Router.id) - query = query.filter( - BgpSpeaker.id == bgp_speaker_id, - BgpSpeaker.advertise_floating_ip_host_routes, - speaker_binding.bgp_speaker_id == BgpSpeaker.id, - dest_alias.floating_network_id == speaker_binding.network_id, - next_hop_alias.network_id == speaker_binding.network_id, - dest_alias.router_id == l3_db.Router.id, - l3_db.Router.gw_port_id == next_hop_alias.port_id, - next_hop_alias.subnet_id == models_v2.Subnet.id, - models_v2.Subnet.ip_version == 4) - query = query.outerjoin(router_attrs, - l3_db.Router.id == router_attrs.router_id) - query = query.filter(router_attrs.distributed != sa.sql.true()) - return self._host_route_list_from_tuples(query.all()) - - def _get_gateway_query(self, context, bgp_speaker_id): - BgpBinding = BgpSpeakerNetworkBinding - ML2PortBinding = ml2_models.PortBinding - IpAllocation = models_v2.IPAllocation - Port = models_v2.Port - gw_query = context.session.query(Port.network_id, - ML2PortBinding.host, - IpAllocation.ip_address) - - #Subquery for FIP agent gateway ports - gw_query = gw_query.filter( - ML2PortBinding.port_id == Port.id, - IpAllocation.port_id == Port.id, - IpAllocation.subnet_id == models_v2.Subnet.id, - models_v2.Subnet.ip_version == 4, - Port.device_owner == lib_consts.DEVICE_OWNER_AGENT_GW, - Port.network_id == BgpBinding.network_id, - BgpBinding.bgp_speaker_id == bgp_speaker_id, - BgpBinding.ip_version == 4) - return gw_query - - def _get_fip_query(self, context, bgp_speaker_id): - BgpBinding = BgpSpeakerNetworkBinding - ML2PortBinding = ml2_models.PortBinding - - #Subquery for floating IP's - fip_query = context.session.query( - l3_db.FloatingIP.floating_network_id, - ML2PortBinding.host, - l3_db.FloatingIP.floating_ip_address) - fip_query = fip_query.filter( - l3_db.FloatingIP.fixed_port_id == ML2PortBinding.port_id, - l3_db.FloatingIP.floating_network_id == BgpBinding.network_id, - BgpBinding.bgp_speaker_id == bgp_speaker_id) - return fip_query - - def _get_dvr_fip_host_routes_by_bgp_speaker(self, context, - bgp_speaker_id): - with context.session.begin(subtransactions=True): - gw_query = self._get_gateway_query(context, bgp_speaker_id) - fip_query = self._get_fip_query(context, bgp_speaker_id) - - #Create the join query - join_query = self._join_fip_by_host_binding_to_agent_gateway( - context, - fip_query.subquery(), - gw_query.subquery()) - return self._host_route_list_from_tuples(join_query.all()) - - def _join_fip_by_host_binding_to_agent_gateway(self, context, - fip_subq, gw_subq): - join_query = context.session.query(fip_subq.c.floating_ip_address, - gw_subq.c.ip_address) - and_cond = and_( - gw_subq.c.host == fip_subq.c.host, - gw_subq.c.network_id == fip_subq.c.floating_network_id) - - return join_query.join(gw_subq, and_cond) - - def _get_tenant_network_routes_by_binding(self, context, - network_id, bgp_speaker_id): - """Get all tenant network routes for the given network.""" - - with context.session.begin(subtransactions=True): - tenant_networks_query = self._tenant_networks_by_network_query( - context, - network_id, - bgp_speaker_id) - nexthops_query = self._nexthop_ip_addresses_by_binding_query( - context, - network_id, - bgp_speaker_id) - join_q = self._join_tenant_networks_to_next_hops( - context, - tenant_networks_query.subquery(), - nexthops_query.subquery()) - return self._make_advertised_routes_list(join_q.all()) - - def _get_tenant_network_routes_by_router(self, context, router_id, - bgp_speaker_id): - """Get all tenant network routes with the given router as nexthop.""" - - with context.session.begin(subtransactions=True): - scopes = self._get_address_scope_ids_for_bgp_speaker( - context, - bgp_speaker_id) - address_scope = aliased(address_scope_db.AddressScope) - inside_query = context.session.query( - models_v2.Subnet.cidr, - models_v2.IPAllocation.ip_address, - address_scope.id) - outside_query = context.session.query( - address_scope.id, - models_v2.IPAllocation.ip_address) - speaker_binding = aliased(BgpSpeakerNetworkBinding, - name="speaker_network_mapping") - port_alias = aliased(l3_db.RouterPort, name='routerport') - inside_query = inside_query.filter( - port_alias.router_id == router_id, - models_v2.IPAllocation.port_id == port_alias.port_id, - models_v2.IPAllocation.subnet_id == models_v2.Subnet.id, - models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id, - models_v2.SubnetPool.address_scope_id == address_scope.id, - address_scope.id.in_(scopes), - port_alias.port_type != lib_consts.DEVICE_OWNER_ROUTER_GW, - speaker_binding.bgp_speaker_id == bgp_speaker_id) - outside_query = outside_query.filter( - port_alias.router_id == router_id, - port_alias.port_type == lib_consts.DEVICE_OWNER_ROUTER_GW, - models_v2.IPAllocation.port_id == port_alias.port_id, - models_v2.IPAllocation.subnet_id == models_v2.Subnet.id, - models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id, - models_v2.SubnetPool.address_scope_id == address_scope.id, - address_scope.id.in_(scopes), - speaker_binding.bgp_speaker_id == bgp_speaker_id, - speaker_binding.network_id == models_v2.Port.network_id, - port_alias.port_id == models_v2.Port.id) - inside_query = inside_query.subquery() - outside_query = outside_query.subquery() - join_query = context.session.query(inside_query.c.cidr, - outside_query.c.ip_address) - and_cond = and_(inside_query.c.id == outside_query.c.id) - join_query = join_query.join(outside_query, and_cond) - return self._make_advertised_routes_list(join_query.all()) - - def _get_tenant_network_routes_by_bgp_speaker(self, context, - bgp_speaker_id): - """Get all tenant network routes to be advertised by a BgpSpeaker.""" - - with context.session.begin(subtransactions=True): - tenant_nets_q = self._tenant_networks_by_bgp_speaker_query( - context, - bgp_speaker_id) - nexthops_q = self._nexthop_ip_addresses_by_bgp_speaker_query( - context, - bgp_speaker_id) - join_q = self._join_tenant_networks_to_next_hops( - context, - tenant_nets_q.subquery(), - nexthops_q.subquery()) - - return self._make_advertised_routes_list(join_q.all()) - - def _join_tenant_networks_to_next_hops(self, context, - tenant_networks_subquery, - nexthops_subquery): - """Join subquery for tenant networks to subquery for nexthop IP's""" - left_subq = tenant_networks_subquery - right_subq = nexthops_subquery - join_query = context.session.query(left_subq.c.cidr, - right_subq.c.ip_address) - and_cond = and_(left_subq.c.router_id == right_subq.c.router_id, - left_subq.c.ip_version == right_subq.c.ip_version) - join_query = join_query.join(right_subq, and_cond) - return join_query - - def _tenant_networks_by_network_query(self, context, - network_id, bgp_speaker_id): - """Return subquery for tenant networks by binding network ID""" - address_scope = aliased(address_scope_db.AddressScope, - name='address_scope') - router_attrs = aliased(l3_attrs_db.RouterExtraAttributes, - name='router_attrs') - tenant_networks_query = context.session.query( - l3_db.RouterPort.router_id, - models_v2.Subnet.cidr, - models_v2.Subnet.ip_version, - address_scope.id) - tenant_networks_query = tenant_networks_query.filter( - l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_GW, - l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_SNAT, - l3_db.RouterPort.router_id == router_attrs.router_id, - models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id, - models_v2.IPAllocation.subnet_id == models_v2.Subnet.id, - models_v2.Subnet.network_id != network_id, - models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id, - models_v2.SubnetPool.address_scope_id == address_scope.id, - BgpSpeaker.id == bgp_speaker_id, - BgpSpeaker.ip_version == address_scope.ip_version, - models_v2.Subnet.ip_version == address_scope.ip_version) - return tenant_networks_query - - def _tenant_networks_by_bgp_speaker_query(self, context, bgp_speaker_id): - """Return subquery for tenant networks by binding bgp_speaker_id""" - router_id = l3_db.RouterPort.router_id.distinct().label('router_id') - tenant_nets_subq = context.session.query(router_id, - models_v2.Subnet.cidr, - models_v2.Subnet.ip_version) - scopes = self._get_address_scope_ids_for_bgp_speaker(context, - bgp_speaker_id) - filters = self._tenant_networks_by_bgp_speaker_filters(scopes) - tenant_nets_subq = tenant_nets_subq.filter(*filters) - return tenant_nets_subq - - def _tenant_networks_by_bgp_speaker_filters(self, address_scope_ids): - """Return the filters for querying tenant networks by BGP speaker""" - router_attrs = aliased(l3_attrs_db.RouterExtraAttributes, - name='router_attrs') - return [models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id, - l3_db.RouterPort.router_id == router_attrs.router_id, - l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_GW, - l3_db.RouterPort.port_type != lib_consts.DEVICE_OWNER_ROUTER_SNAT, - models_v2.IPAllocation.subnet_id == models_v2.Subnet.id, - models_v2.Subnet.network_id != BgpSpeakerNetworkBinding.network_id, - models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id, - models_v2.SubnetPool.address_scope_id.in_(address_scope_ids), - models_v2.Subnet.ip_version == BgpSpeakerNetworkBinding.ip_version, - BgpSpeakerNetworkBinding.bgp_speaker_id == BgpSpeaker.id, - BgpSpeaker.advertise_tenant_networks == sa.sql.true()] - - def _nexthop_ip_addresses_by_binding_query(self, context, - network_id, bgp_speaker_id): - """Return the subquery for locating nexthops by binding network""" - nexthops_query = context.session.query( - l3_db.RouterPort.router_id, - models_v2.IPAllocation.ip_address, - models_v2.Subnet.ip_version) - filters = self._next_hop_ip_addresses_by_binding_filters( - network_id, - bgp_speaker_id) - nexthops_query = nexthops_query.filter(*filters) - return nexthops_query - - def _next_hop_ip_addresses_by_binding_filters(self, - network_id, - bgp_speaker_id): - """Return the filters for querying nexthops by binding network""" - address_scope = aliased(address_scope_db.AddressScope, - name='address_scope') - return [models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id, - models_v2.IPAllocation.subnet_id == models_v2.Subnet.id, - BgpSpeaker.id == bgp_speaker_id, - BgpSpeakerNetworkBinding.bgp_speaker_id == BgpSpeaker.id, - BgpSpeakerNetworkBinding.network_id == network_id, - models_v2.Subnet.network_id == BgpSpeakerNetworkBinding.network_id, - models_v2.Subnet.subnetpool_id == models_v2.SubnetPool.id, - models_v2.SubnetPool.address_scope_id == address_scope.id, - models_v2.Subnet.ip_version == address_scope.ip_version, - l3_db.RouterPort.port_type == DEVICE_OWNER_ROUTER_GW] - - def _nexthop_ip_addresses_by_bgp_speaker_query(self, context, - bgp_speaker_id): - """Return the subquery for locating nexthops by BGP speaker""" - nexthops_query = context.session.query( - l3_db.RouterPort.router_id, - models_v2.IPAllocation.ip_address, - models_v2.Subnet.ip_version) - filters = self._next_hop_ip_addresses_by_bgp_speaker_filters( - bgp_speaker_id) - nexthops_query = nexthops_query.filter(*filters) - return nexthops_query - - def _next_hop_ip_addresses_by_bgp_speaker_filters(self, bgp_speaker_id): - """Return the filters for querying nexthops by BGP speaker""" - router_attrs = aliased(l3_attrs_db.RouterExtraAttributes, - name='router_attrs') - - return [l3_db.RouterPort.port_type == DEVICE_OWNER_ROUTER_GW, - l3_db.RouterPort.router_id == router_attrs.router_id, - BgpSpeakerNetworkBinding.network_id == models_v2.Subnet.network_id, - BgpSpeakerNetworkBinding.ip_version == models_v2.Subnet.ip_version, - BgpSpeakerNetworkBinding.bgp_speaker_id == bgp_speaker_id, - models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id, - models_v2.IPAllocation.subnet_id == models_v2.Subnet.id] - - def _tenant_prefixes_by_router(self, context, router_id, bgp_speaker_id): - with context.session.begin(subtransactions=True): - query = context.session.query(models_v2.Subnet.cidr.distinct()) - filters = self._tenant_prefixes_by_router_filters(router_id, - bgp_speaker_id) - query = query.filter(*filters) - return [x[0] for x in query.all()] - - def _tenant_prefixes_by_router_filters(self, router_id, bgp_speaker_id): - binding = aliased(BgpSpeakerNetworkBinding, name='network_binding') - subnetpool = aliased(models_v2.SubnetPool, - name='subnetpool') - router_attrs = aliased(l3_attrs_db.RouterExtraAttributes, - name='router_attrs') - return [models_v2.Subnet.id == models_v2.IPAllocation.subnet_id, - models_v2.Subnet.subnetpool_id == subnetpool.id, - l3_db.RouterPort.router_id == router_id, - l3_db.Router.id == l3_db.RouterPort.router_id, - l3_db.Router.id == router_attrs.router_id, - l3_db.Router.gw_port_id == models_v2.Port.id, - models_v2.Port.network_id == binding.network_id, - binding.bgp_speaker_id == BgpSpeaker.id, - l3_db.RouterPort.port_type == DEVICE_OWNER_ROUTER_INTF, - models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id] - - def _tenant_prefixes_by_router_interface(self, - context, - router_port_id, - bgp_speaker_id): - with context.session.begin(subtransactions=True): - query = context.session.query(models_v2.Subnet.cidr.distinct()) - filters = self._tenant_prefixes_by_router_filters(router_port_id, - bgp_speaker_id) - query = query.filter(*filters) - return [x[0] for x in query.all()] - - def _tenant_prefixes_by_router_port_filters(self, - router_port_id, - bgp_speaker_id): - binding = aliased(BgpSpeakerNetworkBinding, name='network_binding') - return [models_v2.Subnet.id == models_v2.IPAllocation.subnet_id, - l3_db.RouterPort.port_id == router_port_id, - l3_db.Router.id == l3_db.RouterPort.router_id, - l3_db.Router.gw_port_id == models_v2.Port.id, - models_v2.Port.network_id == binding.network_id, - binding.bgp_speaker_id == BgpSpeaker.id, - models_v2.Subnet.ip_version == binding.ip_version, - l3_db.RouterPort.port_type == DEVICE_OWNER_ROUTER_INTF, - models_v2.IPAllocation.port_id == l3_db.RouterPort.port_id] - - def _bgp_speakers_for_gateway_network(self, context, network_id): - """Return all BgpSpeakers for the given gateway network""" - with context.session.begin(subtransactions=True): - query = context.session.query(BgpSpeaker) - query = query.filter( - BgpSpeakerNetworkBinding.network_id == network_id, - BgpSpeakerNetworkBinding.bgp_speaker_id == BgpSpeaker.id) - return query.all() - - def _bgp_speakers_for_gw_network_by_family(self, context, - network_id, ip_version): - """Return the BgpSpeaker by given gateway network and ip_version""" - with context.session.begin(subtransactions=True): - query = context.session.query(BgpSpeaker) - query = query.filter( - BgpSpeakerNetworkBinding.network_id == network_id, - BgpSpeakerNetworkBinding.bgp_speaker_id == BgpSpeaker.id, - BgpSpeakerNetworkBinding.ip_version == ip_version) - return query.all() - - def _make_advertised_routes_list(self, routes): - route_list = ({'destination': x, - 'next_hop': y} for x, y in routes) - return route_list - - def _route_list_from_prefixes_and_next_hop(self, routes, next_hop): - route_list = [{'destination': x, - 'next_hop': next_hop} for x in routes] - return route_list - - def _host_route_list_from_tuples(self, ip_next_hop_tuples): - """Return the list of host routes given a list of (IP, nexthop)""" - return ({'destination': x + '/32', - 'next_hop': y} for x, y in ip_next_hop_tuples) diff --git a/neutron/db/bgp_dragentscheduler_db.py b/neutron/db/bgp_dragentscheduler_db.py deleted file mode 100644 index ee7c03888c4..00000000000 --- a/neutron/db/bgp_dragentscheduler_db.py +++ /dev/null @@ -1,215 +0,0 @@ -# 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 sqlalchemy.orm import exc - -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: - agents = self.bgp_drscheduler.schedule(context, - created_bgp_speaker) - for agent in agents: - self._bgp_rpc.bgp_speaker_created(context, - created_bgp_speaker['id'], - agent.host) - 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) - - self._bgp_rpc.bgp_speaker_created(context, speaker_id, agent_db.host) - - 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}) - - self._bgp_rpc.bgp_speaker_removed(context, speaker_id, agent_db.host) - - 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})} - - def get_bgp_speakers_for_agent_host(self, context, host): - agent = self._get_agent_by_type_and_host( - context, bgp_consts.AGENT_TYPE_BGP_ROUTING, host) - if not agent.admin_state_up: - return {} - - query = context.session.query(BgpSpeakerDrAgentBinding) - query = query.filter(BgpSpeakerDrAgentBinding.agent_id == agent.id) - try: - binding = query.one() - except exc.NoResultFound: - return [] - bgp_speaker = self.get_bgp_speaker_with_advertised_routes( - context, binding['bgp_speaker_id']) - return [bgp_speaker] - - def get_bgp_speaker_by_speaker_id(self, context, bgp_speaker_id): - try: - return self.get_bgp_speaker(context, bgp_speaker_id) - except exc.NoResultFound: - return {} - - def get_bgp_peer_by_peer_id(self, context, bgp_peer_id): - try: - return self.get_bgp_peer(context, bgp_peer_id) - except exc.NoResultFound: - return {} diff --git a/neutron/db/migration/alembic_migrations/external.py b/neutron/db/migration/alembic_migrations/external.py index 8cffe22ace8..28980ff8ed7 100644 --- a/neutron/db/migration/alembic_migrations/external.py +++ b/neutron/db/migration/alembic_migrations/external.py @@ -31,6 +31,15 @@ REPO_ARISTA_TABLES = [ 'arista_provisioned_tenants', ] +# BGP models in openstack/neutron-dynamic-routing +REPO_NEUTRON_DYNAMIC_ROUTING_TABLES = [ + 'bgp_speakers', + 'bgp_peers', + 'bgp_speaker_network_bindings', + 'bgp_speaker_peer_bindings', + 'bgp_speaker_dragent_bindings', +] + # Models moved to openstack/networking-cisco REPO_CISCO_TABLES = [ 'cisco_ml2_apic_contracts', @@ -113,6 +122,7 @@ REPO_NUAGE_TABLES = [ TABLES = (FWAAS_TABLES + LBAAS_TABLES + VPNAAS_TABLES + REPO_ARISTA_TABLES + + REPO_NEUTRON_DYNAMIC_ROUTING_TABLES + REPO_CISCO_TABLES + REPO_VMWARE_TABLES + REPO_BROCADE_TABLES + diff --git a/neutron/db/migration/models/head.py b/neutron/db/migration/models/head.py index 98e7e42e409..9c4c5d9cca5 100644 --- a/neutron/db/migration/models/head.py +++ b/neutron/db/migration/models/head.py @@ -25,8 +25,6 @@ from neutron.db import address_scope_db # noqa from neutron.db import agents_db # noqa from neutron.db import agentschedulers_db # noqa from neutron.db import allowedaddresspairs_db # noqa -from neutron.db import bgp_db # noqa -from neutron.db import bgp_dragentscheduler_db # noqa from neutron.db import dns_db # noqa from neutron.db import dvr_mac_db # noqa from neutron.db import external_net_db # noqa diff --git a/neutron/extensions/bgp.py b/neutron/extensions/bgp.py deleted file mode 100644 index eda950cb4b5..00000000000 --- a/neutron/extensions/bgp.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2016 Hewlett Packard Development Coompany LP -# -# 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_lib.api import converters -from neutron_lib import exceptions - -from neutron._i18n import _ -from neutron.api import extensions -from neutron.api.v2 import attributes as attr -from neutron.api.v2 import resource_helper as rh -from neutron.services.bgp.common import constants as bgp_consts - -BGP_EXT_ALIAS = 'bgp' -BGP_SPEAKER_RESOURCE_NAME = 'bgp-speaker' -BGP_SPEAKER_BODY_KEY_NAME = 'bgp_speaker' -BGP_PEER_BODY_KEY_NAME = 'bgp_peer' - - -RESOURCE_ATTRIBUTE_MAP = { - BGP_SPEAKER_RESOURCE_NAME + 's': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, 'primary_key': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': attr.NAME_MAX_LEN}, - 'is_visible': True, 'default': ''}, - 'local_as': {'allow_post': True, 'allow_put': False, - 'validate': {'type:range': (bgp_consts.MIN_ASNUM, - bgp_consts.MAX_ASNUM)}, - 'is_visible': True, 'default': None, - 'required_by_policy': False, - 'enforce_policy': False}, - 'ip_version': {'allow_post': True, 'allow_put': False, - 'validate': {'type:values': [4, 6]}, - 'is_visible': True, 'default': None, - 'required_by_policy': False, - 'enforce_policy': False}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': False, - 'validate': {'type:string': attr.TENANT_ID_MAX_LEN}, - 'is_visible': True}, - 'peers': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid_list': None}, - 'is_visible': True, 'default': [], - 'required_by_policy': False, - 'enforce_policy': True}, - 'networks': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid_list': None}, - 'is_visible': True, 'default': [], - 'required_by_policy': False, - 'enforce_policy': True}, - 'advertise_floating_ip_host_routes': { - 'allow_post': True, - 'allow_put': True, - 'convert_to': converters.convert_to_boolean, - 'validate': {'type:boolean': None}, - 'is_visible': True, 'default': True, - 'required_by_policy': False, - 'enforce_policy': True}, - 'advertise_tenant_networks': { - 'allow_post': True, - 'allow_put': True, - 'convert_to': converters.convert_to_boolean, - 'validate': {'type:boolean': None}, - 'is_visible': True, 'default': True, - 'required_by_policy': False, - 'enforce_policy': True}, - }, - 'bgp-peers': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, 'primary_key': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': attr.NAME_MAX_LEN}, - 'is_visible': True, 'default': ''}, - 'peer_ip': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'validate': {'type:ip_address': None}, - 'is_visible': True}, - 'remote_as': {'allow_post': True, 'allow_put': False, - 'validate': {'type:range': (bgp_consts.MIN_ASNUM, - bgp_consts.MAX_ASNUM)}, - 'is_visible': True, 'default': None, - 'required_by_policy': False, - 'enforce_policy': False}, - 'auth_type': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'validate': {'type:values': - bgp_consts.SUPPORTED_AUTH_TYPES}, - 'is_visible': True}, - 'password': {'allow_post': True, 'allow_put': True, - 'required_by_policy': True, - 'validate': {'type:string_or_none': None}, - 'is_visible': False, - 'default': None}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': False, - 'validate': {'type:string': attr.TENANT_ID_MAX_LEN}, - 'is_visible': True} - } -} - - -# Dynamic Routing Exceptions -class BgpSpeakerNotFound(exceptions.NotFound): - message = _("BGP speaker %(id)s could not be found.") - - -class BgpPeerNotFound(exceptions.NotFound): - message = _("BGP peer %(id)s could not be found.") - - -class BgpPeerNotAuthenticated(exceptions.NotFound): - message = _("BGP peer %(bgp_peer_id)s not authenticated.") - - -class BgpSpeakerPeerNotAssociated(exceptions.NotFound): - message = _("BGP peer %(bgp_peer_id)s is not associated with " - "BGP speaker %(bgp_speaker_id)s.") - - -class BgpSpeakerNetworkNotAssociated(exceptions.NotFound): - message = _("Network %(network_id)s is not associated with " - "BGP speaker %(bgp_speaker_id)s.") - - -class BgpSpeakerNetworkBindingError(exceptions.Conflict): - message = _("Network %(network_id)s is already bound to BgpSpeaker " - "%(bgp_speaker_id)s.") - - -class NetworkNotBound(exceptions.NotFound): - message = _("Network %(network_id)s is not bound to a BgpSpeaker.") - - -class DuplicateBgpPeerIpException(exceptions.Conflict): - _message = _("BGP Speaker %(bgp_speaker_id)s is already configured to " - "peer with a BGP Peer at %(peer_ip)s, it cannot peer with " - "BGP Peer %(bgp_peer_id)s.") - - -class InvalidBgpPeerMd5Authentication(exceptions.BadRequest): - message = _("A password must be supplied when using auth_type md5.") - - -class NetworkNotBoundForIpVersion(NetworkNotBound): - message = _("Network %(network_id)s is not bound to a IPv%(ip_version)s " - "BgpSpeaker.") - - -class Bgp(extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - return "Neutron BGP Dynamic Routing Extension" - - @classmethod - def get_alias(cls): - return BGP_EXT_ALIAS - - @classmethod - def get_description(cls): - return("Discover and advertise routes for Neutron prefixes " - "dynamically via BGP") - - @classmethod - def get_updated(cls): - return "2014-07-01T15:37:00-00:00" - - @classmethod - def get_resources(cls): - plural_mappings = rh.build_plural_mappings( - {}, RESOURCE_ATTRIBUTE_MAP) - attr.PLURALS.update(plural_mappings) - action_map = {BGP_SPEAKER_RESOURCE_NAME: - {'add_bgp_peer': 'PUT', - 'remove_bgp_peer': 'PUT', - 'add_gateway_network': 'PUT', - 'remove_gateway_network': 'PUT', - 'get_advertised_routes': 'GET'}} - exts = rh.build_resource_info(plural_mappings, - RESOURCE_ATTRIBUTE_MAP, - BGP_EXT_ALIAS, - action_map=action_map) - - return exts - - def get_extended_resources(self, version): - if version == "2.0": - return RESOURCE_ATTRIBUTE_MAP - else: - return {} - - def update_attributes_map(self, attributes): - super(Bgp, self).update_attributes_map( - attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP) diff --git a/neutron/extensions/bgp_dragentscheduler.py b/neutron/extensions/bgp_dragentscheduler.py deleted file mode 100644 index 4eca18972bb..00000000000 --- a/neutron/extensions/bgp_dragentscheduler.py +++ /dev/null @@ -1,183 +0,0 @@ -# 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. - -import abc -import six -import webob - -from neutron_lib import exceptions -from oslo_log import log as logging - -from neutron.api import extensions -from neutron.api.v2 import base -from neutron.api.v2 import resource -from neutron.extensions import agent -from neutron.extensions import bgp as bgp_ext -from neutron._i18n import _, _LE -from neutron import manager -from neutron import wsgi - - -LOG = logging.getLogger(__name__) - -BGP_DRAGENT_SCHEDULER_EXT_ALIAS = 'bgp_dragent_scheduler' -BGP_DRINSTANCE = 'bgp-drinstance' -BGP_DRINSTANCES = BGP_DRINSTANCE + 's' -BGP_DRAGENT = 'bgp-dragent' -BGP_DRAGENTS = BGP_DRAGENT + 's' - - -class DrAgentInvalid(agent.AgentNotFound): - message = _("BgpDrAgent %(id)s is invalid or has been disabled.") - - -class DrAgentNotHostingBgpSpeaker(exceptions.NotFound): - message = _("BGP speaker %(bgp_speaker_id)s is not hosted " - "by the BgpDrAgent %(agent_id)s.") - - -class DrAgentAssociationError(exceptions.Conflict): - message = _("BgpDrAgent %(agent_id)s is already associated " - "to a BGP speaker.") - - -class BgpDrSchedulerController(wsgi.Controller): - """Schedule BgpSpeaker for a BgpDrAgent""" - def get_plugin(self): - plugin = manager.NeutronManager.get_service_plugins().get( - bgp_ext.BGP_EXT_ALIAS) - if not plugin: - LOG.error(_LE('No plugin for BGP routing registered')) - msg = _('The resource could not be found.') - raise webob.exc.HTTPNotFound(msg) - return plugin - - def index(self, request, **kwargs): - plugin = self.get_plugin() - return plugin.list_bgp_speaker_on_dragent( - request.context, kwargs['agent_id']) - - def create(self, request, body, **kwargs): - plugin = self.get_plugin() - return plugin.add_bgp_speaker_to_dragent( - request.context, - kwargs['agent_id'], - body['bgp_speaker_id']) - - def delete(self, request, id, **kwargs): - plugin = self.get_plugin() - return plugin.remove_bgp_speaker_from_dragent( - request.context, kwargs['agent_id'], id) - - -class BgpDrAgentController(wsgi.Controller): - def get_plugin(self): - plugin = manager.NeutronManager.get_service_plugins().get( - bgp_ext.BGP_EXT_ALIAS) - if not plugin: - LOG.error(_LE('No plugin for BGP routing registered')) - msg = _LE('The resource could not be found.') - raise webob.exc.HTTPNotFound(msg) - return plugin - - def index(self, request, **kwargs): - plugin = manager.NeutronManager.get_service_plugins().get( - bgp_ext.BGP_EXT_ALIAS) - return plugin.list_dragent_hosting_bgp_speaker( - request.context, kwargs['bgp_speaker_id']) - - -class Bgp_dragentscheduler(extensions.ExtensionDescriptor): - """Extension class supporting Dynamic Routing scheduler. - """ - @classmethod - def get_name(cls): - return "BGP Dynamic Routing Agent Scheduler" - - @classmethod - def get_alias(cls): - return BGP_DRAGENT_SCHEDULER_EXT_ALIAS - - @classmethod - def get_description(cls): - return "Schedules BgpSpeakers on BgpDrAgent" - - @classmethod - def get_updated(cls): - return "2015-07-30T10:00:00-00:00" - - @classmethod - def get_resources(cls): - """Returns Ext Resources.""" - exts = [] - parent = dict(member_name="agent", - collection_name="agents") - - controller = resource.Resource(BgpDrSchedulerController(), - base.FAULT_MAP) - exts.append(extensions.ResourceExtension(BGP_DRINSTANCES, - controller, parent)) - - parent = dict(member_name="bgp_speaker", - collection_name="bgp-speakers") - controller = resource.Resource(BgpDrAgentController(), - base.FAULT_MAP) - exts.append(extensions.ResourceExtension(BGP_DRAGENTS, - controller, parent)) - return exts - - def get_extended_resources(self, version): - return {} - - -@six.add_metaclass(abc.ABCMeta) -class BgpDrSchedulerPluginBase(object): - """REST API to operate BGP dynamic routing agent scheduler. - - All the methods must be executed in admin context. - """ - def get_plugin_description(self): - return "Neutron BGP dynamic routing scheduler Plugin" - - def get_plugin_type(self): - return bgp_ext.BGP_EXT_ALIAS - - @abc.abstractmethod - def add_bgp_speaker_to_dragent(self, context, agent_id, speaker_id): - pass - - @abc.abstractmethod - def remove_bgp_speaker_from_dragent(self, context, agent_id, speaker_id): - pass - - @abc.abstractmethod - def list_dragent_hosting_bgp_speaker(self, context, speaker_id): - pass - - @abc.abstractmethod - def list_bgp_speaker_on_dragent(self, context, agent_id): - pass - - @abc.abstractmethod - def get_bgp_speakers_for_agent_host(self, context, host): - pass - - @abc.abstractmethod - def get_bgp_speaker_by_speaker_id(self, context, speaker_id): - pass - - @abc.abstractmethod - def get_bgp_peer_by_peer_id(self, context, bgp_peer_id): - pass diff --git a/neutron/services/bgp/__init__.py b/neutron/services/bgp/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/services/bgp/agent/__init__.py b/neutron/services/bgp/agent/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/services/bgp/agent/bgp_dragent.py b/neutron/services/bgp/agent/bgp_dragent.py deleted file mode 100644 index 720aa2a630e..00000000000 --- a/neutron/services/bgp/agent/bgp_dragent.py +++ /dev/null @@ -1,707 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 collections - -from oslo_config import cfg -from oslo_log import log as logging -import oslo_messaging -from oslo_service import loopingcall -from oslo_service import periodic_task -from oslo_utils import importutils - -from neutron.agent import rpc as agent_rpc -from neutron.common import constants -from neutron.common import rpc as n_rpc -from neutron.common import topics -from neutron.common import utils -from neutron import context -from neutron.extensions import bgp as bgp_ext -from neutron._i18n import _, _LE, _LI, _LW -from neutron import manager -from neutron.services.bgp.common import constants as bgp_consts -from neutron.services.bgp.driver import exceptions as driver_exc - -LOG = logging.getLogger(__name__) - - -class BgpDrAgent(manager.Manager): - """BGP Dynamic Routing agent service manager. - - Note that the public methods of this class are exposed as the server side - of an rpc interface. The neutron server uses - neutron.api.rpc.agentnotifiers.bgp_dr_rpc_agent_api. - BgpDrAgentNotifyApi as the client side to execute the methods - here. For more information about changing rpc interfaces, see - doc/source/devref/rpc_api.rst. - - API version history: - 1.0 initial Version - """ - target = oslo_messaging.Target(version='1.0') - - def __init__(self, host, conf=None): - super(BgpDrAgent, self).__init__() - self.initialize_driver(conf) - self.needs_resync_reasons = collections.defaultdict(list) - self.needs_full_sync_reason = None - - self.cache = BgpSpeakerCache() - self.context = context.get_admin_context_without_session() - self.plugin_rpc = BgpDrPluginApi(bgp_consts.BGP_PLUGIN, - self.context, host) - - def initialize_driver(self, conf): - self.conf = conf or cfg.CONF.BGP - try: - self.dr_driver_cls = ( - importutils.import_object(self.conf.bgp_speaker_driver, - self.conf)) - except ImportError: - LOG.exception(_LE("Error while importing BGP speaker driver %s"), - self.conf.bgp_speaker_driver) - raise SystemExit(1) - - def _handle_driver_failure(self, bgp_speaker_id, method, driver_exec): - self.schedule_resync(reason=driver_exec, - speaker_id=bgp_speaker_id) - LOG.error(_LE('Call to driver for BGP Speaker %(bgp_speaker)s ' - '%(method)s has failed with exception ' - '%(driver_exec)s.'), - {'bgp_speaker': bgp_speaker_id, - 'method': method, - 'driver_exec': driver_exec}) - - def after_start(self): - self.run() - LOG.info(_LI("BGP Dynamic Routing agent started")) - - def run(self): - """Activate BGP Dynamic Routing agent.""" - self.sync_state(self.context) - self.periodic_resync(self.context) - - @utils.synchronized('bgp-dragent') - def sync_state(self, context, full_sync=None, bgp_speakers=None): - try: - hosted_bgp_speakers = self.plugin_rpc.get_bgp_speakers(context) - hosted_bgp_speaker_ids = [bgp_speaker['id'] - for bgp_speaker in hosted_bgp_speakers] - cached_bgp_speakers = self.cache.get_bgp_speaker_ids() - for bgp_speaker_id in cached_bgp_speakers: - if bgp_speaker_id not in hosted_bgp_speaker_ids: - self.remove_bgp_speaker_from_dragent(bgp_speaker_id) - - resync_all = not bgp_speakers or full_sync - only_bs = set() if resync_all else set(bgp_speakers) - for hosted_bgp_speaker in hosted_bgp_speakers: - hosted_bs_id = hosted_bgp_speaker['id'] - if resync_all or hosted_bs_id in only_bs: - if not self.cache.is_bgp_speaker_added(hosted_bs_id): - self.safe_configure_dragent_for_bgp_speaker( - hosted_bgp_speaker) - continue - self.sync_bgp_speaker(hosted_bgp_speaker) - resync_reason = "Periodic route cache refresh" - self.schedule_resync(speaker_id=hosted_bs_id, - reason=resync_reason) - except Exception as e: - self.schedule_full_resync(reason=e) - LOG.error(_LE('Unable to sync BGP speaker state.')) - - def sync_bgp_speaker(self, bgp_speaker): - # sync BGP Speakers - bgp_peer_ips = set( - [bgp_peer['peer_ip'] for bgp_peer in bgp_speaker['peers']]) - cached_bgp_peer_ips = set( - self.cache.get_bgp_peer_ips(bgp_speaker['id'])) - removed_bgp_peer_ips = cached_bgp_peer_ips - bgp_peer_ips - - for bgp_peer_ip in removed_bgp_peer_ips: - self.remove_bgp_peer_from_bgp_speaker(bgp_speaker['id'], - bgp_peer_ip) - if bgp_peer_ips: - self.add_bgp_peers_to_bgp_speaker(bgp_speaker) - - # sync advertise routes - cached_adv_routes = self.cache.get_adv_routes(bgp_speaker['id']) - adv_routes = bgp_speaker['advertised_routes'] - if cached_adv_routes == adv_routes: - return - - for cached_route in cached_adv_routes: - if cached_route not in adv_routes: - self.withdraw_route_via_bgp_speaker(bgp_speaker['id'], - bgp_speaker['local_as'], - cached_route) - - self.advertise_routes_via_bgp_speaker(bgp_speaker) - - @utils.exception_logger() - def _periodic_resync_helper(self, context): - """Resync the BgpDrAgent state at the configured interval.""" - if self.needs_resync_reasons or self.needs_full_sync_reason: - full_sync = self.needs_full_sync_reason - reasons = self.needs_resync_reasons - # Reset old reasons - self.needs_full_sync_reason = None - self.needs_resync_reasons = collections.defaultdict(list) - if full_sync: - LOG.debug("resync all: %(reason)s", {"reason": full_sync}) - for bgp_speaker, reason in reasons.items(): - LOG.debug("resync (%(bgp_speaker)s): %(reason)s", - {"reason": reason, "bgp_speaker": bgp_speaker}) - self.sync_state( - context, full_sync=full_sync, bgp_speakers=reasons.keys()) - - # NOTE: spacing is set 1 sec. The actual interval is controlled - # by neutron/service.py which defaults to CONF.periodic_interval - @periodic_task.periodic_task(spacing=1) - def periodic_resync(self, context): - LOG.debug("Started periodic resync.") - self._periodic_resync_helper(context) - - @utils.synchronized('bgp-dr-agent') - def bgp_speaker_create_end(self, context, payload): - """Handle bgp_speaker_create_end notification event.""" - bgp_speaker_id = payload['bgp_speaker']['id'] - LOG.debug('Received BGP speaker create notification for ' - 'speaker_id=%(speaker_id)s from the neutron server.', - {'speaker_id': bgp_speaker_id}) - self.add_bgp_speaker_helper(bgp_speaker_id) - - @utils.synchronized('bgp-dr-agent') - def bgp_speaker_remove_end(self, context, payload): - """Handle bgp_speaker_create_end notification event.""" - - bgp_speaker_id = payload['bgp_speaker']['id'] - LOG.debug('Received BGP speaker remove notification for ' - 'speaker_id=%(speaker_id)s from the neutron server.', - {'speaker_id': bgp_speaker_id}) - self.remove_bgp_speaker_from_dragent(bgp_speaker_id) - - @utils.synchronized('bgp-dr-agent') - def bgp_peer_association_end(self, context, payload): - """Handle bgp_peer_association_end notification event.""" - - bgp_peer_id = payload['bgp_peer']['peer_id'] - bgp_speaker_id = payload['bgp_peer']['speaker_id'] - LOG.debug('Received BGP peer associate notification for ' - 'speaker_id=%(speaker_id)s peer_id=%(peer_id)s ' - 'from the neutron server.', - {'speaker_id': bgp_speaker_id, - 'peer_id': bgp_peer_id}) - self.add_bgp_peer_helper(bgp_speaker_id, bgp_peer_id) - - @utils.synchronized('bgp-dr-agent') - def bgp_peer_disassociation_end(self, context, payload): - """Handle bgp_peer_disassociation_end notification event.""" - - bgp_peer_ip = payload['bgp_peer']['peer_ip'] - bgp_speaker_id = payload['bgp_peer']['speaker_id'] - LOG.debug('Received BGP peer disassociate notification for ' - 'speaker_id=%(speaker_id)s peer_ip=%(peer_ip)s ' - 'from the neutron server.', - {'speaker_id': bgp_speaker_id, - 'peer_ip': bgp_peer_ip}) - self.remove_bgp_peer_from_bgp_speaker(bgp_speaker_id, bgp_peer_ip) - - @utils.synchronized('bgp-dr-agent') - def bgp_routes_advertisement_end(self, context, payload): - """Handle bgp_routes_advertisement_end notification event.""" - - bgp_speaker_id = payload['advertise_routes']['speaker_id'] - LOG.debug('Received routes advertisement end notification ' - 'for speaker_id=%(speaker_id)s from the neutron server.', - {'speaker_id': bgp_speaker_id}) - routes = payload['advertise_routes']['routes'] - self.add_routes_helper(bgp_speaker_id, routes) - - @utils.synchronized('bgp-dr-agent') - def bgp_routes_withdrawal_end(self, context, payload): - """Handle bgp_routes_withdrawal_end notification event.""" - - bgp_speaker_id = payload['withdraw_routes']['speaker_id'] - LOG.debug('Received route withdrawal notification for ' - 'speaker_id=%(speaker_id)s from the neutron server.', - {'speaker_id': bgp_speaker_id}) - routes = payload['withdraw_routes']['routes'] - self.withdraw_routes_helper(bgp_speaker_id, routes) - - def add_bgp_speaker_helper(self, bgp_speaker_id): - """Add BGP speaker.""" - bgp_speaker = self.safe_get_bgp_speaker_info(bgp_speaker_id) - if bgp_speaker: - self.add_bgp_speaker_on_dragent(bgp_speaker) - - def add_bgp_peer_helper(self, bgp_speaker_id, bgp_peer_id): - """Add BGP peer.""" - # Ideally BGP Speaker must be added by now, If not then let's - # re-sync. - if not self.cache.is_bgp_speaker_added(bgp_speaker_id): - self.schedule_resync(speaker_id=bgp_speaker_id, - reason="BGP Speaker Out-of-sync") - return - - bgp_peer = self.safe_get_bgp_peer_info(bgp_speaker_id, - bgp_peer_id) - if bgp_peer: - bgp_speaker_as = self.cache.get_bgp_speaker_local_as( - bgp_speaker_id) - self.add_bgp_peer_to_bgp_speaker(bgp_speaker_id, - bgp_speaker_as, - bgp_peer) - - def add_routes_helper(self, bgp_speaker_id, routes): - """Advertise routes to BGP speaker.""" - # Ideally BGP Speaker must be added by now, If not then let's - # re-sync. - if not self.cache.is_bgp_speaker_added(bgp_speaker_id): - self.schedule_resync(speaker_id=bgp_speaker_id, - reason="BGP Speaker Out-of-sync") - return - - bgp_speaker_as = self.cache.get_bgp_speaker_local_as(bgp_speaker_id) - for route in routes: - self.advertise_route_via_bgp_speaker(bgp_speaker_id, - bgp_speaker_as, - route) - if self.is_resync_scheduled(bgp_speaker_id): - break - - def withdraw_routes_helper(self, bgp_speaker_id, routes): - """Withdraw routes advertised by BGP speaker.""" - # Ideally BGP Speaker must be added by now, If not then let's - # re-sync. - if not self.cache.is_bgp_speaker_added(bgp_speaker_id): - self.schedule_resync(speaker_id=bgp_speaker_id, - reason="BGP Speaker Out-of-sync") - return - - bgp_speaker_as = self.cache.get_bgp_speaker_local_as(bgp_speaker_id) - for route in routes: - self.withdraw_route_via_bgp_speaker(bgp_speaker_id, - bgp_speaker_as, - route) - if self.is_resync_scheduled(bgp_speaker_id): - break - - def safe_get_bgp_speaker_info(self, bgp_speaker_id): - try: - bgp_speaker = self.plugin_rpc.get_bgp_speaker_info(self.context, - bgp_speaker_id) - if not bgp_speaker: - LOG.warning(_LW('BGP Speaker %s has been deleted.'), - bgp_speaker_id) - return bgp_speaker - except Exception as e: - self.schedule_resync(speaker_id=bgp_speaker_id, - reason=e) - LOG.error(_LE('BGP Speaker %(bgp_speaker)s info call ' - 'failed with reason=%(e)s.'), - {'bgp_speaker': bgp_speaker_id, 'e': e}) - - def safe_get_bgp_peer_info(self, bgp_speaker_id, bgp_peer_id): - try: - bgp_peer = self.plugin_rpc.get_bgp_peer_info(self.context, - bgp_peer_id) - if not bgp_peer: - LOG.warning(_LW('BGP Peer %s has been deleted.'), bgp_peer) - return bgp_peer - except Exception as e: - self.schedule_resync(speaker_id=bgp_speaker_id, - reason=e) - LOG.error(_LE('BGP peer %(bgp_peer)s info call ' - 'failed with reason=%(e)s.'), - {'bgp_peer': bgp_peer_id, 'e': e}) - - @utils.exception_logger() - def safe_configure_dragent_for_bgp_speaker(self, bgp_speaker): - try: - self.add_bgp_speaker_on_dragent(bgp_speaker) - except (bgp_ext.BgpSpeakerNotFound, RuntimeError): - LOG.warning(_LW('BGP speaker %s may have been deleted and its ' - 'resources may have already been disposed.'), - bgp_speaker['id']) - - def add_bgp_speaker_on_dragent(self, bgp_speaker): - # Caching BGP speaker details in BGPSpeakerCache. Will be used - # during smooth. - self.cache.put_bgp_speaker(bgp_speaker) - - LOG.debug('Calling driver for adding BGP speaker %(speaker_id)s,' - ' speaking for local_as %(local_as)s', - {'speaker_id': bgp_speaker['id'], - 'local_as': bgp_speaker['local_as']}) - try: - self.dr_driver_cls.add_bgp_speaker(bgp_speaker['local_as']) - except driver_exc.BgpSpeakerAlreadyScheduled: - return - except Exception as e: - self._handle_driver_failure(bgp_speaker['id'], - 'add_bgp_speaker', e) - - # Add peer and route information to the driver. - self.add_bgp_peers_to_bgp_speaker(bgp_speaker) - self.advertise_routes_via_bgp_speaker(bgp_speaker) - self.schedule_resync(speaker_id=bgp_speaker['id'], - reason="Periodic route cache refresh") - - def remove_bgp_speaker_from_dragent(self, bgp_speaker_id): - if self.cache.is_bgp_speaker_added(bgp_speaker_id): - bgp_speaker_as = self.cache.get_bgp_speaker_local_as( - bgp_speaker_id) - self.cache.remove_bgp_speaker_by_id(bgp_speaker_id) - - LOG.debug('Calling driver for removing BGP speaker %(speaker_as)s', - {'speaker_as': bgp_speaker_as}) - try: - self.dr_driver_cls.delete_bgp_speaker(bgp_speaker_as) - except Exception as e: - self._handle_driver_failure(bgp_speaker_id, - 'remove_bgp_speaker', e) - return - - # Ideally, only the added speakers can be removed by the neutron - # server. Looks like there might be some synchronization - # issue between the server and the agent. Let's initiate a re-sync - # to resolve the issue. - self.schedule_resync(speaker_id=bgp_speaker_id, - reason="BGP Speaker Out-of-sync") - - def add_bgp_peers_to_bgp_speaker(self, bgp_speaker): - for bgp_peer in bgp_speaker['peers']: - self.add_bgp_peer_to_bgp_speaker(bgp_speaker['id'], - bgp_speaker['local_as'], - bgp_peer) - if self.is_resync_scheduled(bgp_speaker['id']): - break - - def add_bgp_peer_to_bgp_speaker(self, bgp_speaker_id, - bgp_speaker_as, bgp_peer): - if self.cache.get_bgp_peer_by_ip(bgp_speaker_id, bgp_peer['peer_ip']): - return - - self.cache.put_bgp_peer(bgp_speaker_id, bgp_peer) - - LOG.debug('Calling driver interface for adding BGP peer %(peer_ip)s ' - 'remote_as=%(remote_as)s to BGP Speaker running for ' - 'local_as=%(local_as)d', - {'peer_ip': bgp_peer['peer_ip'], - 'remote_as': bgp_peer['remote_as'], - 'local_as': bgp_speaker_as}) - try: - self.dr_driver_cls.add_bgp_peer(bgp_speaker_as, - bgp_peer['peer_ip'], - bgp_peer['remote_as'], - bgp_peer['auth_type'], - bgp_peer['password']) - except Exception as e: - self._handle_driver_failure(bgp_speaker_id, - 'add_bgp_peer', e) - - def remove_bgp_peer_from_bgp_speaker(self, bgp_speaker_id, bgp_peer_ip): - # Ideally BGP Speaker must be added by now, If not then let's - # re-sync. - if not self.cache.is_bgp_speaker_added(bgp_speaker_id): - self.schedule_resync(speaker_id=bgp_speaker_id, - reason="BGP Speaker Out-of-sync") - return - - if self.cache.is_bgp_peer_added(bgp_speaker_id, bgp_peer_ip): - self.cache.remove_bgp_peer_by_ip(bgp_speaker_id, bgp_peer_ip) - - bgp_speaker_as = self.cache.get_bgp_speaker_local_as( - bgp_speaker_id) - - LOG.debug('Calling driver interface to remove BGP peer ' - '%(peer_ip)s from BGP Speaker running for ' - 'local_as=%(local_as)d', - {'peer_ip': bgp_peer_ip, 'local_as': bgp_speaker_as}) - try: - self.dr_driver_cls.delete_bgp_peer(bgp_speaker_as, - bgp_peer_ip) - except Exception as e: - self._handle_driver_failure(bgp_speaker_id, - 'remove_bgp_peer', e) - return - - # Ideally, only the added peers can be removed by the neutron - # server. Looks like there might be some synchronization - # issue between the server and the agent. Let's initiate a re-sync - # to resolve the issue. - self.schedule_resync(speaker_id=bgp_speaker_id, - reason="BGP Peer Out-of-sync") - - def advertise_routes_via_bgp_speaker(self, bgp_speaker): - for route in bgp_speaker['advertised_routes']: - self.advertise_route_via_bgp_speaker(bgp_speaker['id'], - bgp_speaker['local_as'], - route) - if self.is_resync_scheduled(bgp_speaker['id']): - break - - def advertise_route_via_bgp_speaker(self, bgp_speaker_id, - bgp_speaker_as, route): - if self.cache.is_route_advertised(bgp_speaker_id, route): - # Requested route already advertised. Hence, Nothing to be done. - return - self.cache.put_adv_route(bgp_speaker_id, route) - - LOG.debug('Calling driver for advertising prefix: %(cidr)s, ' - 'next_hop: %(nexthop)s', - {'cidr': route['destination'], - 'nexthop': route['next_hop']}) - try: - self.dr_driver_cls.advertise_route(bgp_speaker_as, - route['destination'], - route['next_hop']) - except Exception as e: - self._handle_driver_failure(bgp_speaker_id, - 'advertise_route', e) - - def withdraw_route_via_bgp_speaker(self, bgp_speaker_id, - bgp_speaker_as, route): - if self.cache.is_route_advertised(bgp_speaker_id, route): - self.cache.remove_adv_route(bgp_speaker_id, route) - LOG.debug('Calling driver for withdrawing prefix: %(cidr)s, ' - 'next_hop: %(nexthop)s', - {'cidr': route['destination'], - 'nexthop': route['next_hop']}) - try: - self.dr_driver_cls.withdraw_route(bgp_speaker_as, - route['destination'], - route['next_hop']) - except Exception as e: - self._handle_driver_failure(bgp_speaker_id, - 'withdraw_route', e) - return - - # Ideally, only the advertised routes can be withdrawn by the - # neutron server. Looks like there might be some synchronization - # issue between the server and the agent. Let's initiate a re-sync - # to resolve the issue. - self.schedule_resync(speaker_id=bgp_speaker_id, - reason="Advertised routes Out-of-sync") - - def schedule_full_resync(self, reason): - LOG.debug('Recording full resync request for all BGP Speakers ' - 'with reason=%s', reason) - self.needs_full_sync_reason = reason - - def schedule_resync(self, reason, speaker_id): - """Schedule a full resync for a given BGP Speaker. - If no BGP Speaker is specified, resync all BGP Speakers. - """ - LOG.debug('Recording resync request for BGP Speaker %s ' - 'with reason=%s', speaker_id, reason) - self.needs_resync_reasons[speaker_id].append(reason) - - def is_resync_scheduled(self, bgp_speaker_id): - if bgp_speaker_id not in self.needs_resync_reasons: - return False - - reason = self.needs_resync_reasons[bgp_speaker_id] - # Re-sync scheduled for the queried BGP speaker. No point - # continuing further. Let's stop processing and wait for - # re-sync to happen. - LOG.debug('Re-sync already scheduled for BGP Speaker %s ' - 'with reason=%s', bgp_speaker_id, reason) - return True - - -class BgpDrPluginApi(object): - """Agent side of BgpDrAgent RPC API. - - This class implements the client side of an rpc interface. - The server side of this interface can be found in - neutron.api.rpc.handlers.bgp_speaker_rpc.BgpSpeakerRpcCallback. - For more information about changing rpc interfaces, see - doc/source/devref/rpc_api.rst. - - API version history: - 1.0 - Initial version. - """ - def __init__(self, topic, context, host): - self.context = context - self.host = host - target = oslo_messaging.Target(topic=topic, version='1.0') - self.client = n_rpc.get_client(target) - - def get_bgp_speakers(self, context): - """Make a remote process call to retrieve all BGP speakers info.""" - cctxt = self.client.prepare() - return cctxt.call(context, 'get_bgp_speakers', host=self.host) - - def get_bgp_speaker_info(self, context, bgp_speaker_id): - """Make a remote process call to retrieve a BGP speaker info.""" - cctxt = self.client.prepare() - return cctxt.call(context, 'get_bgp_speaker_info', - bgp_speaker_id=bgp_speaker_id) - - def get_bgp_peer_info(self, context, bgp_peer_id): - """Make a remote process call to retrieve a BGP peer info.""" - cctxt = self.client.prepare() - return cctxt.call(context, 'get_bgp_peer_info', - bgp_peer_id=bgp_peer_id) - - -class BgpSpeakerCache(object): - """Agent cache of the current BGP speaker state. - - This class is designed to support the advertisement for - multiple BGP speaker via a single driver interface. - - Version history: - 1.0 - Initial version for caching the state of BGP speaker. - """ - def __init__(self): - self.cache = {} - - def get_bgp_speaker_ids(self): - return self.cache.keys() - - def put_bgp_speaker(self, bgp_speaker): - if bgp_speaker['id'] in self.cache: - self.remove_bgp_speaker_by_id(self.cache[bgp_speaker['id']]) - self.cache[bgp_speaker['id']] = {'bgp_speaker': bgp_speaker, - 'peers': {}, - 'advertised_routes': []} - - def get_bgp_speaker_by_id(self, bgp_speaker_id): - if bgp_speaker_id in self.cache: - return self.cache[bgp_speaker_id]['bgp_speaker'] - - def get_bgp_speaker_local_as(self, bgp_speaker_id): - bgp_speaker = self.get_bgp_speaker_by_id(bgp_speaker_id) - if bgp_speaker: - return bgp_speaker['local_as'] - - def is_bgp_speaker_added(self, bgp_speaker_id): - return self.get_bgp_speaker_by_id(bgp_speaker_id) - - def remove_bgp_speaker_by_id(self, bgp_speaker_id): - if bgp_speaker_id in self.cache: - del self.cache[bgp_speaker_id] - - def put_bgp_peer(self, bgp_speaker_id, bgp_peer): - if bgp_peer['peer_ip'] in self.get_bgp_peer_ips(bgp_speaker_id): - del self.cache[bgp_speaker_id]['peers'][bgp_peer['peer_ip']] - - self.cache[bgp_speaker_id]['peers'][bgp_peer['peer_ip']] = bgp_peer - - def is_bgp_peer_added(self, bgp_speaker_id, bgp_peer_ip): - return self.get_bgp_peer_by_ip(bgp_speaker_id, bgp_peer_ip) - - def get_bgp_peer_ips(self, bgp_speaker_id): - bgp_speaker = self.get_bgp_speaker_by_id(bgp_speaker_id) - if bgp_speaker: - return self.cache[bgp_speaker_id]['peers'].keys() - - def get_bgp_peer_by_ip(self, bgp_speaker_id, bgp_peer_ip): - bgp_speaker = self.get_bgp_speaker_by_id(bgp_speaker_id) - if bgp_speaker: - return self.cache[bgp_speaker_id]['peers'].get(bgp_peer_ip) - - def remove_bgp_peer_by_ip(self, bgp_speaker_id, bgp_peer_ip): - if bgp_peer_ip in self.get_bgp_peer_ips(bgp_speaker_id): - del self.cache[bgp_speaker_id]['peers'][bgp_peer_ip] - - def put_adv_route(self, bgp_speaker_id, route): - self.cache[bgp_speaker_id]['advertised_routes'].append(route) - - def is_route_advertised(self, bgp_speaker_id, route): - routes = self.cache[bgp_speaker_id]['advertised_routes'] - for r in routes: - if r['destination'] == route['destination'] and ( - r['next_hop'] == route['next_hop']): - return True - return False - - def remove_adv_route(self, bgp_speaker_id, route): - routes = self.cache[bgp_speaker_id]['advertised_routes'] - updated_routes = [r for r in routes if ( - r['destination'] != route['destination'])] - self.cache[bgp_speaker_id]['advertised_routes'] = updated_routes - - def get_adv_routes(self, bgp_speaker_id): - return self.cache[bgp_speaker_id]['advertised_routes'] - - def get_state(self): - bgp_speaker_ids = self.get_bgp_speaker_ids() - num_bgp_speakers = len(bgp_speaker_ids) - num_bgp_peers = 0 - num_advertised_routes = 0 - for bgp_speaker_id in bgp_speaker_ids: - bgp_speaker = self.get_bgp_speaker_by_id(bgp_speaker_id) - num_bgp_peers += len(bgp_speaker['peers']) - num_advertised_routes += len(bgp_speaker['advertised_routes']) - return {'bgp_speakers': num_bgp_speakers, - 'bgp_peers': num_bgp_peers, - 'advertise_routes': num_advertised_routes} - - -class BgpDrAgentWithStateReport(BgpDrAgent): - def __init__(self, host, conf=None): - super(BgpDrAgentWithStateReport, - self).__init__(host, conf) - self.state_rpc = agent_rpc.PluginReportStateAPI(topics.PLUGIN) - self.agent_state = { - 'agent_type': bgp_consts.AGENT_TYPE_BGP_ROUTING, - 'binary': 'neutron-bgp-dragent', - 'configurations': {}, - 'host': host, - 'topic': bgp_consts.BGP_DRAGENT, - 'start_flag': True} - report_interval = cfg.CONF.AGENT.report_interval - if report_interval: - self.heartbeat = loopingcall.FixedIntervalLoopingCall( - self._report_state) - self.heartbeat.start(interval=report_interval) - - def _report_state(self): - LOG.debug("Report state task started") - try: - self.agent_state.get('configurations').update( - self.cache.get_state()) - ctx = context.get_admin_context_without_session() - agent_status = self.state_rpc.report_state(ctx, self.agent_state, - True) - if agent_status == constants.AGENT_REVIVED: - LOG.info(_LI("Agent has just been revived. " - "Scheduling full sync")) - self.schedule_full_resync( - reason=_("Agent has just been revived")) - except AttributeError: - # This means the server does not support report_state - LOG.warning(_LW("Neutron server does not support state report. " - "State report for this agent will be disabled.")) - self.heartbeat.stop() - self.run() - return - except Exception: - LOG.exception(_LE("Failed reporting state!")) - return - if self.agent_state.pop('start_flag', None): - self.run() - - def agent_updated(self, context, payload): - """Handle the agent_updated notification event.""" - self.schedule_full_resync( - reason=_("BgpDrAgent updated: %s") % payload) - LOG.info(_LI("agent_updated by server side %s!"), payload) - - def after_start(self): - LOG.info(_LI("BGP dynamic routing agent started")) diff --git a/neutron/services/bgp/agent/config.py b/neutron/services/bgp/agent/config.py deleted file mode 100644 index 4256b6477a3..00000000000 --- a/neutron/services/bgp/agent/config.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 neutron._i18n import _ - -BGP_DRIVER_OPTS = [ - cfg.StrOpt('bgp_speaker_driver', - help=_("BGP speaker driver class to be instantiated.")) -] - -BGP_PROTO_CONFIG_OPTS = [ - cfg.StrOpt('bgp_router_id', - help=_("32-bit BGP identifier, typically an IPv4 address " - "owned by the system running the BGP DrAgent.")) -] diff --git a/neutron/services/bgp/agent/entry.py b/neutron/services/bgp/agent/entry.py deleted file mode 100644 index 4e228240f6f..00000000000 --- a/neutron/services/bgp/agent/entry.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 sys - -from oslo_config import cfg -from oslo_service import service - -from neutron.agent.common import config -from neutron.agent.linux import external_process -from neutron.common import config as common_config -from neutron import service as neutron_service -from neutron.services.bgp.agent import config as bgp_dragent_config -from neutron.services.bgp.common import constants as bgp_consts - - -def register_options(): - config.register_agent_state_opts_helper(cfg.CONF) - config.register_root_helper(cfg.CONF) - cfg.CONF.register_opts(bgp_dragent_config.BGP_DRIVER_OPTS, 'BGP') - cfg.CONF.register_opts(bgp_dragent_config.BGP_PROTO_CONFIG_OPTS, 'BGP') - cfg.CONF.register_opts(external_process.OPTS) - - -def main(): - register_options() - common_config.init(sys.argv[1:]) - config.setup_logging() - server = neutron_service.Service.create( - binary='neutron-bgp-dragent', - topic=bgp_consts.BGP_DRAGENT, - report_interval=cfg.CONF.AGENT.report_interval, - manager='neutron.services.bgp.agent.bgp_dragent.' - 'BgpDrAgentWithStateReport') - service.launch(cfg.CONF, server).wait() diff --git a/neutron/services/bgp/bgp_plugin.py b/neutron/services/bgp/bgp_plugin.py deleted file mode 100644 index 9d6bc8b0254..00000000000 --- a/neutron/services/bgp/bgp_plugin.py +++ /dev/null @@ -1,289 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development Company LP -# -# 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 netaddr import IPAddress -from neutron_lib import constants as n_const -from oslo_config import cfg -from oslo_log import log as logging -from oslo_utils import importutils - -from neutron.api.rpc.agentnotifiers import bgp_dr_rpc_agent_api -from neutron.api.rpc.handlers import bgp_speaker_rpc as bs_rpc -from neutron.callbacks import events -from neutron.callbacks import registry -from neutron.callbacks import resources -from neutron.common import rpc as n_rpc -from neutron import context -from neutron.db import bgp_db -from neutron.db import bgp_dragentscheduler_db -from neutron.extensions import bgp as bgp_ext -from neutron.extensions import bgp_dragentscheduler as dras_ext -from neutron.services.bgp.common import constants as bgp_consts -from neutron.services import service_base - -PLUGIN_NAME = bgp_ext.BGP_EXT_ALIAS + '_svc_plugin' -LOG = logging.getLogger(__name__) - - -class BgpPlugin(service_base.ServicePluginBase, - bgp_db.BgpDbMixin, - bgp_dragentscheduler_db.BgpDrAgentSchedulerDbMixin): - - supported_extension_aliases = [bgp_ext.BGP_EXT_ALIAS, - dras_ext.BGP_DRAGENT_SCHEDULER_EXT_ALIAS] - - def __init__(self): - super(BgpPlugin, self).__init__() - self.bgp_drscheduler = importutils.import_object( - cfg.CONF.bgp_drscheduler_driver) - self._setup_rpc() - self._register_callbacks() - - def get_plugin_name(self): - return PLUGIN_NAME - - def get_plugin_type(self): - return bgp_ext.BGP_EXT_ALIAS - - def get_plugin_description(self): - """returns string description of the plugin.""" - return ("BGP dynamic routing service for announcement of next-hops " - "for tenant networks, floating IP's, and DVR host routes.") - - def _setup_rpc(self): - self.topic = bgp_consts.BGP_PLUGIN - self.conn = n_rpc.create_connection() - self.agent_notifiers[bgp_consts.AGENT_TYPE_BGP_ROUTING] = ( - bgp_dr_rpc_agent_api.BgpDrAgentNotifyApi() - ) - self._bgp_rpc = self.agent_notifiers[bgp_consts.AGENT_TYPE_BGP_ROUTING] - self.endpoints = [bs_rpc.BgpSpeakerRpcCallback()] - self.conn.create_consumer(self.topic, self.endpoints, - fanout=False) - self.conn.consume_in_threads() - - def _register_callbacks(self): - registry.subscribe(self.floatingip_update_callback, - resources.FLOATING_IP, - events.AFTER_UPDATE) - registry.subscribe(self.router_interface_callback, - resources.ROUTER_INTERFACE, - events.AFTER_CREATE) - registry.subscribe(self.router_interface_callback, - resources.ROUTER_INTERFACE, - events.BEFORE_CREATE) - registry.subscribe(self.router_interface_callback, - resources.ROUTER_INTERFACE, - events.AFTER_DELETE) - registry.subscribe(self.router_gateway_callback, - resources.ROUTER_GATEWAY, - events.AFTER_CREATE) - registry.subscribe(self.router_gateway_callback, - resources.ROUTER_GATEWAY, - events.AFTER_DELETE) - - def create_bgp_speaker(self, context, bgp_speaker): - bgp_speaker = super(BgpPlugin, self).create_bgp_speaker(context, - bgp_speaker) - return bgp_speaker - - def delete_bgp_speaker(self, context, bgp_speaker_id): - hosted_bgp_dragents = self.get_dragents_hosting_bgp_speakers( - context, - [bgp_speaker_id]) - super(BgpPlugin, self).delete_bgp_speaker(context, bgp_speaker_id) - for agent in hosted_bgp_dragents: - self._bgp_rpc.bgp_speaker_removed(context, - bgp_speaker_id, - agent.host) - - def add_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info): - ret_value = super(BgpPlugin, self).add_bgp_peer(context, - bgp_speaker_id, - bgp_peer_info) - hosted_bgp_dragents = self.get_dragents_hosting_bgp_speakers( - context, - [bgp_speaker_id]) - for agent in hosted_bgp_dragents: - self._bgp_rpc.bgp_peer_associated(context, bgp_speaker_id, - ret_value['bgp_peer_id'], - agent.host) - return ret_value - - def remove_bgp_peer(self, context, bgp_speaker_id, bgp_peer_info): - hosted_bgp_dragents = self.get_dragents_hosting_bgp_speakers( - context, [bgp_speaker_id]) - - ret_value = super(BgpPlugin, self).remove_bgp_peer(context, - bgp_speaker_id, - bgp_peer_info) - - for agent in hosted_bgp_dragents: - self._bgp_rpc.bgp_peer_disassociated(context, - bgp_speaker_id, - ret_value['bgp_peer_id'], - agent.host) - - def floatingip_update_callback(self, resource, event, trigger, **kwargs): - if event != events.AFTER_UPDATE: - return - - ctx = context.get_admin_context() - new_router_id = kwargs['router_id'] - last_router_id = kwargs['last_known_router_id'] - next_hop = kwargs['next_hop'] - dest = kwargs['floating_ip_address'] + '/32' - bgp_speakers = self._bgp_speakers_for_gw_network_by_family( - ctx, - kwargs['floating_network_id'], - n_const.IP_VERSION_4) - - if last_router_id and new_router_id != last_router_id: - for bgp_speaker in bgp_speakers: - self.stop_route_advertisements(ctx, self._bgp_rpc, - bgp_speaker.id, [dest]) - - if next_hop and new_router_id != last_router_id: - new_host_route = {'destination': dest, 'next_hop': next_hop} - for bgp_speaker in bgp_speakers: - self.start_route_advertisements(ctx, self._bgp_rpc, - bgp_speaker.id, - [new_host_route]) - - def router_interface_callback(self, resource, event, trigger, **kwargs): - if event == events.AFTER_CREATE: - self._handle_router_interface_after_create(**kwargs) - if event == events.AFTER_DELETE: - gw_network = kwargs['network_id'] - next_hops = self._next_hops_from_gateway_ips( - kwargs['gateway_ips']) - ctx = context.get_admin_context() - speakers = self._bgp_speakers_for_gateway_network(ctx, gw_network) - for speaker in speakers: - routes = self._route_list_from_prefixes_and_next_hop( - kwargs['cidrs'], - next_hops[speaker.ip_version]) - self._handle_router_interface_after_delete(gw_network, routes) - - def _handle_router_interface_after_create(self, **kwargs): - gw_network = kwargs['network_id'] - if not gw_network: - return - - ctx = context.get_admin_context() - with ctx.session.begin(subtransactions=True): - speakers = self._bgp_speakers_for_gateway_network(ctx, - gw_network) - next_hops = self._next_hops_from_gateway_ips( - kwargs['gateway_ips']) - - for speaker in speakers: - prefixes = self._tenant_prefixes_by_router( - ctx, - kwargs['router_id'], - speaker.id) - next_hop = next_hops.get(speaker.ip_version) - if next_hop: - rl = self._route_list_from_prefixes_and_next_hop(prefixes, - next_hop) - self.start_route_advertisements(ctx, - self._bgp_rpc, - speaker.id, - rl) - - def router_gateway_callback(self, resource, event, trigger, **kwargs): - if event == events.AFTER_CREATE: - self._handle_router_gateway_after_create(**kwargs) - if event == events.AFTER_DELETE: - gw_network = kwargs['network_id'] - router_id = kwargs['router_id'] - next_hops = self._next_hops_from_gateway_ips( - kwargs['gateway_ips']) - ctx = context.get_admin_context() - speakers = self._bgp_speakers_for_gateway_network(ctx, gw_network) - for speaker in speakers: - if speaker.ip_version in next_hops: - next_hop = next_hops[speaker.ip_version] - prefixes = self._tenant_prefixes_by_router(ctx, - router_id, - speaker.id) - routes = self._route_list_from_prefixes_and_next_hop( - prefixes, - next_hop) - self._handle_router_interface_after_delete(gw_network, routes) - - def _handle_router_gateway_after_create(self, **kwargs): - ctx = context.get_admin_context() - gw_network = kwargs['network_id'] - router_id = kwargs['router_id'] - with ctx.session.begin(subtransactions=True): - speakers = self._bgp_speakers_for_gateway_network(ctx, - gw_network) - next_hops = self._next_hops_from_gateway_ips(kwargs['gw_ips']) - - for speaker in speakers: - if speaker.ip_version in next_hops: - next_hop = next_hops[speaker.ip_version] - prefixes = self._tenant_prefixes_by_router(ctx, - router_id, - speaker.id) - routes = self._route_list_from_prefixes_and_next_hop( - prefixes, - next_hop) - self.start_route_advertisements(ctx, self._bgp_rpc, - speaker.id, routes) - - def _handle_router_interface_after_delete(self, gw_network, routes): - if gw_network and routes: - ctx = context.get_admin_context() - speakers = self._bgp_speakers_for_gateway_network(ctx, gw_network) - for speaker in speakers: - self.stop_route_advertisements(ctx, self._bgp_rpc, - speaker.id, routes) - - def _next_hops_from_gateway_ips(self, gw_ips): - if gw_ips: - return {IPAddress(ip).version: ip for ip in gw_ips} - return {} - - def start_route_advertisements(self, ctx, bgp_rpc, - bgp_speaker_id, routes): - agents = self.list_dragent_hosting_bgp_speaker(ctx, bgp_speaker_id) - for agent in agents['agents']: - bgp_rpc.bgp_routes_advertisement(ctx, - bgp_speaker_id, - routes, - agent['host']) - - msg = "Starting route advertisements for %s on BgpSpeaker %s" - self._debug_log_for_routes(msg, routes, bgp_speaker_id) - - def stop_route_advertisements(self, ctx, bgp_rpc, - bgp_speaker_id, routes): - agents = self.list_dragent_hosting_bgp_speaker(ctx, bgp_speaker_id) - for agent in agents['agents']: - bgp_rpc.bgp_routes_withdrawal(ctx, - bgp_speaker_id, - routes, - agent['host']) - - msg = "Stopping route advertisements for %s on BgpSpeaker %s" - self._debug_log_for_routes(msg, routes, bgp_speaker_id) - - def _debug_log_for_routes(self, msg, routes, bgp_speaker_id): - - # Could have a large number of routes passed, check log level first - if LOG.isEnabledFor(logging.DEBUG): - for route in routes: - LOG.debug(msg, route, bgp_speaker_id) diff --git a/neutron/services/bgp/common/__init__.py b/neutron/services/bgp/common/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/services/bgp/common/constants.py b/neutron/services/bgp/common/constants.py deleted file mode 100644 index 42c47bd0ef5..00000000000 --- a/neutron/services/bgp/common/constants.py +++ /dev/null @@ -1,27 +0,0 @@ -# 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. - -AGENT_TYPE_BGP_ROUTING = 'BGP dynamic routing agent' - -BGP_DRAGENT = 'bgp_dragent' - -BGP_PLUGIN = 'q-bgp-plugin' - -# List of supported authentication types. -SUPPORTED_AUTH_TYPES = ['none', 'md5'] - -# Supported AS number range -MIN_ASNUM = 1 -MAX_ASNUM = 65535 diff --git a/neutron/services/bgp/common/opts.py b/neutron/services/bgp/common/opts.py deleted file mode 100644 index af9e986cfd2..00000000000 --- a/neutron/services/bgp/common/opts.py +++ /dev/null @@ -1,28 +0,0 @@ -# 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. - -import itertools - -import neutron.services.bgp.agent.config - - -def list_bgp_agent_opts(): - return [ - ('BGP', - itertools.chain( - neutron.services.bgp.agent.config.BGP_DRIVER_OPTS, - neutron.services.bgp.agent.config.BGP_PROTO_CONFIG_OPTS) - ) - ] diff --git a/neutron/services/bgp/driver/__init__.py b/neutron/services/bgp/driver/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/services/bgp/driver/base.py b/neutron/services/bgp/driver/base.py deleted file mode 100644 index 128651b7dcc..00000000000 --- a/neutron/services/bgp/driver/base.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 abc -import six - - -@six.add_metaclass(abc.ABCMeta) -class BgpDriverBase(object): - """Base class for BGP Speaking drivers. - - Any class which provides BGP functionality should extend this - defined base class. - """ - - @abc.abstractmethod - def add_bgp_speaker(self, speaker_as): - """Add a BGP speaker. - - :param speaker_as: Specifies BGP Speaker autonomous system number. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type speaker_as: integer - :raises: BgpSpeakerAlreadyScheduled, BgpSpeakerMaxScheduled, - InvalidParamType, InvalidParamRange - """ - - @abc.abstractmethod - def delete_bgp_speaker(self, speaker_as): - """Deletes BGP speaker. - - :param speaker_as: Specifies BGP Speaker autonomous system number. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type speaker_as: integer - :raises: BgpSpeakerNotAdded - """ - - @abc.abstractmethod - def add_bgp_peer(self, speaker_as, peer_ip, peer_as, - auth_type='none', password=None): - """Add a new BGP peer. - - :param speaker_as: Specifies BGP Speaker autonomous system number. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type speaker_as: integer - :param peer_ip: Specifies the IP address of the peer. - :type peer_ip: string - :param peer_as: Specifies Autonomous Number of the peer. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type peer_as: integer - :param auth_type: Specifies authentication type. - By default, authentication will be disabled. - :type auth_type: value in SUPPORTED_AUTH_TYPES - :param password: Authentication password.By default, authentication - will be disabled. - :type password: string - :raises: BgpSpeakerNotAdded, InvalidParamType, InvalidParamRange, - InvaildAuthType, PasswordNotSpecified - """ - - @abc.abstractmethod - def delete_bgp_peer(self, speaker_as, peer_ip): - """Delete a BGP peer associated with the given peer IP - - :param speaker_as: Specifies BGP Speaker autonomous system number. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type speaker_as: integer - :param peer_ip: Specifies the IP address of the peer. Must be the - string representation of an IP address. - :type peer_ip: string - :raises: BgpSpeakerNotAdded, BgpPeerNotAdded - """ - - @abc.abstractmethod - def advertise_route(self, speaker_as, cidr, nexthop): - """Add a new prefix to advertise. - - :param speaker_as: Specifies BGP Speaker autonomous system number. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type speaker_as: integer - :param cidr: CIDR of the network to advertise. Must be the string - representation of an IP network (e.g., 10.1.1.0/24) - :type cidr: string - :param nexthop: Specifies the next hop address for the above - prefix. - :type nexthop: string - :raises: BgpSpeakerNotAdded, InvalidParamType - """ - - @abc.abstractmethod - def withdraw_route(self, speaker_as, cidr, nexthop=None): - """Withdraw an advertised prefix. - - :param speaker_as: Specifies BGP Speaker autonomous system number. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type speaker_as: integer - :param cidr: CIDR of the network to withdraw. Must be the string - representation of an IP network (e.g., 10.1.1.0/24) - :type cidr: string - :param nexthop: Specifies the next hop address for the above - prefix. - :type nexthop: string - :raises: BgpSpeakerNotAdded, RouteNotAdvertised, InvalidParamType - """ - - @abc.abstractmethod - def get_bgp_speaker_statistics(self, speaker_as): - """Collect BGP Speaker statistics. - - :param speaker_as: Specifies BGP Speaker autonomous system number. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type speaker_as: integer - :raises: BgpSpeakerNotAdded - :returns: bgp_speaker_stats: string - """ - - @abc.abstractmethod - def get_bgp_peer_statistics(self, speaker_as, peer_ip, peer_as): - """Collect BGP Peer statistics. - - :param speaker_as: Specifies BGP Speaker autonomous system number. - Must be an integer between MIN_ASNUM and MAX_ASNUM. - :type speaker_as: integer - :param peer_ip: Specifies the IP address of the peer. - :type peer_ip: string - :param peer_as: Specifies the AS number of the peer. Must be an - integer between MIN_ASNUM and MAX_ASNUM. - :type peer_as: integer . - :raises: BgpSpeakerNotAdded, BgpPeerNotAdded - :returns: bgp_peer_stats: string - """ diff --git a/neutron/services/bgp/driver/exceptions.py b/neutron/services/bgp/driver/exceptions.py deleted file mode 100644 index d8e746c2a5d..00000000000 --- a/neutron/services/bgp/driver/exceptions.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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_lib import exceptions as n_exc - -from neutron._i18n import _ - - -# BGP Driver Exceptions -class BgpSpeakerNotAdded(n_exc.BadRequest): - message = _("BGP Speaker for local_as=%(local_as)s with " - "router_id=%(rtid)s not added yet.") - - -class BgpSpeakerMaxScheduled(n_exc.BadRequest): - message = _("Already hosting maximum number of BGP Speakers. " - "Allowed scheduled count=%(count)d") - - -class BgpSpeakerAlreadyScheduled(n_exc.Conflict): - message = _("Already hosting BGP Speaker for local_as=%(current_as)d with " - "router_id=%(rtid)s.") - - -class BgpPeerNotAdded(n_exc.BadRequest): - message = _("BGP Peer %(peer_ip)s for remote_as=%(remote_as)s, running " - "for BGP Speaker %(speaker_as)d not added yet.") - - -class RouteNotAdvertised(n_exc.BadRequest): - message = _("Route %(cidr)s not advertised for BGP Speaker " - "%(speaker_as)d.") - - -class InvalidParamType(n_exc.NeutronException): - message = _("Parameter %(param)s must be of %(param_type)s type.") - - -class InvalidParamRange(n_exc.NeutronException): - message = _("%(param)s must be in %(range)s range.") - - -class InvaildAuthType(n_exc.BadRequest): - message = _("Authentication type not supported. Requested " - "type=%(auth_type)s.") - - -class PasswordNotSpecified(n_exc.BadRequest): - message = _("Password not specified for authentication " - "type=%(auth_type)s.") diff --git a/neutron/services/bgp/driver/ryu/__init__.py b/neutron/services/bgp/driver/ryu/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/services/bgp/driver/ryu/driver.py b/neutron/services/bgp/driver/ryu/driver.py deleted file mode 100644 index 3825cc2f9c4..00000000000 --- a/neutron/services/bgp/driver/ryu/driver.py +++ /dev/null @@ -1,202 +0,0 @@ -# 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_log import log as logging -from ryu.services.protocols.bgp import bgpspeaker -from ryu.services.protocols.bgp.rtconf.neighbors import CONNECT_MODE_ACTIVE - -from neutron.services.bgp.driver import base -from neutron.services.bgp.driver import exceptions as bgp_driver_exc -from neutron.services.bgp.driver import utils -from neutron._i18n import _LE, _LI - -LOG = logging.getLogger(__name__) - - -# Function for logging BGP peer and path changes. -def bgp_peer_down_cb(remote_ip, remote_as): - LOG.info(_LI('BGP Peer %(peer_ip)s for remote_as=%(peer_as)d went DOWN.'), - {'peer_ip': remote_ip, 'peer_as': remote_as}) - - -def bgp_peer_up_cb(remote_ip, remote_as): - LOG.info(_LI('BGP Peer %(peer_ip)s for remote_as=%(peer_as)d is UP.'), - {'peer_ip': remote_ip, 'peer_as': remote_as}) - - -def best_path_change_cb(event): - LOG.info(_LI("Best path change observed. cidr=%(prefix)s, " - "nexthop=%(nexthop)s, remote_as=%(remote_as)d, " - "is_withdraw=%(is_withdraw)s"), - {'prefix': event.prefix, 'nexthop': event.nexthop, - 'remote_as': event.remote_as, - 'is_withdraw': event.is_withdraw}) - - -class RyuBgpDriver(base.BgpDriverBase): - """BGP speaker implementation via Ryu.""" - - def __init__(self, cfg): - LOG.info(_LI('Initializing Ryu driver for BGP Speaker functionality.')) - self._read_config(cfg) - - # Note: Even though Ryu can only support one BGP speaker as of now, - # we have tried making the framework generic for the future purposes. - self.cache = utils.BgpMultiSpeakerCache() - - def _read_config(self, cfg): - if cfg is None or cfg.bgp_router_id is None: - # If either cfg or router_id is not specified, raise voice - LOG.error(_LE('BGP router-id MUST be specified for the correct ' - 'functional working.')) - else: - self.routerid = cfg.bgp_router_id - LOG.info(_LI('Initialized Ryu BGP Speaker driver interface with ' - 'bgp_router_id=%s'), self.routerid) - - def add_bgp_speaker(self, speaker_as): - curr_speaker = self.cache.get_bgp_speaker(speaker_as) - if curr_speaker is not None: - raise bgp_driver_exc.BgpSpeakerAlreadyScheduled( - current_as=speaker_as, - rtid=self.routerid) - - # Ryu can only support One speaker - if self.cache.get_hosted_bgp_speakers_count() == 1: - raise bgp_driver_exc.BgpSpeakerMaxScheduled(count=1) - - # Validate input parameters. - # speaker_as must be an integer in the allowed range. - utils.validate_as_num('local_as', speaker_as) - - # Notify Ryu about BGP Speaker addition. - # Please note: Since, only the route-advertisement support is - # implemented we are explicitly setting the bgp_server_port - # attribute to 0 which disables listening on port 179. - curr_speaker = bgpspeaker.BGPSpeaker(as_number=speaker_as, - router_id=self.routerid, bgp_server_port=0, - best_path_change_handler=best_path_change_cb, - peer_down_handler=bgp_peer_down_cb, - peer_up_handler=bgp_peer_up_cb) - LOG.info(_LI('Added BGP Speaker for local_as=%(as)d with ' - 'router_id= %(rtid)s.'), - {'as': speaker_as, 'rtid': self.routerid}) - - self.cache.put_bgp_speaker(speaker_as, curr_speaker) - - def delete_bgp_speaker(self, speaker_as): - curr_speaker = self.cache.get_bgp_speaker(speaker_as) - if not curr_speaker: - raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as, - rtid=self.routerid) - # Notify Ryu about BGP Speaker deletion - curr_speaker.shutdown() - LOG.info(_LI('Removed BGP Speaker for local_as=%(as)d with ' - 'router_id=%(rtid)s.'), - {'as': speaker_as, 'rtid': self.routerid}) - self.cache.remove_bgp_speaker(speaker_as) - - def add_bgp_peer(self, speaker_as, peer_ip, peer_as, - auth_type='none', password=None): - curr_speaker = self.cache.get_bgp_speaker(speaker_as) - if not curr_speaker: - raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as, - rtid=self.routerid) - - # Validate peer_ip and peer_as. - utils.validate_as_num('remote_as', peer_as) - utils.validate_string(peer_ip) - utils.validate_auth(auth_type, password) - - # Notify Ryu about BGP Peer addition - curr_speaker.neighbor_add(address=peer_ip, - remote_as=peer_as, - password=password, - connect_mode=CONNECT_MODE_ACTIVE) - LOG.info(_LI('Added BGP Peer %(peer)s for remote_as=%(as)d to ' - 'BGP Speaker running for local_as=%(local_as)d.'), - {'peer': peer_ip, 'as': peer_as, 'local_as': speaker_as}) - - def delete_bgp_peer(self, speaker_as, peer_ip): - curr_speaker = self.cache.get_bgp_speaker(speaker_as) - if not curr_speaker: - raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as, - rtid=self.routerid) - # Validate peer_ip. It must be a string. - utils.validate_string(peer_ip) - - # Notify Ryu about BGP Peer removal - curr_speaker.neighbor_del(address=peer_ip) - LOG.info(_LI('Removed BGP Peer %(peer)s from BGP Speaker ' - 'running for local_as=%(local_as)d.'), - {'peer': peer_ip, 'local_as': speaker_as}) - - def advertise_route(self, speaker_as, cidr, nexthop): - curr_speaker = self.cache.get_bgp_speaker(speaker_as) - if not curr_speaker: - raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as, - rtid=self.routerid) - - # Validate cidr and nexthop. Both must be strings. - utils.validate_string(cidr) - utils.validate_string(nexthop) - - # Notify Ryu about route advertisement - curr_speaker.prefix_add(prefix=cidr, next_hop=nexthop) - LOG.info(_LI('Route cidr=%(prefix)s, nexthop=%(nexthop)s is ' - 'advertised for BGP Speaker running for ' - 'local_as=%(local_as)d.'), - {'prefix': cidr, 'nexthop': nexthop, 'local_as': speaker_as}) - - def withdraw_route(self, speaker_as, cidr, nexthop=None): - curr_speaker = self.cache.get_bgp_speaker(speaker_as) - if not curr_speaker: - raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as, - rtid=self.routerid) - # Validate cidr. It must be a string. - utils.validate_string(cidr) - - # Notify Ryu about route withdrawal - curr_speaker.prefix_del(prefix=cidr) - LOG.info(_LI('Route cidr=%(prefix)s is withdrawn from BGP Speaker ' - 'running for local_as=%(local_as)d.'), - {'prefix': cidr, 'local_as': speaker_as}) - - def get_bgp_speaker_statistics(self, speaker_as): - LOG.info(_LI('Collecting BGP Speaker statistics for local_as=%d.'), - speaker_as) - curr_speaker = self.cache.get_bgp_speaker(speaker_as) - if not curr_speaker: - raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as, - rtid=self.routerid) - - # TODO(vikram): Filter and return the necessary information. - # Will be done as part of new RFE requirement - # https://bugs.launchpad.net/neutron/+bug/1527993 - return curr_speaker.neighbor_state_get() - - def get_bgp_peer_statistics(self, speaker_as, peer_ip): - LOG.info(_LI('Collecting BGP Peer statistics for peer_ip=%(peer)s, ' - 'running in speaker_as=%(speaker_as)d '), - {'peer': peer_ip, 'speaker_as': speaker_as}) - curr_speaker = self.cache.get_bgp_speaker(speaker_as) - if not curr_speaker: - raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as, - rtid=self.routerid) - - # TODO(vikram): Filter and return the necessary information. - # Will be done as part of new RFE requirement - # https://bugs.launchpad.net/neutron/+bug/1527993 - return curr_speaker.neighbor_state_get(address=peer_ip) diff --git a/neutron/services/bgp/driver/utils.py b/neutron/services/bgp/driver/utils.py deleted file mode 100644 index c09e6daf79d..00000000000 --- a/neutron/services/bgp/driver/utils.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 six - -from neutron.services.bgp.common import constants as bgp_consts -from neutron.services.bgp.driver import exceptions as bgp_driver_exc - - -# Parameter validation functions provided are provided by the base. -def validate_as_num(param, as_num): - if not isinstance(as_num, six.integer_types): - raise bgp_driver_exc.InvalidParamType(param=param, - param_type='integer') - - if not (bgp_consts.MIN_ASNUM <= as_num <= bgp_consts.MAX_ASNUM): - # Must be in [AS_NUM_MIN, AS_NUM_MAX] range. - allowed_range = ('[' + - str(bgp_consts.MIN_ASNUM) + '-' + - str(bgp_consts.MAX_ASNUM) + - ']') - raise bgp_driver_exc.InvalidParamRange(param=param, - range=allowed_range) - - -def validate_auth(auth_type, password): - validate_string(password) - if auth_type in bgp_consts.SUPPORTED_AUTH_TYPES: - if auth_type != 'none' and password is None: - raise bgp_driver_exc.PasswordNotSpecified(auth_type=auth_type) - if auth_type == 'none' and password is not None: - raise bgp_driver_exc.InvaildAuthType(auth_type=auth_type) - else: - raise bgp_driver_exc.InvaildAuthType(auth_type=auth_type) - - -def validate_string(param): - if param is not None: - if not isinstance(param, six.string_types): - raise bgp_driver_exc.InvalidParamType(param=param, - param_type='string') - - -class BgpMultiSpeakerCache(object): - """Class for saving multiple BGP speakers information. - - Version history: - 1.0 - Initial version for caching multiple BGP speaker information. - """ - def __init__(self): - self.cache = {} - - def get_hosted_bgp_speakers_count(self): - return len(self.cache) - - def put_bgp_speaker(self, local_as, speaker): - self.cache[local_as] = speaker - - def get_bgp_speaker(self, local_as): - return self.cache.get(local_as) - - def remove_bgp_speaker(self, local_as): - self.cache.pop(local_as, None) diff --git a/neutron/services/bgp/scheduler/__init__.py b/neutron/services/bgp/scheduler/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/services/bgp/scheduler/bgp_dragent_scheduler.py b/neutron/services/bgp/scheduler/bgp_dragent_scheduler.py deleted file mode 100644 index fa27609b72c..00000000000 --- a/neutron/services/bgp/scheduler/bgp_dragent_scheduler.py +++ /dev/null @@ -1,191 +0,0 @@ -# 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_db import exception as db_exc -from oslo_log import log as logging -from sqlalchemy.orm import exc -from sqlalchemy import sql - -from neutron.db import agents_db -from neutron.db import bgp_db -from neutron.db import bgp_dragentscheduler_db as bgp_dras_db -from neutron._i18n import _LI, _LW -from neutron.scheduler import base_resource_filter -from neutron.scheduler import base_scheduler -from neutron.services.bgp.common import constants as bgp_consts - -LOG = logging.getLogger(__name__) -BGP_SPEAKER_PER_DRAGENT = 1 - - -class BgpDrAgentFilter(base_resource_filter.BaseResourceFilter): - - def bind(self, context, agents, bgp_speaker_id): - """Bind the BgpSpeaker to a BgpDrAgent.""" - bound_agents = agents[:] - for agent in agents: - # saving agent_id to use it after rollback to avoid - # DetachedInstanceError - agent_id = agent.id - binding = bgp_dras_db.BgpSpeakerDrAgentBinding() - binding.agent_id = agent_id - binding.bgp_speaker_id = bgp_speaker_id - try: - with context.session.begin(subtransactions=True): - context.session.add(binding) - except db_exc.DBDuplicateEntry: - # it's totally ok, someone just did our job! - bound_agents.remove(agent) - LOG.info(_LI('BgpDrAgent %s already present'), agent_id) - LOG.debug('BgpSpeaker %(bgp_speaker_id)s is scheduled to be ' - 'hosted by BgpDrAgent %(agent_id)s', - {'bgp_speaker_id': bgp_speaker_id, - 'agent_id': agent_id}) - super(BgpDrAgentFilter, self).bind(context, bound_agents, - bgp_speaker_id) - - def filter_agents(self, plugin, context, bgp_speaker): - """Return the agents that can host the BgpSpeaker.""" - agents_dict = self._get_bgp_speaker_hostable_dragents( - plugin, context, bgp_speaker) - if not agents_dict['hostable_agents'] or agents_dict['n_agents'] <= 0: - return {'n_agents': 0, - 'hostable_agents': [], - 'hosted_agents': []} - return agents_dict - - def _get_active_dragents(self, plugin, context): - """Return a list of active BgpDrAgents.""" - with context.session.begin(subtransactions=True): - active_dragents = plugin.get_agents_db( - context, filters={ - 'agent_type': [bgp_consts.AGENT_TYPE_BGP_ROUTING], - 'admin_state_up': [True]}) - if not active_dragents: - return [] - return active_dragents - - def _get_num_dragents_hosting_bgp_speaker(self, bgp_speaker_id, - dragent_bindings): - return sum(1 if dragent_binding.bgp_speaker_id == bgp_speaker_id else 0 - for dragent_binding in dragent_bindings) - - def _get_bgp_speaker_hostable_dragents(self, plugin, context, bgp_speaker): - """Return number of additional BgpDrAgents which will actually host - the given BgpSpeaker and a list of BgpDrAgents which can host the - given BgpSpeaker - """ - # only one BgpSpeaker can be hosted by a BgpDrAgent for now. - dragents_per_bgp_speaker = BGP_SPEAKER_PER_DRAGENT - dragent_bindings = plugin.get_dragent_bgp_speaker_bindings(context) - agents_hosting = [dragent_binding.agent_id - for dragent_binding in dragent_bindings] - - num_dragents_hosting_bgp_speaker = ( - self._get_num_dragents_hosting_bgp_speaker(bgp_speaker['id'], - dragent_bindings)) - n_agents = dragents_per_bgp_speaker - num_dragents_hosting_bgp_speaker - if n_agents <= 0: - return {'n_agents': 0, - 'hostable_agents': [], - 'hosted_agents': []} - - active_dragents = self._get_active_dragents(plugin, context) - hostable_dragents = [ - agent for agent in set(active_dragents) - if agent.id not in agents_hosting and plugin.is_eligible_agent( - active=True, agent=agent) - ] - if not hostable_dragents: - return {'n_agents': 0, - 'hostable_agents': [], - 'hosted_agents': []} - - n_agents = min(len(hostable_dragents), n_agents) - return {'n_agents': n_agents, - 'hostable_agents': hostable_dragents, - 'hosted_agents': num_dragents_hosting_bgp_speaker} - - -class BgpDrAgentSchedulerBase(BgpDrAgentFilter): - - def schedule_unscheduled_bgp_speakers(self, context, host): - """Schedule unscheduled BgpSpeaker to a BgpDrAgent. - """ - - LOG.debug('Started auto-scheduling on host %s', host) - with context.session.begin(subtransactions=True): - query = context.session.query(agents_db.Agent) - query = query.filter_by( - agent_type=bgp_consts.AGENT_TYPE_BGP_ROUTING, - host=host, - admin_state_up=sql.true()) - try: - bgp_dragent = query.one() - except (exc.NoResultFound): - LOG.debug('No enabled BgpDrAgent on host %s', host) - return False - - if agents_db.AgentDbMixin.is_agent_down( - bgp_dragent.heartbeat_timestamp): - LOG.warning(_LW('BgpDrAgent %s is down'), bgp_dragent.id) - return False - - if self._is_bgp_speaker_hosted(context, bgp_dragent['id']): - # One BgpDrAgent can only host one BGP speaker - LOG.debug('BgpDrAgent already hosting a speaker on host %s. ' - 'Cannot schedule an another one', host) - return False - - unscheduled_speakers = self._get_unscheduled_bgp_speakers(context) - if not unscheduled_speakers: - LOG.debug('Nothing to auto-schedule on host %s', host) - return False - - self.bind(context, [bgp_dragent], unscheduled_speakers[0]) - return True - - def _is_bgp_speaker_hosted(self, context, agent_id): - speaker_binding_model = bgp_dras_db.BgpSpeakerDrAgentBinding - - query = context.session.query(speaker_binding_model) - query = query.filter(speaker_binding_model.agent_id == agent_id) - - return query.count() > 0 - - def _get_unscheduled_bgp_speakers(self, context): - """BGP speakers that needs to be scheduled. - """ - - no_agent_binding = ~sql.exists().where( - bgp_db.BgpSpeaker.id == - bgp_dras_db.BgpSpeakerDrAgentBinding.bgp_speaker_id) - query = context.session.query(bgp_db.BgpSpeaker.id).filter( - no_agent_binding) - return [bgp_speaker_id_[0] for bgp_speaker_id_ in query] - - -class ChanceScheduler(base_scheduler.BaseChanceScheduler, - BgpDrAgentSchedulerBase): - - def __init__(self): - super(ChanceScheduler, self).__init__(self) - - -class WeightScheduler(base_scheduler.BaseWeightScheduler, - BgpDrAgentSchedulerBase): - - def __init__(self): - super(WeightScheduler, self).__init__(self) diff --git a/neutron/tests/common/helpers.py b/neutron/tests/common/helpers.py index a8324faa569..a8d7d814ad0 100644 --- a/neutron/tests/common/helpers.py +++ b/neutron/tests/common/helpers.py @@ -26,7 +26,6 @@ from neutron.common import topics from neutron import context from neutron.db import agents_db from neutron.db import common_db_mixin -from neutron.services.bgp.common import constants as bgp_const HOST = 'localhost' DEFAULT_AZ = 'nova' @@ -109,30 +108,6 @@ def register_dhcp_agent(host=HOST, networks=0, admin_state_up=True, context.get_admin_context(), agent['agent_type'], agent['host']) -def _get_bgp_dragent_dict(host): - agent = { - 'binary': 'neutron-bgp-dragent', - 'host': host, - 'topic': 'q-bgp_dragent', - 'agent_type': bgp_const.AGENT_TYPE_BGP_ROUTING, - 'configurations': {'bgp_speakers': 1}} - return agent - - -def register_bgp_dragent(host=HOST, admin_state_up=True, - alive=True): - agent = _register_agent( - _get_bgp_dragent_dict(host)) - - if not admin_state_up: - set_agent_admin_state(agent['id']) - if not alive: - kill_agent(agent['id']) - - return FakePlugin()._get_agent_by_type_and_host( - context.get_admin_context(), agent['agent_type'], agent['host']) - - def kill_agent(agent_id): hour_ago = timeutils.utcnow() - datetime.timedelta(hours=1) FakePlugin().update_agent( diff --git a/neutron/tests/contrib/gate_hook.sh b/neutron/tests/contrib/gate_hook.sh index 02bf1c50bfc..e953ab2edd7 100644 --- a/neutron/tests/contrib/gate_hook.sh +++ b/neutron/tests/contrib/gate_hook.sh @@ -61,7 +61,6 @@ case $VENV in "api"|"api-pecan"|"full-pecan"|"dsvm-scenario") load_rc_hook api_extensions load_rc_hook qos - load_rc_hook bgp if [[ "$VENV" =~ "pecan" ]]; then load_conf_hook pecan fi diff --git a/neutron/tests/contrib/hooks/api_extensions b/neutron/tests/contrib/hooks/api_extensions index a03b115fade..249dd38c105 100644 --- a/neutron/tests/contrib/hooks/api_extensions +++ b/neutron/tests/contrib/hooks/api_extensions @@ -4,8 +4,6 @@ NETWORK_API_EXTENSIONS=" allowed-address-pairs, \ auto-allocated-topology, \ availability_zone, \ - bgp, \ - bgp_dragent_scheduler, \ binding, \ default-subnetpools, \ dhcp_agent_scheduler, \ diff --git a/neutron/tests/contrib/hooks/bgp b/neutron/tests/contrib/hooks/bgp deleted file mode 100644 index 48788cd3582..00000000000 --- a/neutron/tests/contrib/hooks/bgp +++ /dev/null @@ -1,2 +0,0 @@ -enable_plugin neutron git://git.openstack.org/openstack/neutron -enable_service q-bgp diff --git a/neutron/tests/etc/policy.json b/neutron/tests/etc/policy.json index 148b756b594..8c9d3fedd74 100644 --- a/neutron/tests/etc/policy.json +++ b/neutron/tests/etc/policy.json @@ -213,26 +213,8 @@ "get_flavor_service_profile": "rule:regular_user", "get_auto_allocated_topology": "rule:admin_or_owner", - "get_bgp_speaker": "rule:admin_only", - "create_bgp_speaker": "rule:admin_only", - "update_bgp_speaker": "rule:admin_only", - "delete_bgp_speaker": "rule:admin_only", - - "get_bgp_peer": "rule:admin_only", - "create_bgp_peer": "rule:admin_only", - "update_bgp_peer": "rule:admin_only", - "delete_bgp_peer": "rule:admin_only", - - "add_bgp_peer": "rule:admin_only", - "remove_bgp_peer": "rule:admin_only", - "add_gateway_network": "rule:admin_only", "remove_gateway_network": "rule:admin_only", - "get_advertised_routes":"rule:admin_only", - - "add_bgp_speaker_to_dragent": "rule:admin_only", - "remove_bgp_speaker_from_dragent": "rule:admin_only", - "list_bgp_speaker_on_dragent": "rule:admin_only", - "list_dragent_hosting_bgp_speaker": "rule:admin_only" + "get_advertised_routes":"rule:admin_only" } diff --git a/neutron/tests/functional/services/bgp/__init__.py b/neutron/tests/functional/services/bgp/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/functional/services/bgp/scheduler/__init__.py b/neutron/tests/functional/services/bgp/scheduler/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/functional/services/bgp/scheduler/test_bgp_dragent_scheduler.py b/neutron/tests/functional/services/bgp/scheduler/test_bgp_dragent_scheduler.py deleted file mode 100644 index 5b87c7a4187..00000000000 --- a/neutron/tests/functional/services/bgp/scheduler/test_bgp_dragent_scheduler.py +++ /dev/null @@ -1,208 +0,0 @@ -# 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. - -import testscenarios - -from neutron import context -from neutron.db import agents_db -from neutron.db import bgp_db -from neutron.db import bgp_dragentscheduler_db as bgp_dras_db -from neutron.db import common_db_mixin -from neutron.services.bgp.scheduler import bgp_dragent_scheduler as bgp_dras -from neutron.tests.common import helpers -from neutron.tests.unit import testlib_api - -# Required to generate tests from scenarios. Not compatible with nose. -load_tests = testscenarios.load_tests_apply_scenarios - - -class TestAutoSchedule(testlib_api.SqlTestCase, - bgp_dras_db.BgpDrAgentSchedulerDbMixin, - agents_db.AgentDbMixin, - common_db_mixin.CommonDbMixin): - """Test various scenarios for schedule_unscheduled_bgp_speakers. - - Below is the brief description of the scenario variables - -------------------------------------------------------- - host_count - number of hosts. - - agent_count - number of BGP dynamic routing agents. - - down_agent_count - number of DRAgents which are inactive. - - bgp_speaker_count - Number of bgp_speakers. - - hosted_bgp_speakers - A mapping of agent id to the ids of the bgp_speakers that they - should be initially hosting. - - expected_schedule_return_value - Expected return value of 'schedule_unscheduled_bgp_speakers'. - - expected_hosted_bgp_speakers - This stores the expected bgp_speakers that should have been - scheduled (or that could have already been scheduled) for each - agent after the 'schedule_unscheduled_bgp_speakers' function is - called. - """ - - scenarios = [ - ('No BgpDrAgent scheduled, if no DRAgent is present', - dict(host_count=1, - agent_count=0, - down_agent_count=0, - bgp_speaker_count=1, - hosted_bgp_speakers={}, - expected_schedule_return_value=False)), - - ('No BgpDrAgent scheduled, if no BGP speaker are present', - dict(host_count=1, - agent_count=1, - down_agent_count=0, - bgp_speaker_count=0, - hosted_bgp_speakers={}, - expected_schedule_return_value=False, - expected_hosted_bgp_speakers={'agent-0': []})), - - ('No BgpDrAgent scheduled, if BGP speaker already hosted', - dict(host_count=1, - agent_count=1, - down_agent_count=0, - bgp_speaker_count=1, - hosted_bgp_speakers={'agent-0': ['bgp-speaker-0']}, - expected_schedule_return_value=False, - expected_hosted_bgp_speakers={'agent-0': ['bgp-speaker-0']})), - - ('BgpDrAgent scheduled to the speaker, if the speaker is not hosted', - dict(host_count=1, - agent_count=1, - down_agent_count=0, - bgp_speaker_count=1, - hosted_bgp_speakers={}, - expected_schedule_return_value=True, - expected_hosted_bgp_speakers={'agent-0': ['bgp-speaker-0']})), - - ('No BgpDrAgent scheduled, if all the agents are down', - dict(host_count=2, - agent_count=2, - down_agent_count=2, - bgp_speaker_count=1, - hosted_bgp_speakers={}, - expected_schedule_return_value=False, - expected_hosted_bgp_speakers={'agent-0': [], - 'agent-1': [], })), - ] - - def _strip_host_index(self, name): - """Strips the host index. - - Eg. if name = '2-agent-3', then 'agent-3' is returned. - """ - return name[name.find('-') + 1:] - - def _extract_index(self, name): - """Extracts the index number and returns. - - Eg. if name = '2-agent-3', then 3 is returned - """ - return int(name.split('-')[-1]) - - def _get_hosted_bgp_speakers_on_dragent(self, agent_id): - query = self.ctx.session.query( - bgp_dras_db.BgpSpeakerDrAgentBinding.bgp_speaker_id) - query = query.filter( - bgp_dras_db.BgpSpeakerDrAgentBinding.agent_id == - agent_id) - - return [item[0] for item in query] - - def _create_and_set_agents_down(self, hosts, agent_count=0, - down_agent_count=0, admin_state_up=True): - agents = [] - if agent_count: - for i, host in enumerate(hosts): - is_alive = i >= down_agent_count - agents.append(helpers.register_bgp_dragent( - host, - admin_state_up=admin_state_up, - alive=is_alive)) - return agents - - def _save_bgp_speakers(self, bgp_speakers): - cls = bgp_db.BgpDbMixin() - bgp_speaker_body = { - 'bgp_speaker': {'name': 'fake_bgp_speaker', - 'ip_version': '4', - 'local_as': '123', - 'advertise_floating_ip_host_routes': '0', - 'advertise_tenant_networks': '0', - 'peers': [], - 'networks': []}} - i = 1 - for bgp_speaker_id in bgp_speakers: - bgp_speaker_body['bgp_speaker']['local_as'] = i - cls._save_bgp_speaker(self.ctx, bgp_speaker_body, - uuid=bgp_speaker_id) - i = i + 1 - - def _test_auto_schedule(self, host_index): - scheduler = bgp_dras.ChanceScheduler() - self.ctx = context.get_admin_context() - msg = 'host_index = %s' % host_index - - # create hosts - hosts = ['%s-agent-%s' % (host_index, i) - for i in range(self.host_count)] - bgp_dragents = self._create_and_set_agents_down(hosts, - self.agent_count, - self.down_agent_count) - - # create bgp_speakers - self._bgp_speakers = ['%s-bgp-speaker-%s' % (host_index, i) - for i in range(self.bgp_speaker_count)] - self._save_bgp_speakers(self._bgp_speakers) - - # pre schedule the bgp_speakers to the agents defined in - # self.hosted_bgp_speakers before calling auto_schedule_bgp_speaker - for agent, bgp_speakers in self.hosted_bgp_speakers.items(): - agent_index = self._extract_index(agent) - for bgp_speaker in bgp_speakers: - bs_index = self._extract_index(bgp_speaker) - scheduler.bind(self.ctx, [bgp_dragents[agent_index]], - self._bgp_speakers[bs_index]) - - retval = scheduler.schedule_unscheduled_bgp_speakers(self.ctx, - hosts[host_index]) - self.assertEqual(self.expected_schedule_return_value, retval, - message=msg) - - if self.agent_count: - agent_id = bgp_dragents[host_index].id - hosted_bgp_speakers = self._get_hosted_bgp_speakers_on_dragent( - agent_id) - hosted_bs_ids = [self._strip_host_index(net) - for net in hosted_bgp_speakers] - expected_hosted_bgp_speakers = self.expected_hosted_bgp_speakers[ - 'agent-%s' % host_index] - self.assertItemsEqual(hosted_bs_ids, expected_hosted_bgp_speakers, - msg) - - def test_auto_schedule(self): - for i in range(self.host_count): - self._test_auto_schedule(i) diff --git a/neutron/tests/tempest/api/test_bgp_speaker_extensions.py b/neutron/tests/tempest/api/test_bgp_speaker_extensions.py deleted file mode 100644 index 123f43fe2da..00000000000 --- a/neutron/tests/tempest/api/test_bgp_speaker_extensions.py +++ /dev/null @@ -1,286 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development Company LP -# -# 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 netaddr -from tempest import config -from tempest.lib import exceptions as lib_exc -from tempest import test -import testtools - -from neutron.tests.tempest.api import base -from neutron.tests.tempest.common import tempest_fixtures as fixtures - -CONF = config.CONF - - -class BgpSpeakerTestJSONBase(base.BaseAdminNetworkTest): - - default_bgp_speaker_args = {'local_as': '1234', - 'ip_version': 4, - 'name': 'my-bgp-speaker', - 'advertise_floating_ip_host_routes': True, - 'advertise_tenant_networks': True} - default_bgp_peer_args = {'remote_as': '4321', - 'name': 'my-bgp-peer', - 'peer_ip': '192.168.1.1', - 'auth_type': 'md5', 'password': 'my-secret'} - - @classmethod - @test.requires_ext(extension="bgp_speaker", service="network") - def resource_setup(cls): - super(BgpSpeakerTestJSONBase, cls).resource_setup() - - cls.admin_routerports = [] - cls.admin_floatingips = [] - cls.admin_routers = [] - cls.ext_net_id = CONF.network.public_network_id - - @classmethod - def resource_cleanup(cls): - for floatingip in cls.admin_floatingips: - cls._try_delete_resource(cls.admin_client.delete_floatingip, - floatingip['id']) - for routerport in cls.admin_routerports: - cls._try_delete_resource( - cls.admin_client.remove_router_interface_with_subnet_id, - routerport['router_id'], routerport['subnet_id']) - for router in cls.admin_routers: - cls._try_delete_resource(cls.admin_client.delete_router, - router['id']) - super(BgpSpeakerTestJSONBase, cls).resource_cleanup() - - def create_bgp_speaker(self, auto_delete=True, **args): - data = {'bgp_speaker': args} - bgp_speaker = self.admin_client.create_bgp_speaker(data) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - if auto_delete: - self.addCleanup(self.delete_bgp_speaker, bgp_speaker_id) - return bgp_speaker - - def create_bgp_peer(self, **args): - bgp_peer = self.admin_client.create_bgp_peer({'bgp_peer': args}) - bgp_peer_id = bgp_peer['bgp-peer']['id'] - self.addCleanup(self.delete_bgp_peer, bgp_peer_id) - return bgp_peer - - def update_bgp_speaker(self, id, **args): - data = {'bgp_speaker': args} - return self.admin_client.update_bgp_speaker(id, data) - - def delete_bgp_speaker(self, id): - return self.admin_client.delete_bgp_speaker(id) - - def get_bgp_speaker(self, id): - return self.admin_client.get_bgp_speaker(id) - - def create_bgp_speaker_and_peer(self): - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_peer = self.create_bgp_peer(**self.default_bgp_peer_args) - return (bgp_speaker, bgp_peer) - - def delete_bgp_peer(self, id): - return self.admin_client.delete_bgp_peer(id) - - def add_bgp_peer(self, bgp_speaker_id, bgp_peer_id): - return self.admin_client.add_bgp_peer_with_id(bgp_speaker_id, - bgp_peer_id) - - def remove_bgp_peer(self, bgp_speaker_id, bgp_peer_id): - return self.admin_client.remove_bgp_peer_with_id(bgp_speaker_id, - bgp_peer_id) - - def delete_address_scope(self, id): - return self.admin_client.delete_address_scope(id) - - -class BgpSpeakerTestJSON(BgpSpeakerTestJSONBase): - - """ - Tests the following operations in the Neutron API using the REST client for - Neutron: - - Create bgp-speaker - Delete bgp-speaker - Create bgp-peer - Update bgp-peer - Delete bgp-peer - """ - - @test.idempotent_id('df259771-7104-4ffa-b77f-bd183600d7f9') - def test_delete_bgp_speaker(self): - bgp_speaker = self.create_bgp_speaker(auto_delete=False, - **self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - self.delete_bgp_speaker(bgp_speaker_id) - self.assertRaises(lib_exc.NotFound, - self.get_bgp_speaker, - bgp_speaker_id) - - @test.idempotent_id('81d9dc45-19f8-4c6e-88b8-401d965cd1b0') - def test_create_bgp_peer(self): - self.create_bgp_peer(**self.default_bgp_peer_args) - - @test.idempotent_id('6ade0319-1ee2-493c-ac4b-5eb230ff3a77') - def test_add_bgp_peer(self): - bgp_speaker, bgp_peer = self.create_bgp_speaker_and_peer() - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - bgp_peer_id = bgp_peer['bgp-peer']['id'] - - self.add_bgp_peer(bgp_speaker_id, bgp_peer_id) - bgp_speaker = self.admin_client.get_bgp_speaker(bgp_speaker_id) - bgp_peers_list = bgp_speaker['bgp-speaker']['peers'] - self.assertEqual(1, len(bgp_peers_list)) - self.assertTrue(bgp_peer_id in bgp_peers_list) - - @test.idempotent_id('f9737708-1d79-440b-8350-779f97d882ee') - def test_remove_bgp_peer(self): - bgp_peer = self.create_bgp_peer(**self.default_bgp_peer_args) - bgp_peer_id = bgp_peer['bgp-peer']['id'] - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - self.add_bgp_peer(bgp_speaker_id, bgp_peer_id) - bgp_speaker = self.admin_client.get_bgp_speaker(bgp_speaker_id) - bgp_peers_list = bgp_speaker['bgp-speaker']['peers'] - self.assertTrue(bgp_peer_id in bgp_peers_list) - - bgp_speaker = self.remove_bgp_peer(bgp_speaker_id, bgp_peer_id) - bgp_speaker = self.admin_client.get_bgp_speaker(bgp_speaker_id) - bgp_peers_list = bgp_speaker['bgp-speaker']['peers'] - self.assertTrue(not bgp_peers_list) - - @testtools.skip('bug/1553374') - @test.idempotent_id('23c8eb37-d10d-4f43-b2e7-6542cb6a4405') - def test_add_gateway_network(self): - self.useFixture(fixtures.LockFixture('gateway_network_binding')) - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - - self.admin_client.add_bgp_gateway_network(bgp_speaker_id, - self.ext_net_id) - bgp_speaker = self.admin_client.get_bgp_speaker(bgp_speaker_id) - network_list = bgp_speaker['bgp-speaker']['networks'] - self.assertEqual(1, len(network_list)) - self.assertTrue(self.ext_net_id in network_list) - - @testtools.skip('bug/1553374') - @test.idempotent_id('6cfc7137-0d99-4a3d-826c-9d1a3a1767b0') - def test_remove_gateway_network(self): - self.useFixture(fixtures.LockFixture('gateway_network_binding')) - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - self.admin_client.add_bgp_gateway_network(bgp_speaker_id, - self.ext_net_id) - bgp_speaker = self.admin_client.get_bgp_speaker(bgp_speaker_id) - networks = bgp_speaker['bgp-speaker']['networks'] - - self.assertTrue(self.ext_net_id in networks) - self.admin_client.remove_bgp_gateway_network(bgp_speaker_id, - self.ext_net_id) - bgp_speaker = self.admin_client.get_bgp_speaker(bgp_speaker_id) - network_list = bgp_speaker['bgp-speaker']['networks'] - self.assertTrue(not network_list) - - @testtools.skip('bug/1553374') - @test.idempotent_id('5bef22ad-5e70-4f7b-937a-dc1944642996') - def test_get_advertised_routes_null_address_scope(self): - self.useFixture(fixtures.LockFixture('gateway_network_binding')) - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - self.admin_client.add_bgp_gateway_network(bgp_speaker_id, - self.ext_net_id) - routes = self.admin_client.get_bgp_advertised_routes(bgp_speaker_id) - self.assertEqual(0, len(routes['advertised_routes'])) - - @testtools.skip('bug/1553374') - @test.idempotent_id('cae9cdb1-ad65-423c-9604-d4cd0073616e') - def test_get_advertised_routes_floating_ips(self): - self.useFixture(fixtures.LockFixture('gateway_network_binding')) - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - self.admin_client.add_bgp_gateway_network(bgp_speaker_id, - self.ext_net_id) - tenant_net = self.create_network() - tenant_subnet = self.create_subnet(tenant_net) - ext_gw_info = {'network_id': self.ext_net_id} - router = self.admin_client.create_router( - 'my-router', - external_gateway_info=ext_gw_info, - admin_state_up=True, - distributed=False) - self.admin_routers.append(router['router']) - self.admin_client.add_router_interface_with_subnet_id( - router['router']['id'], - tenant_subnet['id']) - self.admin_routerports.append({'router_id': router['router']['id'], - 'subnet_id': tenant_subnet['id']}) - tenant_port = self.create_port(tenant_net) - floatingip = self.create_floatingip(self.ext_net_id) - self.admin_floatingips.append(floatingip) - self.client.update_floatingip(floatingip['id'], - port_id=tenant_port['id']) - routes = self.admin_client.get_bgp_advertised_routes(bgp_speaker_id) - self.assertEqual(1, len(routes['advertised_routes'])) - self.assertEqual(floatingip['floating_ip_address'] + '/32', - routes['advertised_routes'][0]['destination']) - - @testtools.skip('bug/1553374') - @test.idempotent_id('c9ad566e-fe8f-4559-8303-bbad9062a30c') - def test_get_advertised_routes_tenant_networks(self): - self.useFixture(fixtures.LockFixture('gateway_network_binding')) - addr_scope = self.create_address_scope('my-scope', ip_version=4) - ext_net = self.create_shared_network(**{'router:external': True}) - tenant_net = self.create_network() - ext_subnetpool = self.create_subnetpool( - 'test-pool-ext', - is_admin=True, - default_prefixlen=24, - address_scope_id=addr_scope['id'], - prefixes=['8.0.0.0/8']) - tenant_subnetpool = self.create_subnetpool( - 'tenant-test-pool', - default_prefixlen=25, - address_scope_id=addr_scope['id'], - prefixes=['10.10.0.0/16']) - self.create_subnet({'id': ext_net['id']}, - cidr=netaddr.IPNetwork('8.0.0.0/24'), - ip_version=4, - client=self.admin_client, - subnetpool_id=ext_subnetpool['id']) - tenant_subnet = self.create_subnet( - {'id': tenant_net['id']}, - cidr=netaddr.IPNetwork('10.10.0.0/24'), - ip_version=4, - subnetpool_id=tenant_subnetpool['id']) - ext_gw_info = {'network_id': ext_net['id']} - router = self.admin_client.create_router( - 'my-router', - external_gateway_info=ext_gw_info, - distributed=False)['router'] - self.admin_routers.append(router) - self.admin_client.add_router_interface_with_subnet_id( - router['id'], - tenant_subnet['id']) - self.admin_routerports.append({'router_id': router['id'], - 'subnet_id': tenant_subnet['id']}) - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - self.admin_client.add_bgp_gateway_network(bgp_speaker_id, - ext_net['id']) - routes = self.admin_client.get_bgp_advertised_routes(bgp_speaker_id) - self.assertEqual(1, len(routes['advertised_routes'])) - self.assertEqual(tenant_subnet['cidr'], - routes['advertised_routes'][0]['destination']) - fixed_ip = router['external_gateway_info']['external_fixed_ips'][0] - self.assertEqual(fixed_ip['ip_address'], - routes['advertised_routes'][0]['next_hop']) diff --git a/neutron/tests/tempest/api/test_bgp_speaker_extensions_negative.py b/neutron/tests/tempest/api/test_bgp_speaker_extensions_negative.py deleted file mode 100644 index 19c1a0259ef..00000000000 --- a/neutron/tests/tempest/api/test_bgp_speaker_extensions_negative.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development Company LP -# -# 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 netaddr -from tempest.lib import exceptions as lib_exc - -from neutron.tests.tempest.api import test_bgp_speaker_extensions as test_base -from tempest import test - - -class BgpSpeakerTestJSONNegative(test_base.BgpSpeakerTestJSONBase): - - """Negative test cases asserting proper behavior of BGP API extension""" - - @test.attr(type='negative') - @test.idempotent_id('75e9ee2f-6efd-4320-bff7-ae24741c8b06') - def test_create_bgp_speaker_illegal_local_asn(self): - self.assertRaises(lib_exc.BadRequest, - self.create_bgp_speaker, - local_as='65537') - - @test.attr(type='negative') - @test.idempotent_id('6742ec2e-382a-4453-8791-13a19b47cd13') - def test_create_bgp_speaker_non_admin(self): - self.assertRaises(lib_exc.Forbidden, - self.client.create_bgp_speaker, - {'bgp_speaker': self.default_bgp_speaker_args}) - - @test.attr(type='negative') - @test.idempotent_id('33f7aaf0-9786-478b-b2d1-a51086a50eb4') - def test_create_bgp_peer_non_admin(self): - self.assertRaises(lib_exc.Forbidden, - self.client.create_bgp_peer, - {'bgp_peer': self.default_bgp_peer_args}) - - @test.attr(type='negative') - @test.idempotent_id('39435932-0266-4358-899b-0e9b1e53c3e9') - def test_update_bgp_speaker_local_asn(self): - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - - self.assertRaises(lib_exc.BadRequest, self.update_bgp_speaker, - bgp_speaker_id, local_as='4321') - - @test.idempotent_id('9cc33701-51e5-421f-a5d5-fd7b330e550f') - def test_get_advertised_routes_tenant_networks(self): - addr_scope1 = self.create_address_scope('my-scope1', ip_version=4) - addr_scope2 = self.create_address_scope('my-scope2', ip_version=4) - ext_net = self.create_shared_network(**{'router:external': True}) - tenant_net1 = self.create_network() - tenant_net2 = self.create_network() - ext_subnetpool = self.create_subnetpool( - 'test-pool-ext', - is_admin=True, - default_prefixlen=24, - address_scope_id=addr_scope1['id'], - prefixes=['8.0.0.0/8']) - tenant_subnetpool1 = self.create_subnetpool( - 'tenant-test-pool', - default_prefixlen=25, - address_scope_id=addr_scope1['id'], - prefixes=['10.10.0.0/16']) - tenant_subnetpool2 = self.create_subnetpool( - 'tenant-test-pool', - default_prefixlen=25, - address_scope_id=addr_scope2['id'], - prefixes=['11.10.0.0/16']) - self.create_subnet({'id': ext_net['id']}, - cidr=netaddr.IPNetwork('8.0.0.0/24'), - ip_version=4, - client=self.admin_client, - subnetpool_id=ext_subnetpool['id']) - tenant_subnet1 = self.create_subnet( - {'id': tenant_net1['id']}, - cidr=netaddr.IPNetwork('10.10.0.0/24'), - ip_version=4, - subnetpool_id=tenant_subnetpool1['id']) - tenant_subnet2 = self.create_subnet( - {'id': tenant_net2['id']}, - cidr=netaddr.IPNetwork('11.10.0.0/24'), - ip_version=4, - subnetpool_id=tenant_subnetpool2['id']) - ext_gw_info = {'network_id': ext_net['id']} - router = self.admin_client.create_router( - 'my-router', - distributed=False, - external_gateway_info=ext_gw_info)['router'] - self.admin_routers.append(router) - self.admin_client.add_router_interface_with_subnet_id( - router['id'], - tenant_subnet1['id']) - self.admin_routerports.append({'router_id': router['id'], - 'subnet_id': tenant_subnet1['id']}) - self.admin_client.add_router_interface_with_subnet_id( - router['id'], - tenant_subnet2['id']) - self.admin_routerports.append({'router_id': router['id'], - 'subnet_id': tenant_subnet2['id']}) - bgp_speaker = self.create_bgp_speaker(**self.default_bgp_speaker_args) - bgp_speaker_id = bgp_speaker['bgp-speaker']['id'] - self.admin_client.add_bgp_gateway_network(bgp_speaker_id, - ext_net['id']) - routes = self.admin_client.get_bgp_advertised_routes(bgp_speaker_id) - self.assertEqual(1, len(routes['advertised_routes'])) - self.assertEqual(tenant_subnet1['cidr'], - routes['advertised_routes'][0]['destination']) - fixed_ip = router['external_gateway_info']['external_fixed_ips'][0] - self.assertEqual(fixed_ip['ip_address'], - routes['advertised_routes'][0]['next_hop']) diff --git a/neutron/tests/tempest/services/network/json/network_client.py b/neutron/tests/tempest/services/network/json/network_client.py index e273f55b86b..4a89ad50653 100644 --- a/neutron/tests/tempest/services/network/json/network_client.py +++ b/neutron/tests/tempest/services/network/json/network_client.py @@ -47,8 +47,6 @@ class NetworkClientJSON(service_client.RestClient): # the following map is used to construct proper URI # for the given neutron resource service_resource_prefix_map = { - 'bgp-peers': '', - 'bgp-speakers': '', 'networks': '', 'subnets': '', 'subnetpools': '', @@ -212,125 +210,6 @@ class NetworkClientJSON(service_client.RestClient): self.expected_success(200, resp.status) return service_client.ResponseBody(resp, body) - # BGP speaker methods - def create_bgp_speaker(self, post_data): - body = self.serialize_list(post_data, "bgp-speakers", "bgp-speaker") - uri = self.get_uri("bgp-speakers") - resp, body = self.post(uri, body) - body = {'bgp-speaker': self.deserialize_list(body)} - self.expected_success(201, resp.status) - return service_client.ResponseBody(resp, body) - - def get_bgp_speaker(self, id): - uri = self.get_uri("bgp-speakers") - bgp_speaker_uri = '%s/%s' % (uri, id) - resp, body = self.get(bgp_speaker_uri) - body = {'bgp-speaker': self.deserialize_list(body)} - self.expected_success(200, resp.status) - return service_client.ResponseBody(resp, body) - - def get_bgp_speakers(self): - uri = self.get_uri("bgp-speakers") - resp, body = self.get(uri) - body = {'bgp-speakers': self.deserialize_list(body)} - self.expected_success(200, resp.status) - return service_client.ResponseBody(resp, body) - - def update_bgp_speaker(self, id, put_data): - body = self.serialize_list(put_data, "bgp-speakers", "bgp-speaker") - uri = self.get_uri("bgp-speakers") - bgp_speaker_uri = '%s/%s' % (uri, id) - resp, body = self.put(bgp_speaker_uri, body) - body = {'bgp-speaker': self.deserialize_list(body)} - self.expected_success(200, resp.status) - return service_client.ResponseBody(resp, body) - - def delete_bgp_speaker(self, id): - uri = self.get_uri("bgp-speakers") - bgp_speaker_uri = '%s/%s' % (uri, id) - resp, body = self.delete(bgp_speaker_uri) - self.expected_success(204, resp.status) - return service_client.ResponseBody(resp, body) - - def create_bgp_peer(self, post_data): - body = self.serialize_list(post_data, "bgp-peers", "bgp-peer") - uri = self.get_uri("bgp-peers") - resp, body = self.post(uri, body) - body = {'bgp-peer': self.deserialize_list(body)} - self.expected_success(201, resp.status) - return service_client.ResponseBody(resp, body) - - def get_bgp_peer(self, id): - uri = self.get_uri("bgp-peers") - bgp_speaker_uri = '%s/%s' % (uri, id) - resp, body = self.get(bgp_speaker_uri) - body = {'bgp-peer': self.deserialize_list(body)} - self.expected_success(200, resp.status) - return service_client.ResponseBody(resp, body) - - def delete_bgp_peer(self, id): - uri = self.get_uri("bgp-peers") - bgp_speaker_uri = '%s/%s' % (uri, id) - resp, body = self.delete(bgp_speaker_uri) - self.expected_success(204, resp.status) - return service_client.ResponseBody(resp, body) - - def add_bgp_peer_with_id(self, bgp_speaker_id, bgp_peer_id): - uri = '%s/bgp-speakers/%s/add_bgp_peer' % (self.uri_prefix, - bgp_speaker_id) - update_body = {"bgp_peer_id": bgp_peer_id} - update_body = jsonutils.dumps(update_body) - resp, body = self.put(uri, update_body) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return service_client.ResponseBody(resp, body) - - def remove_bgp_peer_with_id(self, bgp_speaker_id, bgp_peer_id): - uri = '%s/bgp-speakers/%s/remove_bgp_peer' % (self.uri_prefix, - bgp_speaker_id) - update_body = {"bgp_peer_id": bgp_peer_id} - update_body = jsonutils.dumps(update_body) - resp, body = self.put(uri, update_body) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return service_client.ResponseBody(resp, body) - - def add_bgp_gateway_network(self, bgp_speaker_id, network_id): - uri = '%s/bgp-speakers/%s/add_gateway_network' % (self.uri_prefix, - bgp_speaker_id) - update_body = {"network_id": network_id} - update_body = jsonutils.dumps(update_body) - resp, body = self.put(uri, update_body) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return service_client.ResponseBody(resp, body) - - def remove_bgp_gateway_network(self, bgp_speaker_id, network_id): - uri = '%s/bgp-speakers/%s/remove_gateway_network' - uri = uri % (self.uri_prefix, bgp_speaker_id) - update_body = {"network_id": network_id} - update_body = jsonutils.dumps(update_body) - resp, body = self.put(uri, update_body) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return service_client.ResponseBody(resp, body) - - def get_bgp_advertised_routes(self, bgp_speaker_id): - base_uri = '%s/bgp-speakers/%s/get_advertised_routes' - uri = base_uri % (self.uri_prefix, bgp_speaker_id) - resp, body = self.get(uri) - body = {'advertised_routes': self.deserialize_list(body)} - self.expected_success(200, resp.status) - return service_client.ResponseBody(resp, body) - - def get_bgp_router_routes(self, router_id): - base_uri = '%s/router-routes/%s' - uri = base_uri % (self.uri_prefix, router_id) - resp, body = self.get(uri) - body = self.deserialize_list(body) - self.expected_success(200, resp.status) - return service_client.ResponseBody(resp, body) - # Common methods that are hard to automate def create_bulk_network(self, names, shared=False): network_list = [{'name': name, 'shared': shared} for name in names] diff --git a/neutron/tests/unit/api/rpc/agentnotifiers/test_bgp_dr_rpc_agent_api.py b/neutron/tests/unit/api/rpc/agentnotifiers/test_bgp_dr_rpc_agent_api.py deleted file mode 100644 index b3f08b07ca3..00000000000 --- a/neutron/tests/unit/api/rpc/agentnotifiers/test_bgp_dr_rpc_agent_api.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 mock - -from neutron.api.rpc.agentnotifiers import bgp_dr_rpc_agent_api -from neutron import context -from neutron.tests import base - - -class TestBgpDrAgentNotifyApi(base.BaseTestCase): - - def setUp(self): - super(TestBgpDrAgentNotifyApi, self).setUp() - self.notifier = ( - bgp_dr_rpc_agent_api.BgpDrAgentNotifyApi()) - - mock_cast_p = mock.patch.object(self.notifier, - '_notification_host_cast') - self.mock_cast = mock_cast_p.start() - mock_call_p = mock.patch.object(self.notifier, - '_notification_host_call') - self.mock_call = mock_call_p.start() - self.context = context.get_admin_context() - self.host = 'host-1' - - def test_notify_dragent_bgp_routes_advertisement(self): - bgp_speaker_id = 'bgp-speaker-1' - routes = [{'destination': '1.1.1.1', 'next_hop': '2.2.2.2'}] - self.notifier.bgp_routes_advertisement(self.context, bgp_speaker_id, - routes, self.host) - self.assertEqual(1, self.mock_cast.call_count) - self.assertEqual(0, self.mock_call.call_count) - - def test_notify_dragent_bgp_routes_withdrawal(self): - bgp_speaker_id = 'bgp-speaker-1' - routes = [{'destination': '1.1.1.1'}] - self.notifier.bgp_routes_withdrawal(self.context, bgp_speaker_id, - routes, self.host) - self.assertEqual(1, self.mock_cast.call_count) - self.assertEqual(0, self.mock_call.call_count) - - def test_notify_bgp_peer_disassociated(self): - bgp_speaker_id = 'bgp-speaker-1' - bgp_peer_ip = '1.1.1.1' - self.notifier.bgp_peer_disassociated(self.context, bgp_speaker_id, - bgp_peer_ip, self.host) - self.assertEqual(1, self.mock_cast.call_count) - self.assertEqual(0, self.mock_call.call_count) - - def test_notify_bgp_peer_associated(self): - bgp_speaker_id = 'bgp-speaker-1' - bgp_peer_id = 'bgp-peer-1' - self.notifier.bgp_peer_associated(self.context, bgp_speaker_id, - bgp_peer_id, self.host) - self.assertEqual(1, self.mock_cast.call_count) - self.assertEqual(0, self.mock_call.call_count) - - def test_notify_bgp_speaker_created(self): - bgp_speaker_id = 'bgp-speaker-1' - self.notifier.bgp_speaker_created(self.context, bgp_speaker_id, - self.host) - self.assertEqual(1, self.mock_cast.call_count) - self.assertEqual(0, self.mock_call.call_count) - - def test_notify_bgp_speaker_removed(self): - bgp_speaker_id = 'bgp-speaker-1' - self.notifier.bgp_speaker_removed(self.context, bgp_speaker_id, - self.host) - self.assertEqual(1, self.mock_cast.call_count) - self.assertEqual(0, self.mock_call.call_count) diff --git a/neutron/tests/unit/api/rpc/handlers/test_bgp_speaker_rpc.py b/neutron/tests/unit/api/rpc/handlers/test_bgp_speaker_rpc.py deleted file mode 100644 index 9c405cff527..00000000000 --- a/neutron/tests/unit/api/rpc/handlers/test_bgp_speaker_rpc.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 mock - -from neutron.api.rpc.handlers import bgp_speaker_rpc -from neutron.tests import base - - -class TestBgpSpeakerRpcCallback(base.BaseTestCase): - - def setUp(self): - self.plugin_p = mock.patch('neutron.manager.NeutronManager.' - 'get_service_plugins') - self.plugin = self.plugin_p.start() - self.callback = bgp_speaker_rpc.BgpSpeakerRpcCallback() - super(TestBgpSpeakerRpcCallback, self).setUp() - - def test_get_bgp_speaker_info(self): - self.callback.get_bgp_speaker_info(mock.Mock(), - bgp_speaker_id='id1') - self.assertIsNotNone(len(self.plugin.mock_calls)) - - def test_get_bgp_peer_info(self): - self.callback.get_bgp_peer_info(mock.Mock(), - bgp_peer_id='id1') - self.assertIsNotNone(len(self.plugin.mock_calls)) - - def test_get_bgp_speakers(self): - self.callback.get_bgp_speakers(mock.Mock(), - host='host') - self.assertIsNotNone(len(self.plugin.mock_calls)) diff --git a/neutron/tests/unit/db/test_bgp_db.py b/neutron/tests/unit/db/test_bgp_db.py deleted file mode 100644 index 301bc13285e..00000000000 --- a/neutron/tests/unit/db/test_bgp_db.py +++ /dev/null @@ -1,1045 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development Company LP -# -# 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 contextlib -import netaddr -from neutron_lib import constants -from neutron_lib import exceptions as n_exc -from oslo_utils import uuidutils - -from neutron.extensions import bgp -from neutron.extensions import external_net -from neutron.extensions import portbindings -from neutron import manager -from neutron.plugins.common import constants as p_const -from neutron.services.bgp import bgp_plugin -from neutron.tests.unit.plugins.ml2 import test_plugin - -_uuid = uuidutils.generate_uuid - -ADVERTISE_FIPS_KEY = 'advertise_floating_ip_host_routes' - - -class BgpEntityCreationMixin(object): - - @contextlib.contextmanager - def bgp_speaker(self, ip_version, local_as, name='my-speaker', - advertise_fip_host_routes=True, - advertise_tenant_networks=True, - networks=None, peers=None): - data = {'ip_version': ip_version, - ADVERTISE_FIPS_KEY: advertise_fip_host_routes, - 'advertise_tenant_networks': advertise_tenant_networks, - 'local_as': local_as, 'name': name} - bgp_speaker = self.bgp_plugin.create_bgp_speaker(self.context, - {'bgp_speaker': data}) - bgp_speaker_id = bgp_speaker['id'] - - if networks: - for network_id in networks: - self.bgp_plugin.add_gateway_network( - self.context, - bgp_speaker_id, - {'network_id': network_id}) - if peers: - for peer_id in peers: - self.bgp_plugin.add_bgp_peer(self.context, bgp_speaker_id, - {'bgp_peer_id': peer_id}) - - yield self.bgp_plugin.get_bgp_speaker(self.context, bgp_speaker_id) - - @contextlib.contextmanager - def bgp_peer(self, tenant_id=_uuid(), remote_as='4321', - peer_ip="192.168.1.1", auth_type="md5", - password="my-secret", name="my-peer"): - data = {'peer_ip': peer_ip, 'tenant_id': tenant_id, - 'remote_as': remote_as, 'auth_type': auth_type, - 'password': password, 'name': name} - bgp_peer = self.bgp_plugin.create_bgp_peer(self.context, - {'bgp_peer': data}) - yield bgp_peer - self.bgp_plugin.delete_bgp_peer(self.context, bgp_peer['id']) - - @contextlib.contextmanager - def bgp_speaker_with_gateway_network(self, address_scope_id, local_as, - advertise_fip_host_routes=True, - advertise_tenant_networks=True, - network_external=True, - fmt=None, set_context=False): - pass - - @contextlib.contextmanager - def bgp_speaker_with_router(self, address_scope_id, local_as, - gw_network_id=None, gw_subnet_ids=None, - tenant_subnet_ids=None, - advertise_fip_host_routes=True, - advertise_tenant_networks=True, - fmt=None, set_context=False, - router_distributed=False): - pass - - @contextlib.contextmanager - def router(self, name='bgp-test-router', tenant_id=_uuid(), - admin_state_up=True, **kwargs): - request = {'router': {'tenant_id': tenant_id, - 'name': name, - 'admin_state_up': admin_state_up}} - for arg in kwargs: - request['router'][arg] = kwargs[arg] - router = self.l3plugin.create_router(self.context, request) - yield router - - @contextlib.contextmanager - def router_with_external_and_tenant_networks( - self, - tenant_id=_uuid(), - gw_prefix='8.8.8.0/24', - tenant_prefix='192.168.0.0/16', - address_scope=None, - distributed=False): - prefixes = [gw_prefix, tenant_prefix] - gw_ip_net = netaddr.IPNetwork(gw_prefix) - tenant_ip_net = netaddr.IPNetwork(tenant_prefix) - subnetpool_args = {'tenant_id': tenant_id, - 'name': 'bgp-pool'} - if address_scope: - subnetpool_args['address_scope_id'] = address_scope['id'] - - with self.network() as ext_net, self.network() as int_net,\ - self.subnetpool(prefixes, **subnetpool_args) as pool: - subnetpool_id = pool['subnetpool']['id'] - gw_net_id = ext_net['network']['id'] - with self.subnet(ext_net, - cidr=gw_prefix, - subnetpool_id=subnetpool_id, - ip_version=gw_ip_net.version),\ - self.subnet(int_net, - cidr=tenant_prefix, - subnetpool_id=subnetpool_id, - ip_version=tenant_ip_net.version) as int_subnet: - self._update('networks', gw_net_id, - {'network': {external_net.EXTERNAL: True}}) - ext_gw_info = {'network_id': gw_net_id} - with self.router(external_gateway_info=ext_gw_info, - distributed=distributed) as router: - router_id = router['id'] - router_interface_info = {'subnet_id': - int_subnet['subnet']['id']} - self.l3plugin.add_router_interface(self.context, - router_id, - router_interface_info) - yield router, ext_net, int_net - - -class BgpTests(test_plugin.Ml2PluginV2TestCase, - BgpEntityCreationMixin): - fmt = 'json' - - def setup_parent(self): - self.l3_plugin = ('neutron.tests.unit.extensions.test_l3.' - 'TestL3NatAgentSchedulingServicePlugin') - super(BgpTests, self).setup_parent() - - def setUp(self): - super(BgpTests, self).setUp() - self.l3plugin = manager.NeutronManager.get_service_plugins().get( - p_const.L3_ROUTER_NAT) - self.bgp_plugin = bgp_plugin.BgpPlugin() - self.plugin = manager.NeutronManager.get_plugin() - self.l3plugin = manager.NeutronManager.get_service_plugins().get( - p_const.L3_ROUTER_NAT) - - @contextlib.contextmanager - def subnetpool_with_address_scope(self, ip_version, prefixes=None, - shared=False, admin=True, - name='test-pool', is_default_pool=False, - tenant_id=None, **kwargs): - if not tenant_id: - tenant_id = _uuid() - - scope_data = {'tenant_id': tenant_id, 'ip_version': ip_version, - 'shared': shared, 'name': name + '-scope'} - address_scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - address_scope_id = address_scope['id'] - pool_data = {'tenant_id': tenant_id, 'shared': shared, 'name': name, - 'address_scope_id': address_scope_id, - 'prefixes': prefixes, 'is_default': is_default_pool} - for key in kwargs: - pool_data[key] = kwargs[key] - - yield self.plugin.create_subnetpool(self.context, - {'subnetpool': pool_data}) - - @contextlib.contextmanager - def floatingip_from_address_scope_assoc(self, prefixes, - address_scope_id, - ext_prefixlen=24, - int_prefixlen=24): - pass - - def test_add_duplicate_bgp_peer_ip(self): - peer_ip = '192.168.1.10' - with self.bgp_peer(peer_ip=peer_ip) as peer1,\ - self.bgp_peer(peer_ip=peer_ip) as peer2,\ - self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - - with self.bgp_speaker(sp['ip_version'], 1234, - peers=[peer1['id']]) as speaker: - self.assertRaises(bgp.DuplicateBgpPeerIpException, - self.bgp_plugin.add_bgp_peer, - self.context, speaker['id'], - {'bgp_peer_id': peer2['id']}) - - def test_bgpspeaker_create(self): - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - speaker_name = 'test-speaker' - expected_values = [('ip_version', sp['ip_version']), - ('name', speaker_name)] - with self.bgp_speaker(sp['ip_version'], 1234, - name=speaker_name) as bgp_speaker: - for k, v in expected_values: - self.assertEqual(v, bgp_speaker[k]) - - def test_bgp_speaker_list(self): - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp1,\ - self.subnetpool_with_address_scope(4, - prefixes=['9.0.0.0/8']) as sp2: - with self.bgp_speaker(sp1['ip_version'], 1234, - name='speaker1'),\ - self.bgp_speaker(sp2['ip_version'], 4321, - name='speaker2'): - speakers = self.bgp_plugin.get_bgp_speakers(self.context) - self.assertEqual(2, len(speakers)) - - def test_bgp_speaker_update_local_as(self): - local_as_1 = 1234 - local_as_2 = 4321 - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], local_as_1) as speaker: - self.assertEqual(local_as_1, speaker['local_as']) - new_speaker = self.bgp_plugin.update_bgp_speaker( - self.context, - speaker['id'], - {'bgp_speaker': - {'local_as': local_as_2}}) - self.assertEqual(local_as_2, new_speaker['local_as']) - - def test_bgp_speaker_show_non_existent(self): - self.assertRaises(bgp.BgpSpeakerNotFound, - self.bgp_plugin.get_bgp_speaker, - self.context, _uuid()) - - def test_create_bgp_peer(self): - args = {'tenant_id': _uuid(), - 'remote_as': '1111', - 'peer_ip': '10.10.10.10', - 'auth_type': 'md5'} - with self.bgp_peer(tenant_id=args['tenant_id'], - remote_as=args['remote_as'], - peer_ip=args['peer_ip'], - auth_type='md5', - password='my-secret') as peer: - self.assertIsNone(peer.get('password')) - for key in args: - self.assertEqual(args[key], peer[key]) - - def test_bgp_peer_show_non_existent(self): - self.assertRaises(bgp.BgpPeerNotFound, - self.bgp_plugin.get_bgp_peer, - self.context, - 'unreal-bgp-peer-id') - - def test_associate_bgp_peer(self): - with self.bgp_peer() as peer,\ - self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234) as speaker: - self.bgp_plugin.add_bgp_peer(self.context, speaker['id'], - {'bgp_peer_id': peer['id']}) - new_speaker = self.bgp_plugin.get_bgp_speaker(self.context, - speaker['id']) - self.assertIn('peers', new_speaker) - self.assertIn(peer['id'], new_speaker['peers']) - self.assertEqual(1, len(new_speaker['peers'])) - - def test_remove_bgp_peer(self): - with self.bgp_peer() as peer,\ - self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234, - peers=[peer['id']]) as speaker: - self.bgp_plugin.remove_bgp_peer(self.context, speaker['id'], - {'bgp_peer_id': peer['id']}) - new_speaker = self.bgp_plugin.get_bgp_speaker(self.context, - speaker['id']) - self.assertIn('peers', new_speaker) - self.assertTrue(not new_speaker['peers']) - - def test_remove_unassociated_bgp_peer(self): - with self.bgp_peer() as peer,\ - self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234) as speaker: - self.assertRaises(bgp.BgpSpeakerPeerNotAssociated, - self.bgp_plugin.remove_bgp_peer, - self.context, - speaker['id'], - {'bgp_peer_id': peer['id']}) - - def test_remove_non_existent_bgp_peer(self): - bgp_peer_id = "imaginary" - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234) as speaker: - self.assertRaises(bgp.BgpSpeakerPeerNotAssociated, - self.bgp_plugin.remove_bgp_peer, - self.context, - speaker['id'], - {'bgp_peer_id': bgp_peer_id}) - - def test_add_non_existent_bgp_peer(self): - bgp_peer_id = "imaginary" - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234) as speaker: - self.assertRaises(bgp.BgpPeerNotFound, - self.bgp_plugin.add_bgp_peer, - self.context, - speaker['id'], - {'bgp_peer_id': bgp_peer_id}) - - def test_add_gateway_network(self): - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234) as speaker,\ - self.network() as network: - network_id = network['network']['id'] - self.bgp_plugin.add_gateway_network(self.context, - speaker['id'], - {'network_id': network_id}) - new_speaker = self.bgp_plugin.get_bgp_speaker(self.context, - speaker['id']) - self.assertEqual(1, len(new_speaker['networks'])) - self.assertTrue(network_id in new_speaker['networks']) - - def test_create_bgp_speaker_with_network(self): - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - network = self.plugin.create_network(self.context, - {'network': - {'name': 'test-net', - 'tenant_id': _uuid(), - 'admin_state_up': True, - 'shared': True}}) - with self.bgp_speaker(sp['ip_version'], 1234, - networks=[network['id']]) as speaker: - self.assertEqual(1, len(speaker['networks'])) - self.assertTrue(network['id'] in speaker['networks']) - - def test_remove_gateway_network(self): - with self.network() as network,\ - self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - network_id = network['network']['id'] - with self.bgp_speaker(sp['ip_version'], 1234, - networks=[network_id]) as speaker: - self.bgp_plugin.remove_gateway_network( - self.context, - speaker['id'], - {'network_id': network_id}) - new_speaker = self.bgp_plugin.get_bgp_speaker(self.context, - speaker['id']) - self.assertEqual(0, len(new_speaker['networks'])) - - def test_add_non_existent_gateway_network(self): - network_id = "imaginary" - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234) as speaker: - self.assertRaises(n_exc.NetworkNotFound, - self.bgp_plugin.add_gateway_network, - self.context, speaker['id'], - {'network_id': network_id}) - - def test_remove_non_existent_gateway_network(self): - network_id = "imaginary" - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234) as speaker: - self.assertRaises(bgp.BgpSpeakerNetworkNotAssociated, - self.bgp_plugin.remove_gateway_network, - self.context, speaker['id'], - {'network_id': network_id}) - - def test_add_gateway_network_two_bgp_speakers_same_scope(self): - with self.subnetpool_with_address_scope(4, - prefixes=['8.0.0.0/8']) as sp: - with self.bgp_speaker(sp['ip_version'], 1234) as speaker1,\ - self.bgp_speaker(sp['ip_version'], 4321) as speaker2,\ - self.network() as network: - network_id = network['network']['id'] - self.bgp_plugin.add_gateway_network(self.context, - speaker1['id'], - {'network_id': network_id}) - self.bgp_plugin.add_gateway_network(self.context, - speaker2['id'], - {'network_id': network_id}) - speaker1 = self.bgp_plugin.get_bgp_speaker(self.context, - speaker1['id']) - speaker2 = self.bgp_plugin.get_bgp_speaker(self.context, - speaker2['id']) - for speaker in [speaker1, speaker2]: - self.assertEqual(1, len(speaker['networks'])) - self.assertEqual(network_id, - speaker['networks'][0]) - - def test_create_bgp_peer_md5_auth_no_password(self): - bgp_peer = {'bgp_peer': {'auth_type': 'md5', 'password': None}} - self.assertRaises(bgp.InvalidBgpPeerMd5Authentication, - self.bgp_plugin.create_bgp_peer, - self.context, bgp_peer) - - def test__get_address_scope_ids_for_bgp_speaker(self): - prefixes1 = ['8.0.0.0/8'] - prefixes2 = ['9.0.0.0/8'] - prefixes3 = ['10.0.0.0/8'] - tenant_id = _uuid() - with self.bgp_speaker(4, 1234) as speaker,\ - self.subnetpool_with_address_scope(4, - prefixes=prefixes1, - tenant_id=tenant_id) as sp1,\ - self.subnetpool_with_address_scope(4, - prefixes=prefixes2, - tenant_id=tenant_id) as sp2,\ - self.subnetpool_with_address_scope(4, - prefixes=prefixes3, - tenant_id=tenant_id) as sp3,\ - self.network() as network1, self.network() as network2,\ - self.network() as network3: - network1_id = network1['network']['id'] - network2_id = network2['network']['id'] - network3_id = network3['network']['id'] - base_subnet_data = { - 'allocation_pools': constants.ATTR_NOT_SPECIFIED, - 'cidr': constants.ATTR_NOT_SPECIFIED, - 'prefixlen': constants.ATTR_NOT_SPECIFIED, - 'ip_version': 4, - 'enable_dhcp': True, - 'dns_nameservers': constants.ATTR_NOT_SPECIFIED, - 'host_routes': constants.ATTR_NOT_SPECIFIED} - subnet1_data = {'network_id': network1_id, - 'subnetpool_id': sp1['id'], - 'name': 'subnet1', - 'tenant_id': tenant_id} - subnet2_data = {'network_id': network2_id, - 'subnetpool_id': sp2['id'], - 'name': 'subnet2', - 'tenant_id': tenant_id} - subnet3_data = {'network_id': network3_id, - 'subnetpool_id': sp3['id'], - 'name': 'subnet2', - 'tenant_id': tenant_id} - for k in base_subnet_data: - subnet1_data[k] = base_subnet_data[k] - subnet2_data[k] = base_subnet_data[k] - subnet3_data[k] = base_subnet_data[k] - - self.plugin.create_subnet(self.context, {'subnet': subnet1_data}) - self.plugin.create_subnet(self.context, {'subnet': subnet2_data}) - self.plugin.create_subnet(self.context, {'subnet': subnet3_data}) - self.bgp_plugin.add_gateway_network(self.context, speaker['id'], - {'network_id': network1_id}) - self.bgp_plugin.add_gateway_network(self.context, speaker['id'], - {'network_id': network2_id}) - scopes = self.bgp_plugin._get_address_scope_ids_for_bgp_speaker( - self.context, - speaker['id']) - self.assertEqual(2, len(scopes)) - self.assertTrue(sp1['address_scope_id'] in scopes) - self.assertTrue(sp2['address_scope_id'] in scopes) - - def test_get_routes_by_bgp_speaker_binding(self): - gw_prefix = '172.16.10.0/24' - tenant_prefix = '10.10.10.0/24' - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, 'ip_version': 4, - 'shared': True, 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gw_prefix, - tenant_prefix=tenant_prefix, - address_scope=scope) as res: - router, ext_net, int_net = res - ext_gw_info = router['external_gateway_info'] - gw_net_id = ext_net['network']['id'] - with self.bgp_speaker(4, 1234, - networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - routes = self.bgp_plugin.get_routes_by_bgp_speaker_binding( - self.context, - bgp_speaker_id, - gw_net_id) - routes = list(routes) - next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address'] - self.assertEqual(1, len(routes)) - self.assertEqual(tenant_prefix, routes[0]['destination']) - self.assertEqual(next_hop, routes[0]['next_hop']) - - def test_get_routes_by_binding_network(self): - gw_prefix = '172.16.10.0/24' - tenant_prefix = '10.10.10.0/24' - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, 'ip_version': 4, - 'shared': True, 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gw_prefix, - tenant_prefix=tenant_prefix, - address_scope=scope) as res: - router, ext_net, int_net = res - ext_gw_info = router['external_gateway_info'] - gw_net_id = ext_net['network']['id'] - with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - routes = self.bgp_plugin.get_routes_by_bgp_speaker_binding( - self.context, - bgp_speaker_id, - gw_net_id) - routes = list(routes) - next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address'] - self.assertEqual(1, len(routes)) - self.assertEqual(tenant_prefix, routes[0]['destination']) - self.assertEqual(next_hop, routes[0]['next_hop']) - - def _advertised_routes_by_bgp_speaker(self, - bgp_speaker_ip_version, - local_as, - tenant_cidr, - gateway_cidr, - fip_routes=True, - router_distributed=False): - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, - 'ip_version': bgp_speaker_ip_version, - 'shared': True, - 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gateway_cidr, - tenant_prefix=tenant_cidr, - address_scope=scope, - distributed=router_distributed) as res: - router, ext_net, int_net = res - gw_net_id = ext_net['network']['id'] - with self.bgp_speaker( - bgp_speaker_ip_version, - local_as, - networks=[gw_net_id], - advertise_fip_host_routes=fip_routes) as speaker: - routes = self.bgp_plugin.get_advertised_routes( - self.context, - speaker['id']) - return routes['advertised_routes'] - - def test__tenant_prefixes_by_router_no_gateway_port(self): - with self.network() as net1, self.network() as net2,\ - self.subnetpool_with_address_scope(6, tenant_id='test-tenant', - prefixes=['2001:db8::/63']) as pool: - subnetpool_id = pool['id'] - with self.subnet(network=net1, - cidr=None, - subnetpool_id=subnetpool_id, - ip_version=6) as ext_subnet,\ - self.subnet(network=net2, - cidr=None, - subnetpool_id=subnetpool_id, - ip_version=6) as int_subnet,\ - self.router() as router: - - router_id = router['id'] - int_subnet_id = int_subnet['subnet']['id'] - ext_subnet_id = ext_subnet['subnet']['id'] - self.l3plugin.add_router_interface(self.context, - router_id, - {'subnet_id': - int_subnet_id}) - self.l3plugin.add_router_interface(self.context, - router_id, - {'subnet_id': - ext_subnet_id}) - with self.bgp_speaker(6, 1234) as speaker: - bgp_speaker_id = speaker['id'] - cidrs = list(self.bgp_plugin._tenant_prefixes_by_router( - self.context, - router_id, - bgp_speaker_id)) - self.assertFalse(cidrs) - - def test_get_ipv6_tenant_subnet_routes_by_bgp_speaker_ipv6(self): - tenant_cidr = '2001:db8::/64' - binding_cidr = '2001:ab8::/64' - routes = self._advertised_routes_by_bgp_speaker(6, 1234, tenant_cidr, - binding_cidr) - self.assertEqual(1, len(routes)) - dest_prefix = routes[0]['destination'] - next_hop = routes[0]['next_hop'] - self.assertEqual(tenant_cidr, dest_prefix) - self.assertTrue(netaddr.IPSet([binding_cidr]).__contains__(next_hop)) - - def test_get_ipv4_tenant_subnet_routes_by_bgp_speaker_ipv4(self): - tenant_cidr = '172.16.10.0/24' - binding_cidr = '20.10.1.0/24' - routes = self._advertised_routes_by_bgp_speaker(4, 1234, tenant_cidr, - binding_cidr) - routes = list(routes) - self.assertEqual(1, len(routes)) - dest_prefix = routes[0]['destination'] - next_hop = routes[0]['next_hop'] - self.assertEqual(tenant_cidr, dest_prefix) - self.assertTrue(netaddr.IPSet([binding_cidr]).__contains__(next_hop)) - - def test_get_ipv4_tenant_subnet_routes_by_bgp_speaker_dvr_router(self): - tenant_cidr = '172.16.10.0/24' - binding_cidr = '20.10.1.0/24' - routes = self._advertised_routes_by_bgp_speaker( - 4, - 1234, - tenant_cidr, - binding_cidr, - router_distributed=True) - routes = list(routes) - self.assertEqual(1, len(routes)) - - def test_all_routes_by_bgp_speaker_different_tenant_address_scope(self): - binding_cidr = '2001:db8::/64' - tenant_cidr = '2002:ab8::/64' - with self.subnetpool_with_address_scope(6, tenant_id='test-tenant', - prefixes=[binding_cidr]) as ext_pool,\ - self.subnetpool_with_address_scope(6, tenant_id='test-tenant', - prefixes=[tenant_cidr]) as int_pool,\ - self.network() as ext_net, self.network() as int_net: - gw_net_id = ext_net['network']['id'] - ext_pool_id = ext_pool['id'] - int_pool_id = int_pool['id'] - self._update('networks', gw_net_id, - {'network': {external_net.EXTERNAL: True}}) - with self.subnet(cidr=None, - subnetpool_id=ext_pool_id, - network=ext_net, - ip_version=6) as ext_subnet,\ - self.subnet(cidr=None, - subnetpool_id=int_pool_id, - network=int_net, - ip_version=6) as int_subnet,\ - self.router() as router: - router_id = router['id'] - int_subnet_id = int_subnet['subnet']['id'] - ext_subnet_id = ext_subnet['subnet']['id'] - self.l3plugin.add_router_interface(self.context, - router_id, - {'subnet_id': - int_subnet_id}) - self.l3plugin.add_router_interface(self.context, - router_id, - {'subnet_id': - ext_subnet_id}) - with self.bgp_speaker(6, 1234, - networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - cidrs = self.bgp_plugin.get_routes_by_bgp_speaker_id( - self.context, - bgp_speaker_id) - self.assertEqual(0, len(list(cidrs))) - - def test__get_routes_by_router_with_fip(self): - gw_prefix = '172.16.10.0/24' - tenant_prefix = '10.10.10.0/24' - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, 'ip_version': 4, - 'shared': True, 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gw_prefix, - tenant_prefix=tenant_prefix, - address_scope=scope) as res: - router, ext_net, int_net = res - ext_gw_info = router['external_gateway_info'] - gw_net_id = ext_net['network']['id'] - tenant_net_id = int_net['network']['id'] - fixed_port_data = {'port': - {'name': 'test', - 'network_id': tenant_net_id, - 'tenant_id': tenant_id, - 'admin_state_up': True, - 'device_id': _uuid(), - 'device_owner': 'compute:nova', - 'mac_address': constants.ATTR_NOT_SPECIFIED, - 'fixed_ips': constants.ATTR_NOT_SPECIFIED}} - fixed_port = self.plugin.create_port(self.context, - fixed_port_data) - fip_data = {'floatingip': {'floating_network_id': gw_net_id, - 'tenant_id': tenant_id, - 'port_id': fixed_port['id']}} - fip = self.l3plugin.create_floatingip(self.context, fip_data) - fip_prefix = fip['floating_ip_address'] + '/32' - with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - routes = self.bgp_plugin._get_routes_by_router(self.context, - router['id']) - routes = routes[bgp_speaker_id] - next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address'] - self.assertEqual(2, len(routes)) - tenant_prefix_found = False - fip_prefix_found = False - for route in routes: - self.assertEqual(next_hop, route['next_hop']) - if route['destination'] == tenant_prefix: - tenant_prefix_found = True - if route['destination'] == fip_prefix: - fip_prefix_found = True - self.assertTrue(tenant_prefix_found) - self.assertTrue(fip_prefix_found) - - def test_get_routes_by_bgp_speaker_id_with_fip(self): - gw_prefix = '172.16.10.0/24' - tenant_prefix = '10.10.10.0/24' - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, 'ip_version': 4, - 'shared': True, 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gw_prefix, - tenant_prefix=tenant_prefix, - address_scope=scope) as res: - router, ext_net, int_net = res - ext_gw_info = router['external_gateway_info'] - gw_net_id = ext_net['network']['id'] - tenant_net_id = int_net['network']['id'] - fixed_port_data = {'port': - {'name': 'test', - 'network_id': tenant_net_id, - 'tenant_id': tenant_id, - 'admin_state_up': True, - 'device_id': _uuid(), - 'device_owner': 'compute:nova', - 'mac_address': constants.ATTR_NOT_SPECIFIED, - 'fixed_ips': constants.ATTR_NOT_SPECIFIED}} - fixed_port = self.plugin.create_port(self.context, - fixed_port_data) - fip_data = {'floatingip': {'floating_network_id': gw_net_id, - 'tenant_id': tenant_id, - 'port_id': fixed_port['id']}} - fip = self.l3plugin.create_floatingip(self.context, fip_data) - fip_prefix = fip['floating_ip_address'] + '/32' - with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - routes = self.bgp_plugin.get_routes_by_bgp_speaker_id( - self.context, - bgp_speaker_id) - routes = list(routes) - next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address'] - self.assertEqual(2, len(routes)) - tenant_prefix_found = False - fip_prefix_found = False - for route in routes: - self.assertEqual(next_hop, route['next_hop']) - if route['destination'] == tenant_prefix: - tenant_prefix_found = True - if route['destination'] == fip_prefix: - fip_prefix_found = True - self.assertTrue(tenant_prefix_found) - self.assertTrue(fip_prefix_found) - - def test_get_routes_by_bgp_speaker_id_with_fip_dvr(self): - gw_prefix = '172.16.10.0/24' - tenant_prefix = '10.10.10.0/24' - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, 'ip_version': 4, - 'shared': True, 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gw_prefix, - tenant_prefix=tenant_prefix, - address_scope=scope, - distributed=True) as res: - router, ext_net, int_net = res - ext_gw_info = router['external_gateway_info'] - gw_net_id = ext_net['network']['id'] - tenant_net_id = int_net['network']['id'] - fixed_port_data = {'port': - {'name': 'test', - 'network_id': tenant_net_id, - 'tenant_id': tenant_id, - 'admin_state_up': True, - 'device_id': _uuid(), - 'device_owner': 'compute:nova', - 'mac_address': constants.ATTR_NOT_SPECIFIED, - 'fixed_ips': constants.ATTR_NOT_SPECIFIED, - portbindings.HOST_ID: 'test-host'}} - fixed_port = self.plugin.create_port(self.context, - fixed_port_data) - self.plugin._create_or_update_agent(self.context, - {'agent_type': 'L3 agent', - 'host': 'test-host', - 'binary': 'neutron-l3-agent', - 'topic': 'test'}) - fip_gw = self.l3plugin.create_fip_agent_gw_port_if_not_exists( - self.context, - gw_net_id, - 'test-host') - fip_data = {'floatingip': {'floating_network_id': gw_net_id, - 'tenant_id': tenant_id, - 'port_id': fixed_port['id']}} - fip = self.l3plugin.create_floatingip(self.context, fip_data) - fip_prefix = fip['floating_ip_address'] + '/32' - with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - routes = self.bgp_plugin.get_routes_by_bgp_speaker_id( - self.context, - bgp_speaker_id) - routes = list(routes) - cvr_gw_ip = ext_gw_info['external_fixed_ips'][0]['ip_address'] - dvr_gw_ip = fip_gw['fixed_ips'][0]['ip_address'] - self.assertEqual(2, len(routes)) - tenant_route_verified = False - fip_route_verified = False - for route in routes: - if route['destination'] == tenant_prefix: - self.assertEqual(cvr_gw_ip, route['next_hop']) - tenant_route_verified = True - if route['destination'] == fip_prefix: - self.assertEqual(dvr_gw_ip, route['next_hop']) - fip_route_verified = True - self.assertTrue(tenant_route_verified) - self.assertTrue(fip_route_verified) - - def test__get_dvr_fip_host_routes_by_binding(self): - gw_prefix = '172.16.10.0/24' - tenant_prefix = '10.10.10.0/24' - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, 'ip_version': 4, - 'shared': True, 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gw_prefix, - tenant_prefix=tenant_prefix, - address_scope=scope, - distributed=True) as res: - router, ext_net, int_net = res - gw_net_id = ext_net['network']['id'] - tenant_net_id = int_net['network']['id'] - fixed_port_data = {'port': - {'name': 'test', - 'network_id': tenant_net_id, - 'tenant_id': tenant_id, - 'admin_state_up': True, - 'device_id': _uuid(), - 'device_owner': 'compute:nova', - 'mac_address': constants.ATTR_NOT_SPECIFIED, - 'fixed_ips': constants.ATTR_NOT_SPECIFIED, - portbindings.HOST_ID: 'test-host'}} - fixed_port = self.plugin.create_port(self.context, - fixed_port_data) - self.plugin._create_or_update_agent(self.context, - {'agent_type': 'L3 agent', - 'host': 'test-host', - 'binary': 'neutron-l3-agent', - 'topic': 'test'}) - fip_gw = self.l3plugin.create_fip_agent_gw_port_if_not_exists( - self.context, - gw_net_id, - 'test-host') - fip_data = {'floatingip': {'floating_network_id': gw_net_id, - 'tenant_id': tenant_id, - 'port_id': fixed_port['id']}} - fip = self.l3plugin.create_floatingip(self.context, fip_data) - fip_prefix = fip['floating_ip_address'] + '/32' - with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - routes = self.bgp_plugin._get_dvr_fip_host_routes_by_binding( - self.context, - gw_net_id, - bgp_speaker_id) - routes = list(routes) - dvr_gw_ip = fip_gw['fixed_ips'][0]['ip_address'] - self.assertEqual(1, len(routes)) - self.assertEqual(dvr_gw_ip, routes[0]['next_hop']) - self.assertEqual(fip_prefix, routes[0]['destination']) - - def test__get_dvr_fip_host_routes_by_router(self): - gw_prefix = '172.16.10.0/24' - tenant_prefix = '10.10.10.0/24' - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, 'ip_version': 4, - 'shared': True, 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gw_prefix, - tenant_prefix=tenant_prefix, - address_scope=scope, - distributed=True) as res: - router, ext_net, int_net = res - gw_net_id = ext_net['network']['id'] - tenant_net_id = int_net['network']['id'] - fixed_port_data = {'port': - {'name': 'test', - 'network_id': tenant_net_id, - 'tenant_id': tenant_id, - 'admin_state_up': True, - 'device_id': _uuid(), - 'device_owner': 'compute:nova', - 'mac_address': constants.ATTR_NOT_SPECIFIED, - 'fixed_ips': constants.ATTR_NOT_SPECIFIED, - portbindings.HOST_ID: 'test-host'}} - fixed_port = self.plugin.create_port(self.context, - fixed_port_data) - self.plugin._create_or_update_agent(self.context, - {'agent_type': 'L3 agent', - 'host': 'test-host', - 'binary': 'neutron-l3-agent', - 'topic': 'test'}) - fip_gw = self.l3plugin.create_fip_agent_gw_port_if_not_exists( - self.context, - gw_net_id, - 'test-host') - fip_data = {'floatingip': {'floating_network_id': gw_net_id, - 'tenant_id': tenant_id, - 'port_id': fixed_port['id']}} - fip = self.l3plugin.create_floatingip(self.context, fip_data) - fip_prefix = fip['floating_ip_address'] + '/32' - with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - routes = self.bgp_plugin._get_dvr_fip_host_routes_by_router( - self.context, - bgp_speaker_id, - router['id']) - routes = list(routes) - dvr_gw_ip = fip_gw['fixed_ips'][0]['ip_address'] - self.assertEqual(1, len(routes)) - self.assertEqual(dvr_gw_ip, routes[0]['next_hop']) - self.assertEqual(fip_prefix, routes[0]['destination']) - - def test_get_routes_by_bgp_speaker_binding_with_fip(self): - gw_prefix = '172.16.10.0/24' - tenant_prefix = '10.10.10.0/24' - tenant_id = _uuid() - scope_data = {'tenant_id': tenant_id, 'ip_version': 4, - 'shared': True, 'name': 'bgp-scope'} - scope = self.plugin.create_address_scope( - self.context, - {'address_scope': scope_data}) - with self.router_with_external_and_tenant_networks( - tenant_id=tenant_id, - gw_prefix=gw_prefix, - tenant_prefix=tenant_prefix, - address_scope=scope) as res: - router, ext_net, int_net = res - ext_gw_info = router['external_gateway_info'] - gw_net_id = ext_net['network']['id'] - tenant_net_id = int_net['network']['id'] - fixed_port_data = {'port': - {'name': 'test', - 'network_id': tenant_net_id, - 'tenant_id': tenant_id, - 'admin_state_up': True, - 'device_id': _uuid(), - 'device_owner': 'compute:nova', - 'mac_address': constants.ATTR_NOT_SPECIFIED, - 'fixed_ips': constants.ATTR_NOT_SPECIFIED}} - fixed_port = self.plugin.create_port(self.context, - fixed_port_data) - fip_data = {'floatingip': {'floating_network_id': gw_net_id, - 'tenant_id': tenant_id, - 'port_id': fixed_port['id']}} - fip = self.l3plugin.create_floatingip(self.context, fip_data) - fip_prefix = fip['floating_ip_address'] + '/32' - with self.bgp_speaker(4, 1234, networks=[gw_net_id]) as speaker: - bgp_speaker_id = speaker['id'] - routes = self.bgp_plugin.get_routes_by_bgp_speaker_binding( - self.context, - bgp_speaker_id, - gw_net_id) - routes = list(routes) - next_hop = ext_gw_info['external_fixed_ips'][0]['ip_address'] - self.assertEqual(2, len(routes)) - tenant_prefix_found = False - fip_prefix_found = False - for route in routes: - self.assertEqual(next_hop, route['next_hop']) - if route['destination'] == tenant_prefix: - tenant_prefix_found = True - if route['destination'] == fip_prefix: - fip_prefix_found = True - self.assertTrue(tenant_prefix_found) - self.assertTrue(fip_prefix_found) - - def test__bgp_speakers_for_gateway_network_by_ip_version(self): - with self.network() as ext_net, self.bgp_speaker(6, 1234) as s1,\ - self.bgp_speaker(6, 4321) as s2: - gw_net_id = ext_net['network']['id'] - self._update('networks', gw_net_id, - {'network': {external_net.EXTERNAL: True}}) - self.bgp_plugin.add_gateway_network(self.context, - s1['id'], - {'network_id': gw_net_id}) - self.bgp_plugin.add_gateway_network(self.context, - s2['id'], - {'network_id': gw_net_id}) - speakers = self.bgp_plugin._bgp_speakers_for_gw_network_by_family( - self.context, - gw_net_id, - 6) - self.assertEqual(2, len(speakers)) - - def test__bgp_speakers_for_gateway_network_by_ip_version_no_binding(self): - with self.network() as ext_net, self.bgp_speaker(6, 1234),\ - self.bgp_speaker(6, 4321): - gw_net_id = ext_net['network']['id'] - self._update('networks', gw_net_id, - {'network': {external_net.EXTERNAL: True}}) - speakers = self.bgp_plugin._bgp_speakers_for_gw_network_by_family( - self.context, - gw_net_id, - 6) - self.assertTrue(not speakers) diff --git a/neutron/tests/unit/db/test_bgp_dragentscheduler_db.py b/neutron/tests/unit/db/test_bgp_dragentscheduler_db.py deleted file mode 100644 index 18b2cf549ec..00000000000 --- a/neutron/tests/unit/db/test_bgp_dragentscheduler_db.py +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P. -# -# 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_utils import importutils - -from neutron.api.v2 import attributes -from neutron import context -from neutron.db import bgp_db -from neutron.db import bgp_dragentscheduler_db as bgp_dras_db -from neutron.extensions import agent -from neutron.extensions import bgp -from neutron.extensions import bgp_dragentscheduler as bgp_dras_ext -from neutron import manager -from neutron.tests.unit.db import test_bgp_db -from neutron.tests.unit.db import test_db_base_plugin_v2 as test_db_base_plugin -from neutron.tests.unit.extensions import test_agent - -from webob import exc - - -class BgpDrSchedulerTestExtensionManager(object): - - def get_resources(self): - attributes.RESOURCE_ATTRIBUTE_MAP.update( - agent.RESOURCE_ATTRIBUTE_MAP) - resources = agent.Agent.get_resources() - resources.extend(bgp_dras_ext.Bgp_dragentscheduler.get_resources()) - return resources - - def get_actions(self): - return [] - - def get_request_extensions(self): - return [] - - -class TestBgpDrSchedulerPlugin(bgp_db.BgpDbMixin, - bgp_dras_db.BgpDrAgentSchedulerDbMixin): - - bgp_drscheduler = importutils.import_object( - cfg.CONF.bgp_drscheduler_driver) - - supported_extension_aliases = ["bgp_dragent_scheduler"] - - def get_plugin_description(self): - return ("BGP dynamic routing service Plugin test class that test " - "BGP speaker functionality, with scheduler.") - - -class BgpDrSchedulingTestCase(test_agent.AgentDBTestMixIn, - test_bgp_db.BgpEntityCreationMixin): - - def test_schedule_bgp_speaker(self): - """Test happy path over full scheduling cycle.""" - with self.bgp_speaker(4, 1234) as ri: - bgp_speaker_id = ri['id'] - self._register_bgp_dragent(host='host1') - agent = self._list('agents')['agents'][0] - agent_id = agent['id'] - - data = {'bgp_speaker_id': bgp_speaker_id} - req = self.new_create_request('agents', data, self.fmt, - agent_id, 'bgp-drinstances') - res = req.get_response(self.ext_api) - self.assertEqual(exc.HTTPCreated.code, res.status_int) - - req_show = self.new_show_request('agents', agent_id, self.fmt, - 'bgp-drinstances') - res = req_show.get_response(self.ext_api) - self.assertEqual(exc.HTTPOk.code, res.status_int) - res = self.deserialize(self.fmt, res) - self.assertIn('bgp_speakers', res) - self.assertTrue(bgp_speaker_id, - res['bgp_speakers'][0]['id']) - - req = self.new_delete_request('agents', - agent_id, - self.fmt, - 'bgp-drinstances', - bgp_speaker_id) - res = req.get_response(self.ext_api) - self.assertEqual(exc.HTTPNoContent.code, res.status_int) - - res = req_show.get_response(self.ext_api) - self.assertEqual(exc.HTTPOk.code, res.status_int) - res = self.deserialize(self.fmt, res) - self.assertIn('bgp_speakers', res) - self.assertEqual([], res['bgp_speakers']) - - def test_schedule_bgp_speaker_on_invalid_agent(self): - """Test error while scheduling BGP speaker on an invalid agent.""" - with self.bgp_speaker(4, 1234) as ri: - bgp_speaker_id = ri['id'] - self._register_l3_agent(host='host1') # Register wrong agent - agent = self._list('agents')['agents'][0] - data = {'bgp_speaker_id': bgp_speaker_id} - req = self.new_create_request( - 'agents', data, self.fmt, - agent['id'], 'bgp-drinstances') - res = req.get_response(self.ext_api) - - # Raises an AgentNotFound exception if the agent is invalid - self.assertEqual(exc.HTTPNotFound.code, res.status_int) - - def test_schedule_bgp_speaker_twice_on_same_agent(self): - """Test error if a BGP speaker is scheduled twice on same agent""" - with self.bgp_speaker(4, 1234) as ri: - bgp_speaker_id = ri['id'] - self._register_bgp_dragent(host='host1') - agent = self._list('agents')['agents'][0] - data = {'bgp_speaker_id': bgp_speaker_id} - req = self.new_create_request( - 'agents', data, self.fmt, - agent['id'], 'bgp-drinstances') - res = req.get_response(self.ext_api) - self.assertEqual(exc.HTTPCreated.code, res.status_int) - - # Try second time, should raise conflict - res = req.get_response(self.ext_api) - self.assertEqual(exc.HTTPConflict.code, res.status_int) - - def test_schedule_bgp_speaker_on_two_different_agents(self): - """Test that a BGP speaker can be associated to two agents.""" - with self.bgp_speaker(4, 1234) as ri: - bgp_speaker_id = ri['id'] - self._register_bgp_dragent(host='host1') - self._register_bgp_dragent(host='host2') - data = {'bgp_speaker_id': bgp_speaker_id} - - agent1 = self._list('agents')['agents'][0] - req = self.new_create_request( - 'agents', data, self.fmt, - agent1['id'], 'bgp-drinstances') - res = req.get_response(self.ext_api) - self.assertEqual(exc.HTTPCreated.code, res.status_int) - - agent2 = self._list('agents')['agents'][1] - req = self.new_create_request( - 'agents', data, self.fmt, - agent2['id'], 'bgp-drinstances') - res = req.get_response(self.ext_api) - self.assertEqual(exc.HTTPCreated.code, res.status_int) - - def test_schedule_multi_bgp_speaker_on_one_dragent(self): - """Test only one BGP speaker can be associated to one dragent.""" - with self.bgp_speaker(4, 1) as ri1, self.bgp_speaker(4, 2) as ri2: - self._register_bgp_dragent(host='host1') - - agent = self._list('agents')['agents'][0] - data = {'bgp_speaker_id': ri1['id']} - req = self.new_create_request( - 'agents', data, self.fmt, - agent['id'], 'bgp-drinstances') - res = req.get_response(self.ext_api) - self.assertEqual(exc.HTTPCreated.code, res.status_int) - - data = {'bgp_speaker_id': ri2['id']} - req = self.new_create_request( - 'agents', data, self.fmt, - agent['id'], 'bgp-drinstances') - res = req.get_response(self.ext_api) - self.assertEqual(exc.HTTPConflict.code, res.status_int) - - def test_non_scheduled_bgp_speaker_binding_removal(self): - """Test exception while removing an invalid binding.""" - with self.bgp_speaker(4, 1234) as ri1: - self._register_bgp_dragent(host='host1') - agent = self._list('agents')['agents'][0] - agent_id = agent['id'] - self.assertRaises(bgp_dras_ext.DrAgentNotHostingBgpSpeaker, - self.bgp_plugin.remove_bgp_speaker_from_dragent, - self.context, agent_id, ri1['id']) - - -class BgpDrPluginSchedulerTests(test_db_base_plugin.NeutronDbPluginV2TestCase, - BgpDrSchedulingTestCase): - - def setUp(self, plugin=None, ext_mgr=None, service_plugins=None): - if not plugin: - plugin = ('neutron.tests.unit.db.' - 'test_bgp_dragentscheduler_db.TestBgpDrSchedulerPlugin') - if not service_plugins: - service_plugins = {bgp.BGP_EXT_ALIAS: - 'neutron.services.bgp.bgp_plugin.BgpPlugin'} - - ext_mgr = ext_mgr or BgpDrSchedulerTestExtensionManager() - super(BgpDrPluginSchedulerTests, self).setUp( - plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins) - self.bgp_plugin = manager.NeutronManager.get_service_plugins().get( - bgp.BGP_EXT_ALIAS) - self.context = context.get_admin_context() diff --git a/neutron/tests/unit/extensions/test_agent.py b/neutron/tests/unit/extensions/test_agent.py index f61a4072905..405f672b9e3 100644 --- a/neutron/tests/unit/extensions/test_agent.py +++ b/neutron/tests/unit/extensions/test_agent.py @@ -126,9 +126,6 @@ class AgentDBTestMixIn(object): def _register_l3_agent(self, host): helpers.register_l3_agent(host) - def _register_bgp_dragent(self, host): - helpers.register_bgp_dragent(host) - class AgentDBTestCase(AgentDBTestMixIn, test_db_base_plugin_v2.NeutronDbPluginV2TestCase): diff --git a/neutron/tests/unit/extensions/test_bgp_dragentscheduler.py b/neutron/tests/unit/extensions/test_bgp_dragentscheduler.py deleted file mode 100644 index 3e3fbc7ade3..00000000000 --- a/neutron/tests/unit/extensions/test_bgp_dragentscheduler.py +++ /dev/null @@ -1,224 +0,0 @@ -# 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. - -import testscenarios - -from oslo_utils import importutils - -from neutron import context -from neutron.db import bgp_db -from neutron.db import bgp_dragentscheduler_db as bgp_dras_db -from neutron.services.bgp.scheduler import bgp_dragent_scheduler as bgp_dras -from neutron.tests.common import helpers -from neutron.tests.unit import testlib_api - -# Required to generate tests from scenarios. Not compatible with nose. -load_tests = testscenarios.load_tests_apply_scenarios - - -class TestBgpDrAgentSchedulerBaseTestCase(testlib_api.SqlTestCase): - - def setUp(self): - super(TestBgpDrAgentSchedulerBaseTestCase, self).setUp() - self.ctx = context.get_admin_context() - self.bgp_speaker = {'id': 'foo_bgp_speaker_id'} - self.bgp_speaker_id = 'foo_bgp_speaker_id' - self._save_bgp_speaker(self.bgp_speaker_id) - - def _create_and_set_agents_down(self, hosts, down_agent_count=0, - admin_state_up=True): - agents = [] - for i, host in enumerate(hosts): - is_alive = i >= down_agent_count - agents.append(helpers.register_bgp_dragent( - host, - admin_state_up=admin_state_up, - alive=is_alive)) - return agents - - def _save_bgp_speaker(self, bgp_speaker_id): - cls = bgp_db.BgpDbMixin() - bgp_speaker_body = {'bgp_speaker': {'ip_version': '4', - 'name': 'test-speaker', - 'local_as': '123', - 'advertise_floating_ip_host_routes': '0', - 'advertise_tenant_networks': '0', - 'peers': [], - 'networks': []}} - cls._save_bgp_speaker(self.ctx, bgp_speaker_body, uuid=bgp_speaker_id) - - def _test_schedule_bind_bgp_speaker(self, agents, bgp_speaker_id): - scheduler = bgp_dras.ChanceScheduler() - scheduler.resource_filter.bind(self.ctx, agents, bgp_speaker_id) - results = self.ctx.session.query( - bgp_dras_db.BgpSpeakerDrAgentBinding).filter_by( - bgp_speaker_id=bgp_speaker_id).all() - - for result in results: - self.assertEqual(bgp_speaker_id, result.bgp_speaker_id) - - -class TestBgpDrAgentScheduler(TestBgpDrAgentSchedulerBaseTestCase, - bgp_db.BgpDbMixin): - - def test_schedule_bind_bgp_speaker_single_agent(self): - agents = self._create_and_set_agents_down(['host-a']) - self._test_schedule_bind_bgp_speaker(agents, self.bgp_speaker_id) - - def test_schedule_bind_bgp_speaker_multi_agents(self): - agents = self._create_and_set_agents_down(['host-a', 'host-b']) - self._test_schedule_bind_bgp_speaker(agents, self.bgp_speaker_id) - - -class TestBgpAgentFilter(TestBgpDrAgentSchedulerBaseTestCase, - bgp_db.BgpDbMixin, - bgp_dras_db.BgpDrAgentSchedulerDbMixin): - - def setUp(self): - super(TestBgpAgentFilter, self).setUp() - self.bgp_drscheduler = importutils.import_object( - 'neutron.services.bgp.scheduler' - '.bgp_dragent_scheduler.ChanceScheduler' - ) - self.plugin = self - - def _test_filter_agents_helper(self, bgp_speaker, - expected_filtered_dragent_ids=None, - expected_num_agents=1): - if not expected_filtered_dragent_ids: - expected_filtered_dragent_ids = [] - - filtered_agents = ( - self.plugin.bgp_drscheduler.resource_filter.filter_agents( - self.plugin, self.ctx, bgp_speaker)) - self.assertEqual(expected_num_agents, - filtered_agents['n_agents']) - actual_filtered_dragent_ids = [ - agent.id for agent in filtered_agents['hostable_agents']] - self.assertEqual(len(expected_filtered_dragent_ids), - len(actual_filtered_dragent_ids)) - for filtered_agent_id in actual_filtered_dragent_ids: - self.assertIn(filtered_agent_id, expected_filtered_dragent_ids) - - def test_filter_agents_single_agent(self): - agents = self._create_and_set_agents_down(['host-a']) - expected_filtered_dragent_ids = [agents[0].id] - self._test_filter_agents_helper( - self.bgp_speaker, - expected_filtered_dragent_ids=expected_filtered_dragent_ids) - - def test_filter_agents_no_agents(self): - expected_filtered_dragent_ids = [] - self._test_filter_agents_helper( - self.bgp_speaker, - expected_filtered_dragent_ids=expected_filtered_dragent_ids, - expected_num_agents=0) - - def test_filter_agents_two_agents(self): - agents = self._create_and_set_agents_down(['host-a', 'host-b']) - expected_filtered_dragent_ids = [agent.id for agent in agents] - self._test_filter_agents_helper( - self.bgp_speaker, - expected_filtered_dragent_ids=expected_filtered_dragent_ids) - - def test_filter_agents_agent_already_scheduled(self): - agents = self._create_and_set_agents_down(['host-a', 'host-b']) - self._test_schedule_bind_bgp_speaker([agents[0]], self.bgp_speaker_id) - self._test_filter_agents_helper(self.bgp_speaker, - expected_num_agents=0) - - def test_filter_agents_multiple_agents_bgp_speakers(self): - agents = self._create_and_set_agents_down(['host-a', 'host-b']) - self._test_schedule_bind_bgp_speaker([agents[0]], self.bgp_speaker_id) - bgp_speaker = {'id': 'bar-speaker-id'} - self._save_bgp_speaker(bgp_speaker['id']) - expected_filtered_dragent_ids = [agents[1].id] - self._test_filter_agents_helper( - bgp_speaker, - expected_filtered_dragent_ids=expected_filtered_dragent_ids) - - -class TestAutoScheduleBgpSpeakers(TestBgpDrAgentSchedulerBaseTestCase): - """Unit test scenarios for schedule_unscheduled_bgp_speakers. - - bgp_speaker_present - BGP speaker is present or not - - scheduled_already - BGP speaker is already scheduled to the agent or not - - agent_down - BGP DRAgent is down or alive - - valid_host - If true, then an valid host is passed to schedule BGP speaker, - else an invalid host is passed. - """ - scenarios = [ - ('BGP speaker present', - dict(bgp_speaker_present=True, - scheduled_already=False, - agent_down=False, - valid_host=True, - expected_result=True)), - - ('No BGP speaker', - dict(bgp_speaker_present=False, - scheduled_already=False, - agent_down=False, - valid_host=True, - expected_result=False)), - - ('BGP speaker already scheduled', - dict(bgp_speaker_present=True, - scheduled_already=True, - agent_down=False, - valid_host=True, - expected_result=False)), - - ('BGP DR agent down', - dict(bgp_speaker_present=True, - scheduled_already=False, - agent_down=True, - valid_host=False, - expected_result=False)), - - ('Invalid host', - dict(bgp_speaker_present=True, - scheduled_already=False, - agent_down=False, - valid_host=False, - expected_result=False)), - ] - - def test_auto_schedule_bgp_speaker(self): - scheduler = bgp_dras.ChanceScheduler() - if self.bgp_speaker_present: - down_agent_count = 1 if self.agent_down else 0 - agents = self._create_and_set_agents_down( - ['host-a'], down_agent_count=down_agent_count) - if self.scheduled_already: - self._test_schedule_bind_bgp_speaker(agents, - self.bgp_speaker_id) - - expected_hosted_agents = (1 if self.bgp_speaker_present and - self.valid_host else 0) - host = "host-a" if self.valid_host else "host-b" - observed_ret_value = scheduler.schedule_unscheduled_bgp_speakers( - self.ctx, host) - self.assertEqual(self.expected_result, observed_ret_value) - hosted_agents = self.ctx.session.query( - bgp_dras_db.BgpSpeakerDrAgentBinding).all() - self.assertEqual(expected_hosted_agents, len(hosted_agents)) diff --git a/neutron/tests/unit/services/bgp/__init__.py b/neutron/tests/unit/services/bgp/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/unit/services/bgp/agent/__init__.py b/neutron/tests/unit/services/bgp/agent/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/unit/services/bgp/agent/test_bgp_dragent.py b/neutron/tests/unit/services/bgp/agent/test_bgp_dragent.py deleted file mode 100644 index 09c1f853dde..00000000000 --- a/neutron/tests/unit/services/bgp/agent/test_bgp_dragent.py +++ /dev/null @@ -1,736 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 copy -import sys -import uuid - -import eventlet -import mock -from oslo_config import cfg -import testtools - -from neutron.common import config as common_config -from neutron import context -from neutron.services.bgp.agent import bgp_dragent -from neutron.services.bgp.agent import config as bgp_config -from neutron.services.bgp.agent import entry -from neutron.tests import base - -HOSTNAME = 'hostname' -rpc_api = bgp_dragent.BgpDrPluginApi -BGP_PLUGIN = '%s.%s' % (rpc_api.__module__, rpc_api.__name__) - -FAKE_BGPSPEAKER_UUID = str(uuid.uuid4()) -FAKE_BGPPEER_UUID = str(uuid.uuid4()) - -FAKE_BGP_SPEAKER = {'id': FAKE_BGPSPEAKER_UUID, - 'local_as': 12345, - 'peers': [{'remote_as': '2345', - 'peer_ip': '1.1.1.1', - 'auth_type': 'none', - 'password': ''}], - 'advertised_routes': []} - -FAKE_BGP_PEER = {'id': FAKE_BGPPEER_UUID, - 'remote_as': '2345', - 'peer_ip': '1.1.1.1', - 'auth_type': 'none', - 'password': ''} - -FAKE_ROUTE = {'id': FAKE_BGPSPEAKER_UUID, - 'destination': '2.2.2.2/32', - 'next_hop': '3.3.3.3'} - -FAKE_ROUTES = {'routes': {'id': FAKE_BGPSPEAKER_UUID, - 'destination': '2.2.2.2/32', - 'next_hop': '3.3.3.3'} - } - - -class TestBgpDrAgent(base.BaseTestCase): - def setUp(self): - super(TestBgpDrAgent, self).setUp() - cfg.CONF.register_opts(bgp_config.BGP_DRIVER_OPTS, 'BGP') - cfg.CONF.register_opts(bgp_config.BGP_PROTO_CONFIG_OPTS, 'BGP') - mock_log_p = mock.patch.object(bgp_dragent, 'LOG') - self.mock_log = mock_log_p.start() - self.driver_cls_p = mock.patch( - 'neutron.services.bgp.agent.bgp_dragent.importutils.import_class') - self.driver_cls = self.driver_cls_p.start() - self.context = context.get_admin_context() - - def test_bgp_dragent_manager(self): - state_rpc_str = 'neutron.agent.rpc.PluginReportStateAPI' - # sync_state is needed for this test - with mock.patch.object(bgp_dragent.BgpDrAgentWithStateReport, - 'sync_state', - autospec=True) as mock_sync_state: - with mock.patch(state_rpc_str) as state_rpc: - with mock.patch.object(sys, 'argv') as sys_argv: - sys_argv.return_value = [ - 'bgp_dragent', '--config-file', - base.etcdir('neutron.conf')] - common_config.init(sys.argv[1:]) - agent_mgr = bgp_dragent.BgpDrAgentWithStateReport( - 'testhost') - eventlet.greenthread.sleep(1) - agent_mgr.after_start() - self.assertIsNotNone(len(mock_sync_state.mock_calls)) - state_rpc.assert_has_calls( - [mock.call(mock.ANY), - mock.call().report_state(mock.ANY, mock.ANY, - mock.ANY)]) - - def test_bgp_dragent_main_agent_manager(self): - logging_str = 'neutron.agent.common.config.setup_logging' - launcher_str = 'oslo_service.service.ServiceLauncher' - with mock.patch(logging_str): - with mock.patch.object(sys, 'argv') as sys_argv: - with mock.patch(launcher_str) as launcher: - sys_argv.return_value = ['bgp_dragent', '--config-file', - base.etcdir('neutron.conf')] - entry.main() - launcher.assert_has_calls( - [mock.call(cfg.CONF), - mock.call().launch_service(mock.ANY), - mock.call().wait()]) - - def test_run_completes_single_pass(self): - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - with mock.patch.object(bgp_dr, 'sync_state') as sync_state: - bgp_dr.run() - self.assertIsNotNone(len(sync_state.mock_calls)) - - def test_after_start(self): - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - with mock.patch.object(bgp_dr, 'sync_state') as sync_state: - bgp_dr.after_start() - self.assertIsNotNone(len(sync_state.mock_calls)) - - def _test_sync_state_helper(self, bgp_speaker_list=None, - cached_info=None, - safe_configure_call_count=0, - sync_bgp_speaker_call_count=0, - remove_bgp_speaker_call_count=0, - remove_bgp_speaker_ids=None, - added_bgp_speakers=None, - synced_bgp_speakers=None): - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - - attrs_to_mock = dict( - [(a, mock.MagicMock()) - for a in ['plugin_rpc', 'sync_bgp_speaker', - 'safe_configure_dragent_for_bgp_speaker', - 'remove_bgp_speaker_from_dragent']]) - - with mock.patch.multiple(bgp_dr, **attrs_to_mock): - if not cached_info: - cached_info = {} - if not added_bgp_speakers: - added_bgp_speakers = [] - if not remove_bgp_speaker_ids: - remove_bgp_speaker_ids = [] - if not synced_bgp_speakers: - synced_bgp_speakers = [] - - bgp_dr.plugin_rpc.get_bgp_speakers.return_value = bgp_speaker_list - bgp_dr.cache.cache = cached_info - bgp_dr.cache.clear_cache = mock.Mock() - bgp_dr.sync_state(mock.ANY) - - self.assertEqual( - remove_bgp_speaker_call_count, - bgp_dr.remove_bgp_speaker_from_dragent.call_count) - - if remove_bgp_speaker_call_count: - expected_calls = [mock.call(bgp_speaker_id) - for bgp_speaker_id in remove_bgp_speaker_ids] - bgp_dr.remove_bgp_speaker_from_dragent.assert_has_calls( - expected_calls) - - self.assertEqual( - safe_configure_call_count, - bgp_dr.safe_configure_dragent_for_bgp_speaker.call_count) - - if safe_configure_call_count: - expected_calls = [mock.call(bgp_speaker) - for bgp_speaker in added_bgp_speakers] - bgp_dr.safe_configure_dragent_for_bgp_speaker.assert_has_calls( - expected_calls) - - self.assertEqual(sync_bgp_speaker_call_count, - bgp_dr.sync_bgp_speaker.call_count) - - if sync_bgp_speaker_call_count: - expected_calls = [mock.call(bgp_speaker) - for bgp_speaker in synced_bgp_speakers] - bgp_dr.sync_bgp_speaker.assert_has_calls(expected_calls) - - def test_sync_state_bgp_speaker_added(self): - bgp_speaker_list = [{'id': 'foo-id', - 'local_as': 12345, - 'peers': [], - 'advertised_routes': []}] - self._test_sync_state_helper(bgp_speaker_list=bgp_speaker_list, - safe_configure_call_count=1, - added_bgp_speakers=bgp_speaker_list) - - def test_sync_state_bgp_speaker_deleted(self): - bgp_speaker_list = [] - cached_bgp_speaker = {'id': 'foo-id', - 'local_as': 12345, - 'peers': ['peer-1'], - 'advertised_routes': []} - cached_info = {'foo-id': cached_bgp_speaker} - self._test_sync_state_helper(bgp_speaker_list=bgp_speaker_list, - cached_info=cached_info, - remove_bgp_speaker_call_count=1, - remove_bgp_speaker_ids=['foo-id']) - - def test_sync_state_added_and_deleted(self): - bgp_speaker_list = [{'id': 'foo-id', - 'local_as': 12345, - 'peers': [], - 'advertised_routes': []}] - cached_bgp_speaker = {'bgp_speaker': {'local_as': 12345}, - 'peers': ['peer-1'], - 'advertised_routes': []} - cached_info = {'bar-id': cached_bgp_speaker} - - self._test_sync_state_helper(bgp_speaker_list=bgp_speaker_list, - cached_info=cached_info, - remove_bgp_speaker_call_count=1, - remove_bgp_speaker_ids=['bar-id'], - safe_configure_call_count=1, - added_bgp_speakers=bgp_speaker_list) - - def test_sync_state_added_and_synced(self): - bgp_speaker_list = [{'id': 'foo-id', - 'local_as': 12345, - 'peers': [], - 'advertised_routes': []}, - {'id': 'bar-id', 'peers': ['peer-2'], - 'advertised_routes': []}, - {'id': 'temp-id', 'peers': ['temp-1'], - 'advertised_routes': []}] - - cached_bgp_speaker = {'id': 'bar-id', 'bgp_speaker': {'id': 'bar-id'}, - 'peers': ['peer-1'], - 'advertised_routes': []} - cached_bgp_speaker_2 = {'id': 'temp-id', - 'bgp_speaker': {'id': 'temp-id'}, - 'peers': ['temp-1'], - 'advertised_routes': []} - cached_info = {'bar-id': cached_bgp_speaker, - 'temp-id': cached_bgp_speaker_2} - - self._test_sync_state_helper(bgp_speaker_list=bgp_speaker_list, - cached_info=cached_info, - safe_configure_call_count=1, - added_bgp_speakers=[bgp_speaker_list[0]], - sync_bgp_speaker_call_count=2, - synced_bgp_speakers=[bgp_speaker_list[1], - bgp_speaker_list[2]] - ) - - def test_sync_state_added_synced_and_removed(self): - bgp_speaker_list = [{'id': 'foo-id', - 'local_as': 12345, - 'peers': [], - 'advertised_routes': []}, - {'id': 'bar-id', 'peers': ['peer-2'], - 'advertised_routes': []}] - cached_bgp_speaker = {'id': 'bar-id', - 'bgp_speaker': {'id': 'bar-id'}, - 'peers': ['peer-1'], - 'advertised_routes': []} - cached_bgp_speaker_2 = {'id': 'temp-id', - 'bgp_speaker': {'id': 'temp-id'}, - 'peers': ['temp-1'], - 'advertised_routes': []} - cached_info = {'bar-id': cached_bgp_speaker, - 'temp-id': cached_bgp_speaker_2} - - self._test_sync_state_helper(bgp_speaker_list=bgp_speaker_list, - cached_info=cached_info, - remove_bgp_speaker_call_count=1, - remove_bgp_speaker_ids=['temp-id'], - safe_configure_call_count=1, - added_bgp_speakers=[bgp_speaker_list[0]], - sync_bgp_speaker_call_count=1, - synced_bgp_speakers=[bgp_speaker_list[1]]) - - def _test_sync_bgp_speaker_helper(self, bgp_speaker, cached_info=None, - remove_bgp_peer_call_count=0, - removed_bgp_peer_ip_list=None, - withdraw_route_call_count=0, - withdraw_routes_list=None, - add_bgp_peers_called=False, - advertise_routes_called=False): - if not cached_info: - cached_info = {} - if not removed_bgp_peer_ip_list: - removed_bgp_peer_ip_list = [] - if not withdraw_routes_list: - withdraw_routes_list = [] - - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - - attrs_to_mock = dict( - [(a, mock.MagicMock()) - for a in ['remove_bgp_peer_from_bgp_speaker', - 'add_bgp_peers_to_bgp_speaker', - 'advertise_routes_via_bgp_speaker', - 'withdraw_route_via_bgp_speaker']]) - - with mock.patch.multiple(bgp_dr, **attrs_to_mock): - bgp_dr.cache.cache = cached_info - bgp_dr.sync_bgp_speaker(bgp_speaker) - - self.assertEqual( - remove_bgp_peer_call_count, - bgp_dr.remove_bgp_peer_from_bgp_speaker.call_count) - - if remove_bgp_peer_call_count: - expected_calls = [mock.call(bgp_speaker['id'], peer_ip) - for peer_ip in removed_bgp_peer_ip_list] - bgp_dr.remove_bgp_peer_from_bgp_speaker.assert_has_calls( - expected_calls) - - self.assertEqual(add_bgp_peers_called, - bgp_dr.add_bgp_peers_to_bgp_speaker.called) - - if add_bgp_peers_called: - bgp_dr.add_bgp_peers_to_bgp_speaker.assert_called_with( - bgp_speaker) - - self.assertEqual( - withdraw_route_call_count, - bgp_dr.withdraw_route_via_bgp_speaker.call_count) - - if withdraw_route_call_count: - expected_calls = [mock.call(bgp_speaker['id'], 12345, route) - for route in withdraw_routes_list] - bgp_dr.withdraw_route_via_bgp_speaker.assert_has_calls( - expected_calls) - - self.assertEqual(advertise_routes_called, - bgp_dr.advertise_routes_via_bgp_speaker.called) - - if advertise_routes_called: - bgp_dr.advertise_routes_via_bgp_speaker.assert_called_with( - bgp_speaker) - - def test_sync_bgp_speaker_bgp_peers_updated(self): - peers = [{'id': 'peer-1', 'peer_ip': '1.1.1.1'}, - {'id': 'peer-2', 'peer_ip': '2.2.2.2'}] - bgp_speaker = {'id': 'foo-id', - 'local_as': 12345, - 'peers': peers, - 'advertised_routes': []} - - cached_peers = {'1.1.1.1': {'id': 'peer-2', 'peer_ip': '1.1.1.1'}, - '3.3.3.3': {'id': 'peer-3', 'peer_ip': '3.3.3.3'}} - - cached_bgp_speaker = {'foo-id': {'bgp_speaker': {'local_as': 12345}, - 'peers': cached_peers, - 'advertised_routes': []}} - self._test_sync_bgp_speaker_helper( - bgp_speaker, cached_info=cached_bgp_speaker, - remove_bgp_peer_call_count=1, - removed_bgp_peer_ip_list=['3.3.3.3'], - add_bgp_peers_called=True, - advertise_routes_called=False) - - def test_sync_bgp_speaker_routes_updated(self): - adv_routes = [{'destination': '10.0.0.0/24', 'next_hop': '1.1.1.1'}, - {'destination': '20.0.0.0/24', 'next_hop': '2.2.2.2'}] - bgp_speaker = {'id': 'foo-id', - 'local_as': 12345, - 'peers': {}, - 'advertised_routes': adv_routes} - - cached_adv_routes = [{'destination': '20.0.0.0/24', - 'next_hop': '2.2.2.2'}, - {'destination': '30.0.0.0/24', - 'next_hop': '3.3.3.3'}] - - cached_bgp_speaker = { - 'foo-id': {'bgp_speaker': {'local_as': 12345}, - 'peers': {}, - 'advertised_routes': cached_adv_routes}} - - self._test_sync_bgp_speaker_helper( - bgp_speaker, cached_info=cached_bgp_speaker, - withdraw_route_call_count=1, - withdraw_routes_list=[cached_adv_routes[1]], - add_bgp_peers_called=False, - advertise_routes_called=True) - - def test_sync_bgp_speaker_peers_routes_added(self): - peers = [{'id': 'peer-1', 'peer_ip': '1.1.1.1'}, - {'id': 'peer-2', 'peer_ip': '2.2.2.2'}] - adv_routes = [{'destination': '10.0.0.0/24', - 'next_hop': '1.1.1.1'}, - {'destination': '20.0.0.0/24', - 'next_hop': '2.2.2.2'}] - bgp_speaker = {'id': 'foo-id', - 'local_as': 12345, - 'peers': peers, - 'advertised_routes': adv_routes} - - cached_bgp_speaker = { - 'foo-id': {'bgp_speaker': {'local_as': 12345}, - 'peers': {}, - 'advertised_routes': []}} - - self._test_sync_bgp_speaker_helper( - bgp_speaker, cached_info=cached_bgp_speaker, - add_bgp_peers_called=True, - advertise_routes_called=True) - - def test_sync_state_plugin_error(self): - with mock.patch(BGP_PLUGIN) as plug: - mock_plugin = mock.Mock() - mock_plugin.get_bgp_speakers.side_effect = Exception - plug.return_value = mock_plugin - - with mock.patch.object(bgp_dragent.LOG, 'error') as log: - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - with mock.patch.object(bgp_dr, - 'schedule_full_resync') as schedule_full_resync: - bgp_dr.sync_state(mock.ANY) - - self.assertTrue(log.called) - self.assertTrue(schedule_full_resync.called) - - def test_periodic_resync(self): - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - with mock.patch.object(bgp_dr, - '_periodic_resync_helper') as resync_helper: - bgp_dr.periodic_resync(self.context) - self.assertTrue(resync_helper.called) - - def test_periodic_resync_helper(self): - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - bgp_dr.schedule_resync('foo reason', 'foo-id') - with mock.patch.object(bgp_dr, 'sync_state') as sync_state: - sync_state.side_effect = RuntimeError - with testtools.ExpectedException(RuntimeError): - bgp_dr._periodic_resync_helper(self.context) - self.assertTrue(sync_state.called) - self.assertEqual(len(bgp_dr.needs_resync_reasons), 0) - - def _test_add_bgp_peer_helper(self, bgp_speaker_id, - bgp_peer, cached_bgp_speaker, - put_bgp_peer_called=True): - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - - bgp_dr.cache.cache = cached_bgp_speaker - with mock.patch.object( - bgp_dr.cache, 'put_bgp_peer') as mock_put_bgp_peer: - bgp_dr.add_bgp_peer_to_bgp_speaker('foo-id', 12345, bgp_peer) - if put_bgp_peer_called: - mock_put_bgp_peer.assert_called_once_with( - bgp_speaker_id, bgp_peer) - else: - self.assertFalse(mock_put_bgp_peer.called) - - def test_add_bgp_peer_not_cached(self): - bgp_peer = {'peer_ip': '1.1.1.1', 'remote_as': 34567, - 'auth_type': 'md5', 'password': 'abc'} - cached_bgp_speaker = {'foo-id': {'bgp_speaker': {'local_as': 12345}, - 'peers': {}, - 'advertised_routes': []}} - - self._test_add_bgp_peer_helper('foo-id', bgp_peer, cached_bgp_speaker) - - def test_add_bgp_peer_already_cached(self): - bgp_peer = {'peer_ip': '1.1.1.1', 'remote_as': 34567, - 'auth_type': 'md5', 'password': 'abc'} - cached_peers = {'1.1.1.1': {'peer_ip': '1.1.1.1', 'remote_as': 34567}} - cached_bgp_speaker = {'foo-id': {'bgp_speaker': {'local_as': 12345}, - 'peers': cached_peers, - 'advertised_routes': []}} - - self._test_add_bgp_peer_helper('foo-id', bgp_peer, cached_bgp_speaker, - put_bgp_peer_called=False) - - def _test_advertise_route_helper(self, bgp_speaker_id, - route, cached_bgp_speaker, - put_adv_route_called=True): - bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - - bgp_dr.cache.cache = cached_bgp_speaker - with mock.patch.object( - bgp_dr.cache, 'put_adv_route') as mock_put_adv_route: - bgp_dr.advertise_route_via_bgp_speaker(bgp_speaker_id, 12345, - route) - if put_adv_route_called: - mock_put_adv_route.assert_called_once_with( - bgp_speaker_id, route) - else: - self.assertFalse(mock_put_adv_route.called) - - def test_advertise_route_helper_not_cached(self): - route = {'destination': '10.0.0.0/24', 'next_hop': '1.1.1.1'} - cached_bgp_speaker = {'foo-id': {'bgp_speaker': {'local_as': 12345}, - 'peers': {}, - 'advertised_routes': []}} - - self._test_advertise_route_helper('foo-id', route, cached_bgp_speaker, - put_adv_route_called=True) - - def test_advertise_route_helper_already_cached(self): - route = {'destination': '10.0.0.0/24', 'next_hop': '1.1.1.1'} - cached_bgp_speaker = {'foo-id': {'bgp_speaker': {'local_as': 12345}, - 'peers': {}, - 'advertised_routes': [route]}} - - self._test_advertise_route_helper('foo-id', route, cached_bgp_speaker, - put_adv_route_called=False) - - -class TestBgpDrAgentEventHandler(base.BaseTestCase): - - cache_cls = 'neutron.services.bgp.agent.bgp_dragent.BgpSpeakerCache' - - def setUp(self): - super(TestBgpDrAgentEventHandler, self).setUp() - cfg.CONF.register_opts(bgp_config.BGP_DRIVER_OPTS, 'BGP') - cfg.CONF.register_opts(bgp_config.BGP_PROTO_CONFIG_OPTS, 'BGP') - - mock_log_p = mock.patch.object(bgp_dragent, 'LOG') - self.mock_log = mock_log_p.start() - - self.plugin_p = mock.patch(BGP_PLUGIN) - plugin_cls = self.plugin_p.start() - self.plugin = mock.Mock() - plugin_cls.return_value = self.plugin - - self.cache_p = mock.patch(self.cache_cls) - cache_cls = self.cache_p.start() - self.cache = mock.Mock() - cache_cls.return_value = self.cache - - self.driver_cls_p = mock.patch( - 'neutron.services.bgp.agent.bgp_dragent.importutils.import_class') - self.driver_cls = self.driver_cls_p.start() - - self.bgp_dr = bgp_dragent.BgpDrAgent(HOSTNAME) - self.schedule_full_resync_p = mock.patch.object( - self.bgp_dr, 'schedule_full_resync') - self.schedule_full_resync = self.schedule_full_resync_p.start() - self.context = mock.Mock() - - def test_bgp_speaker_create_end(self): - payload = {'bgp_speaker': {'id': FAKE_BGPSPEAKER_UUID}} - - with mock.patch.object(self.bgp_dr, - 'add_bgp_speaker_helper') as enable: - self.bgp_dr.bgp_speaker_create_end(None, payload) - enable.assert_called_once_with(FAKE_BGP_SPEAKER['id']) - - def test_bgp_peer_association_end(self): - payload = {'bgp_peer': {'speaker_id': FAKE_BGPSPEAKER_UUID, - 'peer_id': FAKE_BGPPEER_UUID}} - - with mock.patch.object(self.bgp_dr, - 'add_bgp_peer_helper') as enable: - self.bgp_dr.bgp_peer_association_end(None, payload) - enable.assert_called_once_with(FAKE_BGP_SPEAKER['id'], - FAKE_BGP_PEER['id']) - - def test_route_advertisement_end(self): - routes = [{'destination': '2.2.2.2/32', 'next_hop': '3.3.3.3'}, - {'destination': '4.4.4.4/32', 'next_hop': '5.5.5.5'}] - payload = {'advertise_routes': {'speaker_id': FAKE_BGPSPEAKER_UUID, - 'routes': routes}} - - expected_calls = [mock.call(FAKE_BGP_SPEAKER['id'], routes)] - - with mock.patch.object(self.bgp_dr, - 'add_routes_helper') as enable: - self.bgp_dr.bgp_routes_advertisement_end(None, payload) - enable.assert_has_calls(expected_calls) - - def test_add_bgp_speaker_helper(self): - self.plugin.get_bgp_speaker_info.return_value = FAKE_BGP_SPEAKER - add_bs_p = mock.patch.object(self.bgp_dr, - 'add_bgp_speaker_on_dragent') - add_bs = add_bs_p.start() - self.bgp_dr.add_bgp_speaker_helper(FAKE_BGP_SPEAKER['id']) - self.plugin.assert_has_calls([ - mock.call.get_bgp_speaker_info(mock.ANY, - FAKE_BGP_SPEAKER['id'])]) - add_bs.assert_called_once_with(FAKE_BGP_SPEAKER) - - def test_add_bgp_peer_helper(self): - self.plugin.get_bgp_peer_info.return_value = FAKE_BGP_PEER - add_bp_p = mock.patch.object(self.bgp_dr, - 'add_bgp_peer_to_bgp_speaker') - add_bp = add_bp_p.start() - self.bgp_dr.add_bgp_peer_helper(FAKE_BGP_SPEAKER['id'], - FAKE_BGP_PEER['id']) - self.plugin.assert_has_calls([ - mock.call.get_bgp_peer_info(mock.ANY, - FAKE_BGP_PEER['id'])]) - self.assertEqual(1, add_bp.call_count) - - def test_add_routes_helper(self): - add_rt_p = mock.patch.object(self.bgp_dr, - 'advertise_route_via_bgp_speaker') - add_bp = add_rt_p.start() - self.bgp_dr.add_routes_helper(FAKE_BGP_SPEAKER['id'], FAKE_ROUTES) - self.assertEqual(1, add_bp.call_count) - - def test_bgp_speaker_remove_end(self): - payload = {'bgp_speaker': {'id': FAKE_BGPSPEAKER_UUID}} - - with mock.patch.object(self.bgp_dr, - 'remove_bgp_speaker_from_dragent') as disable: - self.bgp_dr.bgp_speaker_remove_end(None, payload) - disable.assert_called_once_with(FAKE_BGP_SPEAKER['id']) - - def test_bgp_peer_disassociation_end(self): - payload = {'bgp_peer': {'speaker_id': FAKE_BGPSPEAKER_UUID, - 'peer_ip': '1.1.1.1'}} - - with mock.patch.object(self.bgp_dr, - 'remove_bgp_peer_from_bgp_speaker') as disable: - self.bgp_dr.bgp_peer_disassociation_end(None, payload) - disable.assert_called_once_with(FAKE_BGPSPEAKER_UUID, - FAKE_BGP_PEER['peer_ip']) - - def test_bgp_routes_withdrawal_end(self): - withdraw_routes = [{'destination': '2.2.2.2/32'}, - {'destination': '3.3.3.3/32'}] - payload = {'withdraw_routes': {'speaker_id': FAKE_BGPSPEAKER_UUID, - 'routes': withdraw_routes}} - - expected_calls = [mock.call(FAKE_BGP_SPEAKER['id'], withdraw_routes)] - - with mock.patch.object(self.bgp_dr, - 'withdraw_routes_helper') as disable: - self.bgp_dr.bgp_routes_withdrawal_end(None, payload) - disable.assert_has_calls(expected_calls) - - -class TestBGPSpeakerCache(base.BaseTestCase): - - def setUp(self): - super(TestBGPSpeakerCache, self).setUp() - self.expected_cache = {FAKE_BGP_SPEAKER['id']: - {'bgp_speaker': FAKE_BGP_SPEAKER, - 'peers': {}, - 'advertised_routes': []}} - self.bs_cache = bgp_dragent.BgpSpeakerCache() - - def test_put_bgp_speaker(self): - self.bs_cache.put_bgp_speaker(FAKE_BGP_SPEAKER) - self.assertEqual(self.expected_cache, self.bs_cache.cache) - - def test_put_bgp_speaker_existing(self): - prev_bs_info = {'id': 'foo-id'} - with mock.patch.object(self.bs_cache, - 'remove_bgp_speaker_by_id') as remove: - self.bs_cache.cache[FAKE_BGP_SPEAKER['id']] = prev_bs_info - self.bs_cache.put_bgp_speaker(FAKE_BGP_SPEAKER) - remove.assert_called_once_with(prev_bs_info) - self.assertEqual(self.expected_cache, self.bs_cache.cache) - - def remove_bgp_speaker_by_id(self): - self.bs_cache.put_bgp_speaker(FAKE_BGP_SPEAKER) - self.assertEqual(1, len(self.bs_cache.cache)) - self.bs_cache.remove_bgp_speaker_by_id(FAKE_BGP_SPEAKER['id']) - self.assertEqual(0, len(self.bs_cache.cache)) - - def test_get_bgp_speaker_by_id(self): - self.bs_cache.put_bgp_speaker(FAKE_BGP_SPEAKER) - - self.assertEqual( - FAKE_BGP_SPEAKER, - self.bs_cache.get_bgp_speaker_by_id(FAKE_BGP_SPEAKER['id'])) - - def test_get_bgp_speaker_ids(self): - self.bs_cache.put_bgp_speaker(FAKE_BGP_SPEAKER) - - self.assertEqual([FAKE_BGP_SPEAKER['id']], - list(self.bs_cache.get_bgp_speaker_ids())) - - def _test_bgp_peer_helper(self, remove=False): - self.bs_cache.put_bgp_speaker(FAKE_BGP_SPEAKER) - self.bs_cache.put_bgp_peer(FAKE_BGP_SPEAKER['id'], FAKE_BGP_PEER) - expected_cache = copy.deepcopy(self.expected_cache) - expected_cache[FAKE_BGP_SPEAKER['id']]['peers'] = { - FAKE_BGP_PEER['peer_ip']: FAKE_BGP_PEER} - self.assertEqual(expected_cache, self.bs_cache.cache) - - if remove: - self.bs_cache.remove_bgp_peer_by_ip(FAKE_BGP_SPEAKER['id'], - 'foo-ip') - self.assertEqual(expected_cache, self.bs_cache.cache) - - self.bs_cache.remove_bgp_peer_by_ip(FAKE_BGP_SPEAKER['id'], - FAKE_BGP_PEER['peer_ip']) - self.assertEqual(self.expected_cache, self.bs_cache.cache) - - def test_put_bgp_peer(self): - self._test_bgp_peer_helper() - - def test_remove_bgp_peer(self): - self._test_bgp_peer_helper(remove=True) - - def _test_bgp_speaker_adv_route_helper(self, remove=False): - self.bs_cache.put_bgp_speaker(FAKE_BGP_SPEAKER) - self.bs_cache.put_adv_route(FAKE_BGP_SPEAKER['id'], FAKE_ROUTE) - expected_cache = copy.deepcopy(self.expected_cache) - expected_cache[FAKE_BGP_SPEAKER['id']]['advertised_routes'].append( - FAKE_ROUTE) - self.assertEqual(expected_cache, self.bs_cache.cache) - - fake_route_2 = copy.deepcopy(FAKE_ROUTE) - fake_route_2['destination'] = '4.4.4.4/32' - self.bs_cache.put_adv_route(FAKE_BGP_SPEAKER['id'], fake_route_2) - - expected_cache[FAKE_BGP_SPEAKER['id']]['advertised_routes'].append( - fake_route_2) - self.assertEqual(expected_cache, self.bs_cache.cache) - - if remove: - self.bs_cache.remove_adv_route(FAKE_BGP_SPEAKER['id'], - fake_route_2) - expected_cache[FAKE_BGP_SPEAKER['id']]['advertised_routes'] = ( - [FAKE_ROUTE]) - self.assertEqual(expected_cache, self.bs_cache.cache) - - self.bs_cache.remove_adv_route(FAKE_BGP_SPEAKER['id'], - FAKE_ROUTE) - self.assertEqual(self.expected_cache, self.bs_cache.cache) - - def test_put_bgp_speaker_adv_route(self): - self._test_bgp_speaker_adv_route_helper() - - def test_remove_bgp_speaker_adv_route(self): - self._test_bgp_speaker_adv_route_helper(remove=True) - - def test_is_bgp_speaker_adv_route_present(self): - self._test_bgp_speaker_adv_route_helper() - self.assertTrue(self.bs_cache.is_route_advertised( - FAKE_BGP_SPEAKER['id'], FAKE_ROUTE)) - self.assertFalse(self.bs_cache.is_route_advertised( - FAKE_BGP_SPEAKER['id'], {'destination': 'foo-destination', - 'next_hop': 'foo-next-hop'})) diff --git a/neutron/tests/unit/services/bgp/driver/__init__.py b/neutron/tests/unit/services/bgp/driver/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/unit/services/bgp/driver/ryu/__init__.py b/neutron/tests/unit/services/bgp/driver/ryu/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/unit/services/bgp/driver/ryu/test_driver.py b/neutron/tests/unit/services/bgp/driver/ryu/test_driver.py deleted file mode 100644 index ed8c6ba4cd6..00000000000 --- a/neutron/tests/unit/services/bgp/driver/ryu/test_driver.py +++ /dev/null @@ -1,250 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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 mock -from oslo_config import cfg -from ryu.services.protocols.bgp import bgpspeaker -from ryu.services.protocols.bgp.rtconf.neighbors import CONNECT_MODE_ACTIVE - -from neutron.services.bgp.agent import config as bgp_config -from neutron.services.bgp.driver import exceptions as bgp_driver_exc -from neutron.services.bgp.driver.ryu import driver as ryu_driver -from neutron.tests import base - -# Test variables for BGP Speaker -FAKE_LOCAL_AS1 = 12345 -FAKE_LOCAL_AS2 = 23456 -FAKE_ROUTER_ID = '1.1.1.1' - -# Test variables for BGP Peer -FAKE_PEER_AS = 45678 -FAKE_PEER_IP = '2.2.2.5' -FAKE_AUTH_TYPE = 'md5' -FAKE_PEER_PASSWORD = 'awesome' - -# Test variables for Route -FAKE_ROUTE = '2.2.2.0/24' -FAKE_NEXTHOP = '5.5.5.5' - - -class TestRyuBgpDriver(base.BaseTestCase): - - def setUp(self): - super(TestRyuBgpDriver, self).setUp() - cfg.CONF.register_opts(bgp_config.BGP_PROTO_CONFIG_OPTS, 'BGP') - cfg.CONF.set_override('bgp_router_id', FAKE_ROUTER_ID, 'BGP') - self.ryu_bgp_driver = ryu_driver.RyuBgpDriver(cfg.CONF.BGP) - mock_ryu_speaker_p = mock.patch.object(bgpspeaker, 'BGPSpeaker') - self.mock_ryu_speaker = mock_ryu_speaker_p.start() - - def test_add_new_bgp_speaker(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.mock_ryu_speaker.assert_called_once_with( - as_number=FAKE_LOCAL_AS1, router_id=FAKE_ROUTER_ID, - bgp_server_port=0, - best_path_change_handler=ryu_driver.best_path_change_cb, - peer_down_handler=ryu_driver.bgp_peer_down_cb, - peer_up_handler=ryu_driver.bgp_peer_up_cb) - - def test_remove_bgp_speaker(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - speaker = self.ryu_bgp_driver.cache.get_bgp_speaker(FAKE_LOCAL_AS1) - self.ryu_bgp_driver.delete_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(0, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.assertEqual(1, speaker.shutdown.call_count) - - def test_add_bgp_peer_without_password(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.ryu_bgp_driver.add_bgp_peer(FAKE_LOCAL_AS1, - FAKE_PEER_IP, - FAKE_PEER_AS) - speaker = self.ryu_bgp_driver.cache.get_bgp_speaker(FAKE_LOCAL_AS1) - speaker.neighbor_add.assert_called_once_with( - address=FAKE_PEER_IP, - remote_as=FAKE_PEER_AS, - password=None, - connect_mode=CONNECT_MODE_ACTIVE) - - def test_add_bgp_peer_with_password(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.ryu_bgp_driver.add_bgp_peer(FAKE_LOCAL_AS1, - FAKE_PEER_IP, - FAKE_PEER_AS, - FAKE_AUTH_TYPE, - FAKE_PEER_PASSWORD) - speaker = self.ryu_bgp_driver.cache.get_bgp_speaker(FAKE_LOCAL_AS1) - speaker.neighbor_add.assert_called_once_with( - address=FAKE_PEER_IP, - remote_as=FAKE_PEER_AS, - password=FAKE_PEER_PASSWORD, - connect_mode=CONNECT_MODE_ACTIVE) - - def test_remove_bgp_peer(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.ryu_bgp_driver.delete_bgp_peer(FAKE_LOCAL_AS1, FAKE_PEER_IP) - speaker = self.ryu_bgp_driver.cache.get_bgp_speaker(FAKE_LOCAL_AS1) - speaker.neighbor_del.assert_called_once_with(address=FAKE_PEER_IP) - - def test_advertise_route(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.ryu_bgp_driver.advertise_route(FAKE_LOCAL_AS1, - FAKE_ROUTE, - FAKE_NEXTHOP) - speaker = self.ryu_bgp_driver.cache.get_bgp_speaker(FAKE_LOCAL_AS1) - speaker.prefix_add.assert_called_once_with(prefix=FAKE_ROUTE, - next_hop=FAKE_NEXTHOP) - - def test_withdraw_route(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.ryu_bgp_driver.withdraw_route(FAKE_LOCAL_AS1, FAKE_ROUTE) - speaker = self.ryu_bgp_driver.cache.get_bgp_speaker(FAKE_LOCAL_AS1) - speaker.prefix_del.assert_called_once_with(prefix=FAKE_ROUTE) - - def test_add_same_bgp_speakers_twice(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertRaises(bgp_driver_exc.BgpSpeakerAlreadyScheduled, - self.ryu_bgp_driver.add_bgp_speaker, FAKE_LOCAL_AS1) - - def test_add_different_bgp_speakers_when_one_already_added(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertRaises(bgp_driver_exc.BgpSpeakerMaxScheduled, - self.ryu_bgp_driver.add_bgp_speaker, - FAKE_LOCAL_AS2) - - def test_add_bgp_speaker_with_invalid_asnum_paramtype(self): - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.add_bgp_speaker, '12345') - - def test_add_bgp_speaker_with_invalid_asnum_range(self): - self.assertRaises(bgp_driver_exc.InvalidParamRange, - self.ryu_bgp_driver.add_bgp_speaker, -1) - self.assertRaises(bgp_driver_exc.InvalidParamRange, - self.ryu_bgp_driver.add_bgp_speaker, 65536) - - def test_add_bgp_peer_with_invalid_paramtype(self): - # Test with an invalid asnum data-type - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, '12345') - # Test with an invalid auth-type and an invalid password - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, FAKE_PEER_AS, - 'sha-1', 1234) - # Test with an invalid auth-type and a valid password - self.assertRaises(bgp_driver_exc.InvaildAuthType, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, FAKE_PEER_AS, - 'hmac-md5', FAKE_PEER_PASSWORD) - # Test with none auth-type and a valid password - self.assertRaises(bgp_driver_exc.InvaildAuthType, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, FAKE_PEER_AS, - 'none', FAKE_PEER_PASSWORD) - # Test with none auth-type and an invalid password - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, FAKE_PEER_AS, - 'none', 1234) - # Test with a valid auth-type and no password - self.assertRaises(bgp_driver_exc.PasswordNotSpecified, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, FAKE_PEER_AS, - FAKE_AUTH_TYPE, None) - - def test_add_bgp_peer_with_invalid_asnum_range(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertRaises(bgp_driver_exc.InvalidParamRange, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, -1) - self.assertRaises(bgp_driver_exc.InvalidParamRange, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, 65536) - - def test_add_bgp_peer_without_adding_speaker(self): - self.assertRaises(bgp_driver_exc.BgpSpeakerNotAdded, - self.ryu_bgp_driver.add_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP, FAKE_PEER_AS) - - def test_remove_bgp_peer_with_invalid_paramtype(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.delete_bgp_peer, - FAKE_LOCAL_AS1, 12345) - - def test_remove_bgp_peer_without_adding_speaker(self): - self.assertRaises(bgp_driver_exc.BgpSpeakerNotAdded, - self.ryu_bgp_driver.delete_bgp_peer, - FAKE_LOCAL_AS1, FAKE_PEER_IP) - - def test_advertise_route_with_invalid_paramtype(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.advertise_route, - FAKE_LOCAL_AS1, 12345, FAKE_NEXTHOP) - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.advertise_route, - FAKE_LOCAL_AS1, FAKE_ROUTE, 12345) - - def test_advertise_route_without_adding_speaker(self): - self.assertRaises(bgp_driver_exc.BgpSpeakerNotAdded, - self.ryu_bgp_driver.advertise_route, - FAKE_LOCAL_AS1, FAKE_ROUTE, FAKE_NEXTHOP) - - def test_withdraw_route_with_invalid_paramtype(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.withdraw_route, - FAKE_LOCAL_AS1, 12345) - self.assertRaises(bgp_driver_exc.InvalidParamType, - self.ryu_bgp_driver.withdraw_route, - FAKE_LOCAL_AS1, 12345) - - def test_withdraw_route_without_adding_speaker(self): - self.assertRaises(bgp_driver_exc.BgpSpeakerNotAdded, - self.ryu_bgp_driver.withdraw_route, - FAKE_LOCAL_AS1, FAKE_ROUTE) - - def test_add_multiple_bgp_speakers(self): - self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.assertRaises(bgp_driver_exc.BgpSpeakerMaxScheduled, - self.ryu_bgp_driver.add_bgp_speaker, - FAKE_LOCAL_AS2) - self.assertRaises(bgp_driver_exc.BgpSpeakerNotAdded, - self.ryu_bgp_driver.delete_bgp_speaker, - FAKE_LOCAL_AS2) - self.assertEqual(1, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) - self.ryu_bgp_driver.delete_bgp_speaker(FAKE_LOCAL_AS1) - self.assertEqual(0, - self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count()) diff --git a/neutron/tests/unit/services/bgp/driver/test_utils.py b/neutron/tests/unit/services/bgp/driver/test_utils.py deleted file mode 100644 index 34bd854dbc1..00000000000 --- a/neutron/tests/unit/services/bgp/driver/test_utils.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2016 Huawei Technologies India Pvt. Ltd. -# -# 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.services.bgp.driver import utils -from neutron.tests import base - -FAKE_LOCAL_AS = 12345 -FAKE_RYU_SPEAKER = {} - - -class TestBgpMultiSpeakerCache(base.BaseTestCase): - - def setUp(self): - super(TestBgpMultiSpeakerCache, self).setUp() - self.expected_cache = {FAKE_LOCAL_AS: FAKE_RYU_SPEAKER} - self.bs_cache = utils.BgpMultiSpeakerCache() - - def test_put_bgp_speaker(self): - self.bs_cache.put_bgp_speaker(FAKE_LOCAL_AS, FAKE_RYU_SPEAKER) - self.assertEqual(self.expected_cache, self.bs_cache.cache) - - def test_remove_bgp_speaker(self): - self.bs_cache.put_bgp_speaker(FAKE_LOCAL_AS, FAKE_RYU_SPEAKER) - self.assertEqual(1, len(self.bs_cache.cache)) - self.bs_cache.remove_bgp_speaker(FAKE_LOCAL_AS) - self.assertEqual(0, len(self.bs_cache.cache)) - - def test_get_bgp_speaker(self): - self.bs_cache.put_bgp_speaker(FAKE_LOCAL_AS, FAKE_RYU_SPEAKER) - self.assertEqual( - FAKE_RYU_SPEAKER, - self.bs_cache.get_bgp_speaker(FAKE_LOCAL_AS)) - - def test_get_hosted_bgp_speakers_count(self): - self.bs_cache.put_bgp_speaker(FAKE_LOCAL_AS, FAKE_RYU_SPEAKER) - self.assertEqual(1, self.bs_cache.get_hosted_bgp_speakers_count()) diff --git a/neutron/tests/unit/services/bgp/scheduler/__init__.py b/neutron/tests/unit/services/bgp/scheduler/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/unit/services/bgp/scheduler/test_bgp_dragent_scheduler.py b/neutron/tests/unit/services/bgp/scheduler/test_bgp_dragent_scheduler.py deleted file mode 100644 index 47ac21d0a20..00000000000 --- a/neutron/tests/unit/services/bgp/scheduler/test_bgp_dragent_scheduler.py +++ /dev/null @@ -1,224 +0,0 @@ -# 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. - -import testscenarios - -from oslo_utils import importutils - -from neutron import context -from neutron.db import bgp_db -from neutron.db import bgp_dragentscheduler_db as bgp_dras_db -from neutron.services.bgp.scheduler import bgp_dragent_scheduler as bgp_dras -from neutron.tests.common import helpers -from neutron.tests.unit import testlib_api - -# Required to generate tests from scenarios. Not compatible with nose. -load_tests = testscenarios.load_tests_apply_scenarios - - -class TestBgpDrAgentSchedulerBaseTestCase(testlib_api.SqlTestCase): - - def setUp(self): - super(TestBgpDrAgentSchedulerBaseTestCase, self).setUp() - self.ctx = context.get_admin_context() - self.bgp_speaker = {'id': 'foo_bgp_speaker_id'} - self.bgp_speaker_id = 'foo_bgp_speaker_id' - self._save_bgp_speaker(self.bgp_speaker_id) - - def _create_and_set_agents_down(self, hosts, down_agent_count=0, - admin_state_up=True): - agents = [] - for i, host in enumerate(hosts): - is_alive = i >= down_agent_count - agents.append(helpers.register_bgp_dragent( - host, - admin_state_up=admin_state_up, - alive=is_alive)) - return agents - - def _save_bgp_speaker(self, bgp_speaker_id): - cls = bgp_db.BgpDbMixin() - bgp_speaker_body = {'bgp_speaker': { - 'name': 'fake_bgp_speaker', - 'ip_version': '4', - 'local_as': '123', - 'advertise_floating_ip_host_routes': '0', - 'advertise_tenant_networks': '0', - 'peers': [], - 'networks': []}} - cls._save_bgp_speaker(self.ctx, bgp_speaker_body, uuid=bgp_speaker_id) - - def _test_schedule_bind_bgp_speaker(self, agents, bgp_speaker_id): - scheduler = bgp_dras.ChanceScheduler() - scheduler.resource_filter.bind(self.ctx, agents, bgp_speaker_id) - results = self.ctx.session.query( - bgp_dras_db.BgpSpeakerDrAgentBinding).filter_by( - bgp_speaker_id=bgp_speaker_id).all() - - for result in results: - self.assertEqual(bgp_speaker_id, result.bgp_speaker_id) - - -class TestBgpDrAgentScheduler(TestBgpDrAgentSchedulerBaseTestCase, - bgp_db.BgpDbMixin): - - def test_schedule_bind_bgp_speaker_single_agent(self): - agents = self._create_and_set_agents_down(['host-a']) - self._test_schedule_bind_bgp_speaker(agents, self.bgp_speaker_id) - - def test_schedule_bind_bgp_speaker_multi_agents(self): - agents = self._create_and_set_agents_down(['host-a', 'host-b']) - self._test_schedule_bind_bgp_speaker(agents, self.bgp_speaker_id) - - -class TestBgpAgentFilter(TestBgpDrAgentSchedulerBaseTestCase, - bgp_db.BgpDbMixin, - bgp_dras_db.BgpDrAgentSchedulerDbMixin): - - def setUp(self): - super(TestBgpAgentFilter, self).setUp() - self.bgp_drscheduler = importutils.import_object( - 'neutron.services.bgp.scheduler.' - 'bgp_dragent_scheduler.ChanceScheduler' - ) - self.plugin = self - - def _test_filter_agents_helper(self, bgp_speaker, - expected_filtered_dragent_ids=None, - expected_num_agents=1): - filtered_agents = ( - self.plugin.bgp_drscheduler.resource_filter.filter_agents( - self.plugin, self.ctx, bgp_speaker)) - self.assertEqual(expected_num_agents, - filtered_agents['n_agents']) - actual_filtered_dragent_ids = [ - agent.id for agent in filtered_agents['hostable_agents']] - if expected_filtered_dragent_ids is None: - expected_filtered_dragent_ids = [] - self.assertEqual(len(expected_filtered_dragent_ids), - len(actual_filtered_dragent_ids)) - for filtered_agent_id in actual_filtered_dragent_ids: - self.assertIn(filtered_agent_id, expected_filtered_dragent_ids) - - def test_filter_agents_single_agent(self): - agents = self._create_and_set_agents_down(['host-a']) - expected_filtered_dragent_ids = [agents[0].id] - self._test_filter_agents_helper( - self.bgp_speaker, - expected_filtered_dragent_ids=expected_filtered_dragent_ids) - - def test_filter_agents_no_agents(self): - expected_filtered_dragent_ids = [] - self._test_filter_agents_helper( - self.bgp_speaker, - expected_filtered_dragent_ids=expected_filtered_dragent_ids, - expected_num_agents=0) - - def test_filter_agents_two_agents(self): - agents = self._create_and_set_agents_down(['host-a', 'host-b']) - expected_filtered_dragent_ids = [agent.id for agent in agents] - self._test_filter_agents_helper( - self.bgp_speaker, - expected_filtered_dragent_ids=expected_filtered_dragent_ids) - - def test_filter_agents_agent_already_scheduled(self): - agents = self._create_and_set_agents_down(['host-a', 'host-b']) - self._test_schedule_bind_bgp_speaker([agents[0]], self.bgp_speaker_id) - self._test_filter_agents_helper(self.bgp_speaker, - expected_num_agents=0) - - def test_filter_agents_multiple_agents_bgp_speakers(self): - agents = self._create_and_set_agents_down(['host-a', 'host-b']) - self._test_schedule_bind_bgp_speaker([agents[0]], self.bgp_speaker_id) - bgp_speaker = {'id': 'bar-speaker-id'} - self._save_bgp_speaker(bgp_speaker['id']) - expected_filtered_dragent_ids = [agents[1].id] - self._test_filter_agents_helper( - bgp_speaker, - expected_filtered_dragent_ids=expected_filtered_dragent_ids) - - -class TestAutoScheduleBgpSpeakers(TestBgpDrAgentSchedulerBaseTestCase): - """Unit test scenarios for schedule_unscheduled_bgp_speakers. - - bgp_speaker_present - BGP speaker is present or not - - scheduled_already - BGP speaker is already scheduled to the agent or not - - agent_down - BGP DRAgent is down or alive - - valid_host - If true, then an valid host is passed to schedule BGP speaker, - else an invalid host is passed. - """ - scenarios = [ - ('BGP speaker present', - dict(bgp_speaker_present=True, - scheduled_already=False, - agent_down=False, - valid_host=True, - expected_result=True)), - - ('No BGP speaker', - dict(bgp_speaker_present=False, - scheduled_already=False, - agent_down=False, - valid_host=True, - expected_result=False)), - - ('BGP speaker already scheduled', - dict(bgp_speaker_present=True, - scheduled_already=True, - agent_down=False, - valid_host=True, - expected_result=False)), - - ('BGP DR agent down', - dict(bgp_speaker_present=True, - scheduled_already=False, - agent_down=True, - valid_host=False, - expected_result=False)), - - ('Invalid host', - dict(bgp_speaker_present=True, - scheduled_already=False, - agent_down=False, - valid_host=False, - expected_result=False)), - ] - - def test_auto_schedule_bgp_speaker(self): - scheduler = bgp_dras.ChanceScheduler() - if self.bgp_speaker_present: - down_agent_count = 1 if self.agent_down else 0 - agents = self._create_and_set_agents_down( - ['host-a'], down_agent_count=down_agent_count) - if self.scheduled_already: - self._test_schedule_bind_bgp_speaker(agents, - self.bgp_speaker_id) - - expected_hosted_agents = (1 if self.bgp_speaker_present and - self.valid_host else 0) - host = "host-a" if self.valid_host else "host-b" - observed_ret_value = scheduler.schedule_unscheduled_bgp_speakers( - self.ctx, host) - self.assertEqual(self.expected_result, observed_ret_value) - hosted_agents = self.ctx.session.query( - bgp_dras_db.BgpSpeakerDrAgentBinding).all() - self.assertEqual(expected_hosted_agents, len(hosted_agents)) diff --git a/setup.cfg b/setup.cfg index 88383d146df..f1f69e8384d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,7 +40,6 @@ scripts = [entry_points] console_scripts = - neutron-bgp-dragent = neutron.cmd.eventlet.agents.bgp_dragent:main neutron-db-manage = neutron.db.migration.cli:main neutron-debug = neutron.debug.shell:main neutron-dhcp-agent = neutron.cmd.eventlet.agents.dhcp:main @@ -77,7 +76,6 @@ neutron.service_plugins = neutron.services.loadbalancer.plugin.LoadBalancerPlugin = neutron_lbaas.services.loadbalancer.plugin:LoadBalancerPlugin neutron.services.vpn.plugin.VPNDriverPlugin = neutron_vpnaas.services.vpn.plugin:VPNDriverPlugin qos = neutron.services.qos.qos_plugin:QoSPlugin - bgp = neutron.services.bgp.bgp_plugin:BgpPlugin tag = neutron.services.tag.tag_plugin:TagPlugin flavors = neutron.services.flavors.flavors_plugin:FlavorsPlugin auto_allocate = neutron.services.auto_allocate.plugin:Plugin @@ -134,7 +132,6 @@ oslo.config.opts = neutron = neutron.opts:list_opts neutron.agent = neutron.opts:list_agent_opts neutron.base.agent = neutron.opts:list_base_agent_opts - neutron.bgp.agent = neutron.services.bgp.common.opts:list_bgp_agent_opts neutron.db = neutron.opts:list_db_opts neutron.dhcp.agent = neutron.opts:list_dhcp_agent_opts neutron.extensions = neutron.opts:list_extension_opts