Remove ryu plugin

Ryu plugin was marked deprecated in Juno.
This commit actually removes the code for Kilo.

We (Ryu team) recommend users to migrate to ofagent, on which
we aim to concentrate our development resources by this deprecation.

DocImpact
Partial-Bug: #1391714
Change-Id: I4916ce3c246730dc00516404471f8a1a008e27b6
This commit is contained in:
YAMAMOTO Takashi 2014-11-10 13:32:26 +09:00
parent 2dde3601d6
commit a843f7cf08
24 changed files with 49 additions and 1898 deletions

View File

@ -1,44 +0,0 @@
[ovs]
# integration_bridge = br-int
# openflow_rest_api = <host IP address of ofp rest api service>:<port: 8080>
# openflow_rest_api = 127.0.0.1:8080
# tunnel key range: 0 < tunnel_key_min < tunnel_key_max
# VLAN: 12bits, GRE, VXLAN: 24bits
# tunnel_key_min = 1
# tunnel_key_max = 0xffffff
# tunnel_ip = <ip address for tunneling>
# tunnel_interface = interface for tunneling
# when tunnel_ip is NOT specified, ip address is read
# from this interface
# tunnel_ip =
# tunnel_interface =
tunnel_interface = eth0
# ovsdb_port = port number on which ovsdb is listening
# ryu-agent uses this parameter to setup ovsdb.
# ovs-vsctl set-manager ptcp:<ovsdb_port>
# See set-manager section of man ovs-vsctl for details.
# currently ptcp is only supported.
# ovsdb_ip = <host IP address on which ovsdb is listening>
# ovsdb_interface = interface for ovsdb
# when ovsdb_addr NOT specifiied, ip address is gotten
# from this interface
# ovsdb_port = 6634
# ovsdb_ip =
# ovsdb_interface =
ovsdb_interface = eth0
[securitygroup]
# Firewall driver for realizing neutron security group function
# firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
# Controls if neutron security group is enabled or not.
# It should be false when you use nova security group.
# enable_security_group = True
[agent]
# Agent's polling interval in seconds
# polling_interval = 2

View File

@ -1,21 +0,0 @@
# neutron-rootwrap command filters for nodes on which neutron is
# expected to control network
#
# This file should be owned by (and only-writeable by) the root user
# format seems to be
# cmd-name: filter-name, raw-command, user, args
[Filters]
# ryu-agent
# unclear whether both variants are necessary, but I'm transliterating
# from the old mechanism
# neutron/plugins/ryu/agent/ryu_neutron_agent.py:
# "ovs-vsctl", "--timeout=2", ...
ovs-vsctl: CommandFilter, ovs-vsctl, root
# neutron/plugins/ryu/agent/ryu_neutron_agent.py:
# "xe", "vif-param-get", ...
xe: CommandFilter, xe, root

View File

@ -0,0 +1,48 @@
# Copyright 2014 OpenStack Foundation
#
# 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.
#
"""remove ryu plugin
Revision ID: 408cfbf6923c
Revises: 1f71e54a85e7
Create Date: 2014-11-10 13:17:12.709642
"""
# revision identifiers, used by Alembic.
revision = '408cfbf6923c'
down_revision = '1f71e54a85e7'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.drop_table('tunnelkeylasts')
op.drop_table('tunnelkeys')
def downgrade():
op.create_table(
'tunnelkeylasts',
sa.Column('last_key', sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('last_key'))
op.create_table(
'tunnelkeys',
sa.Column('network_id', sa.String(length=36), nullable=False),
sa.Column('tunnel_key', sa.Integer(), autoincrement=False,
nullable=False),
sa.ForeignKeyConstraint(['network_id'], ['networks.id'], ),
sa.PrimaryKeyConstraint('tunnel_key'))

View File

@ -1 +1 @@
1f71e54a85e7
408cfbf6923c

View File

@ -73,7 +73,6 @@ from neutron.plugins.nec.db import packetfilter as nec_packetfilter # noqa
from neutron.plugins.nec.db import router # noqa
from neutron.plugins.nuage import nuage_models # noqa
from neutron.plugins.openvswitch import ovs_models_v2 # noqa
from neutron.plugins.ryu.db import models_v2 as ryu_models_v2 # noqa
from neutron.plugins.vmware.dbexts import lsn_db # noqa
from neutron.plugins.vmware.dbexts import maclearning # noqa
from neutron.plugins.vmware.dbexts import models as vmware_models # noqa

View File

@ -1,22 +0,0 @@
Neutron plugin for Ryu Network Operating System
This directory includes neutron plugin for Ryu Network Operating System.
# -- Installation
For how to install/set up this plugin with Ryu and OpenStack, please refer to
https://github.com/osrg/ryu/wiki/OpenStack
# -- Ryu General
For general Ryu stuff, please refer to
http://osrg.github.io/ryu/
Ryu is available at github
git://github.com/osrg/ryu.git
https://github.com/osrg/ryu
The mailing is at
ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel
Enjoy!

View File

@ -1,312 +0,0 @@
#!/usr/bin/env python
# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
# Based on openvswitch agent.
#
# Copyright 2011 VMware, Inc.
# 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 httplib
import socket
import sys
import time
import eventlet
eventlet.monkey_patch()
from oslo.config import cfg
from ryu.app import client
from ryu.app import conf_switch_key
from ryu.app import rest_nw_id
from neutron.agent.linux import ip_lib
from neutron.agent.linux import ovs_lib
from neutron.agent import rpc as agent_rpc
from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.common import config as common_config
from neutron.common import exceptions as n_exc
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron import context as q_context
from neutron.extensions import securitygroup as ext_sg
from neutron.openstack.common import log
from neutron.plugins.ryu.common import config # noqa
LOG = log.getLogger(__name__)
# This is copied of nova.flags._get_my_ip()
# Agent shouldn't depend on nova module
def _get_my_ip():
"""Return the actual ip of the local machine.
This code figures out what source address would be used if some traffic
were to be sent out to some well known address on the Internet. In this
case, a Google DNS server is used, but the specific address does not
matter much. No traffic is actually sent.
"""
csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
csock.connect(('8.8.8.8', 80))
(addr, _port) = csock.getsockname()
csock.close()
return addr
def _get_ip_from_nic(nic):
ip_wrapper = ip_lib.IPWrapper()
dev = ip_wrapper.device(nic)
addrs = dev.addr.list(scope='global')
for addr in addrs:
if addr['ip_version'] == 4:
return addr['cidr'].split('/')[0]
def _get_ip(cfg_ip_str, cfg_interface_str):
ip = None
try:
ip = getattr(cfg.CONF.OVS, cfg_ip_str)
except (cfg.NoSuchOptError, cfg.NoSuchGroupError):
pass
if ip:
return ip
iface = None
try:
iface = getattr(cfg.CONF.OVS, cfg_interface_str)
except (cfg.NoSuchOptError, cfg.NoSuchGroupError):
pass
if iface:
ip = _get_ip_from_nic(iface)
if ip:
return ip
LOG.warning(_('Could not get IPv4 address from %(nic)s: %(cfg)s'),
{'nic': iface, 'cfg': cfg_interface_str})
return _get_my_ip()
def _get_tunnel_ip():
return _get_ip('tunnel_ip', 'tunnel_interface')
def _get_ovsdb_ip():
return _get_ip('ovsdb_ip', 'ovsdb_interface')
class OVSBridge(ovs_lib.OVSBridge):
def __init__(self, br_name, root_helper):
ovs_lib.OVSBridge.__init__(self, br_name, root_helper)
self.datapath_id = None
def find_datapath_id(self):
self.datapath_id = self.get_datapath_id()
def set_manager(self, target):
self.run_vsctl(["set-manager", target])
def get_ofport(self, name):
return self.db_get_val("Interface", name, "ofport")
def _get_ports(self, get_port):
ports = []
port_names = self.get_port_name_list()
for name in port_names:
if self.get_ofport(name) < 0:
continue
port = get_port(name)
if port:
ports.append(port)
return ports
def _get_external_port(self, name):
# exclude vif ports
external_ids = self.db_get_map("Interface", name, "external_ids")
if external_ids:
return
# exclude tunnel ports
options = self.db_get_map("Interface", name, "options")
if "remote_ip" in options:
return
ofport = self.get_ofport(name)
return ovs_lib.VifPort(name, ofport, None, None, self)
def get_external_ports(self):
return self._get_ports(self._get_external_port)
class VifPortSet(object):
def __init__(self, int_br, ryu_rest_client):
super(VifPortSet, self).__init__()
self.int_br = int_br
self.api = ryu_rest_client
def setup(self):
for port in self.int_br.get_external_ports():
LOG.debug(_('External port %s'), port)
self.api.update_port(rest_nw_id.NW_ID_EXTERNAL,
port.switch.datapath_id, port.ofport)
class RyuPluginApi(agent_rpc.PluginApi,
sg_rpc.SecurityGroupServerRpcApiMixin):
def get_ofp_rest_api_addr(self, context):
LOG.debug(_("Get Ryu rest API address"))
cctxt = self.client.prepare()
return cctxt.call(context, 'get_ofp_rest_api')
class RyuSecurityGroupAgent(sg_rpc.SecurityGroupAgentRpcMixin):
def __init__(self, context, plugin_rpc, root_helper):
self.context = context
self.plugin_rpc = plugin_rpc
self.root_helper = root_helper
self.init_firewall()
class OVSNeutronOFPRyuAgent(n_rpc.RpcCallback,
sg_rpc.SecurityGroupAgentRpcCallbackMixin):
RPC_API_VERSION = '1.1'
def __init__(self, integ_br, tunnel_ip, ovsdb_ip, ovsdb_port,
polling_interval, root_helper):
super(OVSNeutronOFPRyuAgent, self).__init__()
self.polling_interval = polling_interval
self._setup_rpc()
self.sg_agent = RyuSecurityGroupAgent(self.context,
self.plugin_rpc,
root_helper)
self._setup_integration_br(root_helper, integ_br, tunnel_ip,
ovsdb_port, ovsdb_ip)
def _setup_rpc(self):
self.topic = topics.AGENT
self.plugin_rpc = RyuPluginApi(topics.PLUGIN)
self.context = q_context.get_admin_context_without_session()
self.endpoints = [self]
consumers = [[topics.PORT, topics.UPDATE],
[topics.SECURITY_GROUP, topics.UPDATE]]
self.connection = agent_rpc.create_consumers(self.endpoints,
self.topic,
consumers)
def _setup_integration_br(self, root_helper, integ_br,
tunnel_ip, ovsdb_port, ovsdb_ip):
self.int_br = OVSBridge(integ_br, root_helper)
self.int_br.find_datapath_id()
rest_api_addr = self.plugin_rpc.get_ofp_rest_api_addr(self.context)
if not rest_api_addr:
raise n_exc.Invalid(_("Ryu rest API port isn't specified"))
LOG.debug(_("Going to ofp controller mode %s"), rest_api_addr)
ryu_rest_client = client.OFPClient(rest_api_addr)
self.vif_ports = VifPortSet(self.int_br, ryu_rest_client)
self.vif_ports.setup()
sc_client = client.SwitchConfClient(rest_api_addr)
sc_client.set_key(self.int_br.datapath_id,
conf_switch_key.OVS_TUNNEL_ADDR, tunnel_ip)
# Currently Ryu supports only tcp methods. (ssl isn't supported yet)
self.int_br.set_manager('ptcp:%d' % ovsdb_port)
sc_client.set_key(self.int_br.datapath_id, conf_switch_key.OVSDB_ADDR,
'tcp:%s:%d' % (ovsdb_ip, ovsdb_port))
def port_update(self, context, **kwargs):
LOG.debug(_("Port update received"))
port = kwargs.get('port')
vif_port = self.int_br.get_vif_port_by_id(port['id'])
if not vif_port:
return
if ext_sg.SECURITYGROUPS in port:
self.sg_agent.refresh_firewall()
def _update_ports(self, registered_ports):
ports = self.int_br.get_vif_port_set()
if ports == registered_ports:
return
added = ports - registered_ports
removed = registered_ports - ports
return {'current': ports,
'added': added,
'removed': removed}
def _process_devices_filter(self, port_info):
if 'added' in port_info:
self.sg_agent.prepare_devices_filter(port_info['added'])
if 'removed' in port_info:
self.sg_agent.remove_devices_filter(port_info['removed'])
def daemon_loop(self):
ports = set()
while True:
start = time.time()
try:
port_info = self._update_ports(ports)
if port_info:
LOG.debug(_("Agent loop has new device"))
self._process_devices_filter(port_info)
ports = port_info['current']
except Exception:
LOG.exception(_("Error in agent event loop"))
elapsed = max(time.time() - start, 0)
if (elapsed < self.polling_interval):
time.sleep(self.polling_interval - elapsed)
else:
LOG.debug(_("Loop iteration exceeded interval "
"(%(polling_interval)s vs. %(elapsed)s)!"),
{'polling_interval': self.polling_interval,
'elapsed': elapsed})
def main():
common_config.init(sys.argv[1:])
common_config.setup_logging()
integ_br = cfg.CONF.OVS.integration_bridge
polling_interval = cfg.CONF.AGENT.polling_interval
root_helper = cfg.CONF.AGENT.root_helper
tunnel_ip = _get_tunnel_ip()
LOG.debug(_('tunnel_ip %s'), tunnel_ip)
ovsdb_port = cfg.CONF.OVS.ovsdb_port
LOG.debug(_('ovsdb_port %s'), ovsdb_port)
ovsdb_ip = _get_ovsdb_ip()
LOG.debug(_('ovsdb_ip %s'), ovsdb_ip)
try:
agent = OVSNeutronOFPRyuAgent(integ_br, tunnel_ip, ovsdb_ip,
ovsdb_port, polling_interval,
root_helper)
except httplib.HTTPException as e:
LOG.error(_("Initialization failed: %s"), e)
sys.exit(1)
LOG.info(_("Ryu initialization on the node is done. "
"Agent initialized successfully, now running..."))
agent.daemon_loop()
sys.exit(0)
if __name__ == "__main__":
main()

View File

@ -1,50 +0,0 @@
# Copyright 2012 Red Hat, Inc.
#
# 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.agent.common import config
from neutron.agent.linux import ovs_lib # noqa
ovs_opts = [
cfg.StrOpt('integration_bridge', default='br-int',
help=_("Integration bridge to use.")),
cfg.StrOpt('openflow_rest_api', default='127.0.0.1:8080',
help=_("OpenFlow REST API location.")),
cfg.IntOpt('tunnel_key_min', default=1,
help=_("Minimum tunnel ID to use.")),
cfg.IntOpt('tunnel_key_max', default=0xffffff,
help=_("Maximum tunnel ID to use.")),
cfg.StrOpt('tunnel_ip',
help=_("Tunnel IP to use.")),
cfg.StrOpt('tunnel_interface',
help=_("Tunnel interface to use.")),
cfg.IntOpt('ovsdb_port', default=6634,
help=_("OVSDB port to connect to.")),
cfg.StrOpt('ovsdb_ip',
help=_("OVSDB IP to connect to.")),
cfg.StrOpt('ovsdb_interface',
help=_("OVSDB interface to connect to.")),
]
agent_opts = [
cfg.IntOpt('polling_interval', default=2,
help=_("The number of seconds the agent will wait between "
"polling for local device changes.")),
]
cfg.CONF.register_opts(ovs_opts, "OVS")
cfg.CONF.register_opts(agent_opts, "AGENT")
config.register_root_helper(cfg.CONF)

View File

@ -1,214 +0,0 @@
# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
# 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 sqlalchemy import exc as sa_exc
from sqlalchemy import func
from sqlalchemy.orm import exc as orm_exc
from neutron.common import exceptions as n_exc
import neutron.db.api as db
from neutron.db import models_v2
from neutron.db import securitygroups_db as sg_db
from neutron.extensions import securitygroup as ext_sg
from neutron import manager
from neutron.openstack.common import log as logging
from neutron.plugins.ryu.db import models_v2 as ryu_models_v2
LOG = logging.getLogger(__name__)
def network_all_tenant_list():
session = db.get_session()
return session.query(models_v2.Network).all()
def get_port_from_device(port_id):
LOG.debug(_("get_port_from_device() called:port_id=%s"), port_id)
session = db.get_session()
sg_binding_port = sg_db.SecurityGroupPortBinding.port_id
query = session.query(models_v2.Port,
sg_db.SecurityGroupPortBinding.security_group_id)
query = query.outerjoin(sg_db.SecurityGroupPortBinding,
models_v2.Port.id == sg_binding_port)
query = query.filter(models_v2.Port.id == port_id)
port_and_sgs = query.all()
if not port_and_sgs:
return None
port = port_and_sgs[0][0]
plugin = manager.NeutronManager.get_plugin()
port_dict = plugin._make_port_dict(port)
port_dict[ext_sg.SECURITYGROUPS] = [
sg_id for port_, sg_id in port_and_sgs if sg_id]
port_dict['security_group_rules'] = []
port_dict['security_group_source_groups'] = []
port_dict['fixed_ips'] = [ip['ip_address'] for ip in port['fixed_ips']]
return port_dict
class TunnelKey(object):
# VLAN: 12 bits
# GRE, VXLAN: 24bits
# TODO(yamahata): STT: 64bits
_KEY_MIN_HARD = 1
_KEY_MAX_HARD = 0xffffffff
def __init__(self, key_min=_KEY_MIN_HARD, key_max=_KEY_MAX_HARD):
self.key_min = key_min
self.key_max = key_max
if (key_min < self._KEY_MIN_HARD or key_max > self._KEY_MAX_HARD or
key_min > key_max):
raise ValueError(_('Invalid tunnel key options '
'tunnel_key_min: %(key_min)d '
'tunnel_key_max: %(key_max)d. '
'Using default value') % {'key_min': key_min,
'key_max': key_max})
def _last_key(self, session):
try:
return session.query(ryu_models_v2.TunnelKeyLast).one()
except orm_exc.MultipleResultsFound:
max_key = session.query(
func.max(ryu_models_v2.TunnelKeyLast.last_key))
if max_key > self.key_max:
max_key = self.key_min
session.query(ryu_models_v2.TunnelKeyLast).delete()
last_key = ryu_models_v2.TunnelKeyLast(last_key=max_key)
except orm_exc.NoResultFound:
last_key = ryu_models_v2.TunnelKeyLast(last_key=self.key_min)
session.add(last_key)
session.flush()
return session.query(ryu_models_v2.TunnelKeyLast).one()
def _find_key(self, session, last_key):
"""Try to find unused tunnel key.
Trying to find unused tunnel key in TunnelKey table starting
from last_key + 1.
When all keys are used, raise sqlalchemy.orm.exc.NoResultFound
"""
# key 0 is used for special meanings. So don't allocate 0.
# sqlite doesn't support
# '(select order by limit) union all (select order by limit) '
# 'order by limit'
# So do it manually
# new_key = session.query("new_key").from_statement(
# # If last_key + 1 isn't used, it's the result
# 'SELECT new_key '
# 'FROM (SELECT :last_key + 1 AS new_key) q1 '
# 'WHERE NOT EXISTS '
# '(SELECT 1 FROM tunnelkeys WHERE tunnel_key = :last_key + 1) '
#
# 'UNION ALL '
#
# # if last_key + 1 used,
# # find the least unused key from last_key + 1
# '(SELECT t.tunnel_key + 1 AS new_key '
# 'FROM tunnelkeys t '
# 'WHERE NOT EXISTS '
# '(SELECT 1 FROM tunnelkeys ti '
# ' WHERE ti.tunnel_key = t.tunnel_key + 1) '
# 'AND t.tunnel_key >= :last_key '
# 'ORDER BY new_key LIMIT 1) '
#
# 'ORDER BY new_key LIMIT 1'
# ).params(last_key=last_key).one()
try:
new_key = session.query("new_key").from_statement(
# If last_key + 1 isn't used, it's the result
'SELECT new_key '
'FROM (SELECT :last_key + 1 AS new_key) q1 '
'WHERE NOT EXISTS '
'(SELECT 1 FROM tunnelkeys WHERE tunnel_key = :last_key + 1) '
).params(last_key=last_key).one()
except orm_exc.NoResultFound:
new_key = session.query("new_key").from_statement(
# if last_key + 1 used,
# find the least unused key from last_key + 1
'(SELECT t.tunnel_key + 1 AS new_key '
'FROM tunnelkeys t '
'WHERE NOT EXISTS '
'(SELECT 1 FROM tunnelkeys ti '
' WHERE ti.tunnel_key = t.tunnel_key + 1) '
'AND t.tunnel_key >= :last_key '
'ORDER BY new_key LIMIT 1) '
).params(last_key=last_key).one()
new_key = new_key[0] # the result is tuple.
LOG.debug(_("last_key %(last_key)s new_key %(new_key)s"),
{'last_key': last_key, 'new_key': new_key})
if new_key > self.key_max:
LOG.debug(_("No key found"))
raise orm_exc.NoResultFound()
return new_key
def _allocate(self, session, network_id):
last_key = self._last_key(session)
try:
new_key = self._find_key(session, last_key.last_key)
except orm_exc.NoResultFound:
new_key = self._find_key(session, self.key_min)
tunnel_key = ryu_models_v2.TunnelKey(network_id=network_id,
tunnel_key=new_key)
last_key.last_key = new_key
session.add(tunnel_key)
return new_key
_TRANSACTION_RETRY_MAX = 16
def allocate(self, session, network_id):
count = 0
while True:
session.begin(subtransactions=True)
try:
new_key = self._allocate(session, network_id)
session.commit()
break
except sa_exc.SQLAlchemyError:
session.rollback()
count += 1
if count > self._TRANSACTION_RETRY_MAX:
# if this happens too often, increase _TRANSACTION_RETRY_MAX
LOG.warn(_("Transaction retry exhausted (%d). "
"Abandoned tunnel key allocation."), count)
raise n_exc.ResourceExhausted()
return new_key
def delete(self, session, network_id):
session.query(ryu_models_v2.TunnelKey).filter_by(
network_id=network_id).delete()
session.flush()
def all_list(self):
session = db.get_session()
return session.query(ryu_models_v2.TunnelKey).all()
def set_port_status(session, port_id, status):
try:
port = session.query(models_v2.Port).filter_by(id=port_id).one()
port['status'] = status
session.merge(port)
session.flush()
except orm_exc.NoResultFound:
raise n_exc.PortNotFound(port_id=port_id)

View File

@ -1,40 +0,0 @@
# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
# 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 sqlalchemy as sa
from neutron.db import model_base
class TunnelKeyLast(model_base.BASEV2):
"""Last allocated Tunnel key.
The next key allocation will be started from this value + 1
"""
last_key = sa.Column(sa.Integer, primary_key=True)
def __repr__(self):
return "<TunnelKeyLast(%x)>" % self.last_key
class TunnelKey(model_base.BASEV2):
"""Netowrk ID <-> tunnel key mapping."""
network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id"),
nullable=False)
tunnel_key = sa.Column(sa.Integer, primary_key=True,
nullable=False, autoincrement=False)
def __repr__(self):
return "<TunnelKey(%s,%x)>" % (self.network_id, self.tunnel_key)

View File

@ -1,276 +0,0 @@
# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
# <yamahata at valinux co jp>
# 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 ryu.app import client
from ryu.app import rest_nw_id
from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.api.rpc.handlers import dhcp_rpc
from neutron.api.rpc.handlers import l3_rpc
from neutron.api.rpc.handlers import metadata_rpc
from neutron.api.rpc.handlers import securitygroups_rpc
from neutron.common import constants as q_const
from neutron.common import exceptions as n_exc
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron.db import api as db
from neutron.db import db_base_plugin_v2
from neutron.db import external_net_db
from neutron.db import extraroute_db
from neutron.db import l3_gwmode_db
from neutron.db import models_v2
from neutron.db import portbindings_base
from neutron.db import securitygroups_rpc_base as sg_db_rpc
from neutron.extensions import portbindings
from neutron.openstack.common import excutils
from neutron.openstack.common import log as logging
from neutron.plugins.common import constants as svc_constants
from neutron.plugins.ryu.common import config # noqa
from neutron.plugins.ryu.db import api_v2 as db_api_v2
LOG = logging.getLogger(__name__)
class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin):
@classmethod
def get_port_from_device(cls, device):
port = db_api_v2.get_port_from_device(device)
if port:
port['device'] = device
return port
class RyuRpcCallbacks(n_rpc.RpcCallback):
RPC_API_VERSION = '1.1'
def __init__(self, ofp_rest_api_addr):
super(RyuRpcCallbacks, self).__init__()
self.ofp_rest_api_addr = ofp_rest_api_addr
def get_ofp_rest_api(self, context, **kwargs):
LOG.debug(_("get_ofp_rest_api: %s"), self.ofp_rest_api_addr)
return self.ofp_rest_api_addr
class AgentNotifierApi(n_rpc.RpcProxy,
sg_rpc.SecurityGroupAgentRpcApiMixin):
BASE_RPC_API_VERSION = '1.0'
def __init__(self, topic):
super(AgentNotifierApi, self).__init__(
topic=topic, default_version=self.BASE_RPC_API_VERSION)
self.topic_port_update = topics.get_topic_name(topic,
topics.PORT,
topics.UPDATE)
def port_update(self, context, port):
self.fanout_cast(context,
self.make_msg('port_update', port=port),
topic=self.topic_port_update)
class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
SecurityGroupServerRpcMixin,
portbindings_base.PortBindingBaseMixin):
_supported_extension_aliases = ["external-net", "router", "ext-gw-mode",
"extraroute", "security-group",
"binding", "quotas"]
@property
def supported_extension_aliases(self):
if not hasattr(self, '_aliases'):
aliases = self._supported_extension_aliases[:]
sg_rpc.disable_security_group_extension_by_config(aliases)
self._aliases = aliases
return self._aliases
def __init__(self, configfile=None):
super(RyuNeutronPluginV2, self).__init__()
self.base_binding_dict = self._get_base_binding_dict()
portbindings_base.register_port_dict_function()
self.tunnel_key = db_api_v2.TunnelKey(
cfg.CONF.OVS.tunnel_key_min, cfg.CONF.OVS.tunnel_key_max)
self.ofp_api_host = cfg.CONF.OVS.openflow_rest_api
if not self.ofp_api_host:
raise n_exc.Invalid(_('Invalid configuration. check ryu.ini'))
self.client = client.OFPClient(self.ofp_api_host)
self.tun_client = client.TunnelClient(self.ofp_api_host)
self.iface_client = client.NeutronIfaceClient(self.ofp_api_host)
for nw_id in rest_nw_id.RESERVED_NETWORK_IDS:
if nw_id != rest_nw_id.NW_ID_UNKNOWN:
self.client.update_network(nw_id)
self._setup_rpc()
# register known all network list on startup
self._create_all_tenant_network()
def _get_base_binding_dict(self):
sg_enabled = sg_rpc.is_firewall_enabled()
vif_details = {portbindings.CAP_PORT_FILTER: sg_enabled,
portbindings.OVS_HYBRID_PLUG: sg_enabled}
binding = {portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
portbindings.VIF_DETAILS: vif_details}
return binding
def _setup_rpc(self):
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
self.conn = n_rpc.create_connection(new=True)
self.notifier = AgentNotifierApi(topics.AGENT)
self.endpoints = [RyuRpcCallbacks(self.ofp_api_host),
securitygroups_rpc.SecurityGroupServerRpcCallback(),
dhcp_rpc.DhcpRpcCallback(),
l3_rpc.L3RpcCallback(),
metadata_rpc.MetadataRpcCallback()]
for svc_topic in self.service_topics.values():
self.conn.create_consumer(svc_topic, self.endpoints, fanout=False)
self.conn.consume_in_threads()
def _create_all_tenant_network(self):
for net in db_api_v2.network_all_tenant_list():
self.client.update_network(net.id)
for tun in self.tunnel_key.all_list():
self.tun_client.update_tunnel_key(tun.network_id, tun.tunnel_key)
session = db.get_session()
for port in session.query(models_v2.Port):
self.iface_client.update_network_id(port.id, port.network_id)
def _client_create_network(self, net_id, tunnel_key):
self.client.create_network(net_id)
self.tun_client.create_tunnel_key(net_id, tunnel_key)
def _client_delete_network(self, net_id):
RyuNeutronPluginV2._safe_client_delete_network(self.safe_reference,
net_id)
@staticmethod
def _safe_client_delete_network(safe_reference, net_id):
# Avoid handing naked plugin references to the client. When
# the client is mocked for testing, such references can
# prevent the plugin from being deallocated.
client.ignore_http_not_found(
lambda: safe_reference.client.delete_network(net_id))
client.ignore_http_not_found(
lambda: safe_reference.tun_client.delete_tunnel_key(net_id))
def create_network(self, context, network):
session = context.session
with session.begin(subtransactions=True):
#set up default security groups
tenant_id = self._get_tenant_id_for_create(
context, network['network'])
self._ensure_default_security_group(context, tenant_id)
net = super(RyuNeutronPluginV2, self).create_network(context,
network)
self._process_l3_create(context, net, network['network'])
tunnel_key = self.tunnel_key.allocate(session, net['id'])
try:
self._client_create_network(net['id'], tunnel_key)
except Exception:
with excutils.save_and_reraise_exception():
self._client_delete_network(net['id'])
return net
def update_network(self, context, id, network):
session = context.session
with session.begin(subtransactions=True):
net = super(RyuNeutronPluginV2, self).update_network(context, id,
network)
self._process_l3_update(context, net, network['network'])
return net
def delete_network(self, context, id):
self._client_delete_network(id)
session = context.session
with session.begin(subtransactions=True):
self.tunnel_key.delete(session, id)
self._process_l3_delete(context, id)
super(RyuNeutronPluginV2, self).delete_network(context, id)
def create_port(self, context, port):
session = context.session
port_data = port['port']
with session.begin(subtransactions=True):
self._ensure_default_security_group_on_port(context, port)
sgids = self._get_security_groups_on_port(context, port)
port = super(RyuNeutronPluginV2, self).create_port(context, port)
self._process_portbindings_create_and_update(context,
port_data,
port)
self._process_port_create_security_group(
context, port, sgids)
self.notify_security_groups_member_updated(context, port)
self.iface_client.create_network_id(port['id'], port['network_id'])
return port
def delete_port(self, context, id, l3_port_check=True):
# if needed, check to see if this is a port owned by
# and l3-router. If so, we should prevent deletion.
if l3_port_check:
self.prevent_l3_port_deletion(context, id)
with context.session.begin(subtransactions=True):
router_ids = self.disassociate_floatingips(
context, id, do_notify=False)
port = self.get_port(context, id)
self._delete_port_security_group_bindings(context, id)
super(RyuNeutronPluginV2, self).delete_port(context, id)
# now that we've left db transaction, we are safe to notify
self.notify_routers_updated(context, router_ids)
self.notify_security_groups_member_updated(context, port)
def update_port(self, context, id, port):
deleted = port['port'].get('deleted', False)
session = context.session
need_port_update_notify = False
with session.begin(subtransactions=True):
original_port = super(RyuNeutronPluginV2, self).get_port(
context, id)
updated_port = super(RyuNeutronPluginV2, self).update_port(
context, id, port)
self._process_portbindings_create_and_update(context,
port['port'],
updated_port)
need_port_update_notify = self.update_security_group_on_port(
context, id, port, original_port, updated_port)
need_port_update_notify |= self.is_security_group_member_updated(
context, original_port, updated_port)
need_port_update_notify |= (original_port['admin_state_up'] !=
updated_port['admin_state_up'])
if need_port_update_notify:
self.notifier.port_update(context, updated_port)
if deleted:
db_api_v2.set_port_status(session, id, q_const.PORT_STATUS_DOWN)
return updated_port

View File

@ -118,8 +118,6 @@ class _TestModelsMigrations(test_migrations.ModelsMigrationsSync):
def setUp(self):
patch = mock.patch.dict('sys.modules', {
'ryu': mock.MagicMock(),
'ryu.app': mock.MagicMock(),
'heleosapi': mock.MagicMock(),
'midonetclient': mock.MagicMock(),
'midonetclient.neutron': mock.MagicMock(),

View File

@ -1,42 +0,0 @@
# Copyright (c) 2013 OpenStack Foundation.
#
# 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
def patch_fake_ryu_client():
ryu_mod = mock.Mock()
ryu_app_mod = ryu_mod.app
ryu_app_client = ryu_app_mod.client
conf_switch_key = ryu_app_mod.conf_switch_key
conf_switch_key.OVSDB_ADDR = 'ovsdb_addr'
conf_switch_key.OVS_TUNNEL_ADDR = 'ovs_tunnel_addr'
rest_nw_id = ryu_app_mod.rest_nw_id
rest_nw_id.NW_ID_EXTERNAL = '__NW_ID_EXTERNAL__'
rest_nw_id.NW_ID_RESERVED = '__NW_ID_RESERVED__'
rest_nw_id.NW_ID_VPORT_GRE = '__NW_ID_VPORT_GRE__'
rest_nw_id.NW_ID_UNKNOWN = '__NW_ID_UNKNOWN__'
rest_nw_id.RESERVED_NETWORK_IDS = [
rest_nw_id.NW_ID_EXTERNAL,
rest_nw_id.NW_ID_RESERVED,
rest_nw_id.NW_ID_VPORT_GRE,
rest_nw_id.NW_ID_UNKNOWN,
]
return mock.patch.dict('sys.modules',
{'ryu': ryu_mod,
'ryu.app': ryu_app_mod,
'ryu.app.client': ryu_app_client,
'ryu.app.conf_switch_key': conf_switch_key,
'ryu.app.rest_nw_id': rest_nw_id})

View File

@ -1,31 +0,0 @@
# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
# 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 neutron.plugins.ryu.common import config # noqa
from neutron.tests import base
class ConfigurationTest(base.BaseTestCase):
"""Configuration file Tests."""
def test_defaults(self):
self.assertEqual('br-int', cfg.CONF.OVS.integration_bridge)
self.assertEqual(2, cfg.CONF.AGENT.polling_interval)
self.assertEqual('sudo', cfg.CONF.AGENT.root_helper)
self.assertEqual('127.0.0.1:8080', cfg.CONF.OVS.openflow_rest_api)
self.assertEqual(1, cfg.CONF.OVS.tunnel_key_min)
self.assertEqual(0xffffff, cfg.CONF.OVS.tunnel_key_max)
self.assertEqual(6634, cfg.CONF.OVS.ovsdb_port)

View File

@ -1,648 +0,0 @@
# Copyright (c) 2013 OpenStack Foundation.
#
# 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 httplib
import mock
from neutron.openstack.common import importutils
from neutron.tests import base
from neutron.tests.unit.ryu import fake_ryu
class RyuAgentTestCase(base.BaseTestCase):
_AGENT_NAME = 'neutron.plugins.ryu.agent.ryu_neutron_agent'
def setUp(self):
super(RyuAgentTestCase, self).setUp()
self.fake_ryu = fake_ryu.patch_fake_ryu_client().start()
self.mod_agent = importutils.import_module(self._AGENT_NAME)
class TestOVSNeutronOFPRyuAgent(RyuAgentTestCase):
def setUp(self):
super(TestOVSNeutronOFPRyuAgent, self).setUp()
self.plugin_api = mock.patch(
self._AGENT_NAME + '.RyuPluginApi').start()
self.ovsbridge = mock.patch(
self._AGENT_NAME + '.OVSBridge').start()
self.vifportset = mock.patch(
self._AGENT_NAME + '.VifPortSet').start()
self.q_ctx = mock.patch(
self._AGENT_NAME + '.q_context').start()
self.agent_rpc = mock.patch(
self._AGENT_NAME + '.agent_rpc.create_consumers').start()
self.sg_rpc = mock.patch(
self._AGENT_NAME + '.sg_rpc').start()
self.sg_agent = mock.patch(
self._AGENT_NAME + '.RyuSecurityGroupAgent').start()
def mock_rest_addr(self, rest_addr):
integ_br = 'integ_br'
tunnel_ip = '192.168.0.1'
ovsdb_ip = '172.16.0.1'
ovsdb_port = 16634
interval = 2
root_helper = 'helper'
self.mod_agent.OVSBridge.return_value.datapath_id = '1234'
mock_context = mock.Mock(return_value='abc')
self.q_ctx.get_admin_context_without_session = mock_context
mock_rest_addr = mock.Mock(return_value=rest_addr)
self.plugin_api.return_value.get_ofp_rest_api_addr = mock_rest_addr
# Instantiate OVSNeutronOFPRyuAgent
return self.mod_agent.OVSNeutronOFPRyuAgent(
integ_br, tunnel_ip, ovsdb_ip, ovsdb_port, interval, root_helper)
def test_valid_rest_addr(self):
self.mock_rest_addr('192.168.0.1:8080')
# OVSBridge
self.ovsbridge.assert_has_calls([
mock.call('integ_br', 'helper'),
mock.call().find_datapath_id()
])
# RyuPluginRpc
self.plugin_api.assert_has_calls([
mock.call('q-plugin'),
mock.call().get_ofp_rest_api_addr('abc')
])
# Agent RPC
self.agent_rpc.assert_has_calls([
mock.call(mock.ANY, 'q-agent-notifier', mock.ANY)
])
# OFPClient
self.mod_agent.client.OFPClient.assert_has_calls([
mock.call('192.168.0.1:8080')
])
# VifPortSet
self.vifportset.assert_has_calls([
mock.call(
self.ovsbridge.return_value,
self.mod_agent.client.OFPClient.return_value),
mock.call().setup()
])
# SwitchConfClient
self.mod_agent.client.SwitchConfClient.assert_has_calls([
mock.call('192.168.0.1:8080'),
mock.call().set_key('1234', 'ovs_tunnel_addr', '192.168.0.1'),
mock.call().set_key('1234', 'ovsdb_addr',
'tcp:%s:%d' % ('172.16.0.1', 16634))
])
# OVSBridge
self.ovsbridge.return_value.set_manager.assert_has_calls([
mock.call('ptcp:%d' % 16634)
])
def test_invalid_rest_addr(self):
self.assertRaises(self.mod_agent.n_exc.Invalid,
self.mock_rest_addr, (''))
def mock_port_update(self, **kwargs):
agent = self.mock_rest_addr('192.168.0.1:8080')
agent.port_update(mock.Mock(), **kwargs)
def test_port_update(self, **kwargs):
port = {'id': 1, 'security_groups': 'default'}
with mock.patch.object(self.ovsbridge.return_value,
'get_vif_port_by_id',
return_value=1) as get_vif:
self.mock_port_update(port=port)
get_vif.assert_called_once_with(1)
self.sg_agent.assert_has_calls([
mock.call().refresh_firewall()
])
def test_port_update_not_vifport(self, **kwargs):
port = {'id': 1, 'security_groups': 'default'}
with mock.patch.object(self.ovsbridge.return_value,
'get_vif_port_by_id',
return_value=0) as get_vif:
self.mock_port_update(port=port)
get_vif.assert_called_once_with(1)
self.assertFalse(self.sg_agent.return_value.refresh_firewall.called)
def test_port_update_without_secgroup(self, **kwargs):
port = {'id': 1}
with mock.patch.object(self.ovsbridge.return_value,
'get_vif_port_by_id',
return_value=1) as get_vif:
self.mock_port_update(port=port)
get_vif.assert_called_once_with(1)
self.assertFalse(self.sg_agent.return_value.refresh_firewall.called)
def mock_update_ports(self, vif_port_set=None, registered_ports=None):
with mock.patch.object(self.ovsbridge.return_value,
'get_vif_port_set',
return_value=vif_port_set):
agent = self.mock_rest_addr('192.168.0.1:8080')
return agent._update_ports(registered_ports)
def test_update_ports_unchanged(self):
self.assertIsNone(self.mock_update_ports())
def test_update_ports_changed(self):
vif_port_set = set([1, 3])
registered_ports = set([1, 2])
expected = dict(current=vif_port_set,
added=set([3]),
removed=set([2]))
actual = self.mock_update_ports(vif_port_set, registered_ports)
self.assertEqual(expected, actual)
def mock_process_devices_filter(self, port_info):
agent = self.mock_rest_addr('192.168.0.1:8080')
agent._process_devices_filter(port_info)
def test_process_devices_filter_add(self):
port_info = {'added': 1}
self.mock_process_devices_filter(port_info)
self.sg_agent.assert_has_calls([
mock.call().prepare_devices_filter(1)
])
def test_process_devices_filter_remove(self):
port_info = {'removed': 2}
self.mock_process_devices_filter(port_info)
self.sg_agent.assert_has_calls([
mock.call().remove_devices_filter(2)
])
def test_process_devices_filter_both(self):
port_info = {'added': 1, 'removed': 2}
self.mock_process_devices_filter(port_info)
self.sg_agent.assert_has_calls([
mock.call().prepare_devices_filter(1),
mock.call().remove_devices_filter(2)
])
def test_process_devices_filter_none(self):
port_info = {}
self.mock_process_devices_filter(port_info)
self.assertFalse(
self.sg_agent.return_value.prepare_devices_filter.called)
self.assertFalse(
self.sg_agent.return_value.remove_devices_filter.called)
class TestRyuPluginApi(RyuAgentTestCase):
def test_get_ofp_rest_api_addr(self):
rpcapi = self.mod_agent.RyuPluginApi('foo')
with contextlib.nested(
mock.patch.object(rpcapi.client, 'call'),
mock.patch.object(rpcapi.client, 'prepare'),
) as (
rpc_mock, prepare_mock
):
prepare_mock.return_value = rpcapi.client
rpc_mock.return_value = 'return'
addr = rpcapi.get_ofp_rest_api_addr('context')
self.assertEqual('return', addr)
rpc_mock.assert_called_once_with('context', 'get_ofp_rest_api')
class TestVifPortSet(RyuAgentTestCase):
def test_setup(self):
attrs = {'switch.datapath_id': 'dp1', 'ofport': 'p1'}
p1 = mock.Mock(**attrs)
attrs = {'switch.datapath_id': 'dp2', 'ofport': 'p2'}
p2 = mock.Mock(**attrs)
attrs = {'get_external_ports.return_value': [p1, p2]}
int_br = mock.Mock(**attrs)
with mock.patch(self._AGENT_NAME + '.client.OFPClient') as client:
api = client()
vif = self.mod_agent.VifPortSet(int_br, api)
vif.setup()
client.assert_has_calls([
mock.call().update_port('__NW_ID_EXTERNAL__', 'dp1', 'p1'),
mock.call().update_port('__NW_ID_EXTERNAL__', 'dp2', 'p2')
])
def test_setup_empty(self):
attrs = {'get_external_ports.return_value': []}
int_br = mock.Mock(**attrs)
api = mock.Mock()
vif = self.mod_agent.VifPortSet(int_br, api)
vif.setup()
self.assertEqual(api.update_port.call_count, 0)
class TestOVSBridge(RyuAgentTestCase):
def setUp(self):
super(TestOVSBridge, self).setUp()
self.lib_ovs = mock.patch(
'neutron.agent.linux.ovs_lib.OVSBridge').start()
def test_find_datapath_id(self):
with mock.patch(self._AGENT_NAME + '.OVSBridge.get_datapath_id',
return_value='1234') as mock_get_dpid:
br = self.mod_agent.OVSBridge('br_name', 'helper')
br.find_datapath_id()
mock_get_dpid.assert_has_calls([
mock.call()
])
self.assertEqual(br.datapath_id, '1234')
def test_set_manager(self):
with mock.patch(
self._AGENT_NAME + '.OVSBridge.run_vsctl') as mock_vsctl:
br = self.mod_agent.OVSBridge('br_name', 'helper')
br.set_manager('target')
mock_vsctl.assert_has_calls([
mock.call(['set-manager', 'target'])
])
def test_get_ofport(self):
with mock.patch(
self._AGENT_NAME + '.OVSBridge.db_get_val',
return_value=1) as mock_db:
br = self.mod_agent.OVSBridge('br_name', 'helper')
ofport = br.get_ofport('name')
mock_db.assert_has_calls([
mock.call('Interface', 'name', 'ofport')
])
self.assertEqual(ofport, 1)
def test_get_ports(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSBridge.get_port_name_list',
return_value=['p1', 'p2']),
mock.patch(self._AGENT_NAME + '.OVSBridge.get_ofport',
return_value=1)
) as (mock_name, mock_ofport):
get_port = mock.Mock(side_effect=['port1', 'port2'])
br = self.mod_agent.OVSBridge('br_name', 'helper')
ports = br._get_ports(get_port)
mock_name.assert_has_calls([
mock.call()
])
mock_ofport.assert_has_calls([
mock.call('p1'),
mock.call('p2')
])
get_port.assert_has_calls([
mock.call('p1'),
mock.call('p2')
])
self.assertEqual(len(ports), 2)
self.assertEqual(ports, ['port1', 'port2'])
def test_get_ports_empty(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSBridge.get_port_name_list',
return_value=[]),
mock.patch(self._AGENT_NAME + '.OVSBridge.get_ofport',
return_value=1)
) as (mock_name, mock_ofport):
get_port = mock.Mock(side_effect=['port1', 'port2'])
br = self.mod_agent.OVSBridge('br_name', 'helper')
ports = br._get_ports(get_port)
mock_name.assert_has_calls([
mock.call()
])
self.assertEqual(mock_ofport.call_count, 0)
self.assertEqual(get_port.call_count, 0)
self.assertEqual(len(ports), 0)
def test_get_ports_invalid_ofport(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSBridge.get_port_name_list',
return_value=['p1', 'p2']),
mock.patch(self._AGENT_NAME + '.OVSBridge.get_ofport',
side_effect=[-1, 1])
) as (mock_name, mock_ofport):
get_port = mock.Mock(side_effect=['port1', 'port2'])
br = self.mod_agent.OVSBridge('br_name', 'helper')
ports = br._get_ports(get_port)
mock_name.assert_has_calls([
mock.call()
])
mock_ofport.assert_has_calls([
mock.call('p1'),
mock.call('p2')
])
get_port.assert_has_calls([
mock.call('p2')
])
self.assertEqual(len(ports), 1)
self.assertEqual(ports, ['port1'])
def test_get_ports_invalid_port(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSBridge.get_port_name_list',
return_value=['p1', 'p2']),
mock.patch(self._AGENT_NAME + '.OVSBridge.get_ofport',
side_effect=[1, 2])
) as (mock_name, mock_ofport):
get_port = mock.Mock(side_effect=[None, 'port2'])
br = self.mod_agent.OVSBridge('br_name', 'helper')
ports = br._get_ports(get_port)
mock_name.assert_has_calls([
mock.call()
])
mock_ofport.assert_has_calls([
mock.call('p1'),
mock.call('p2')
])
get_port.assert_has_calls([
mock.call('p1'),
mock.call('p2')
])
self.assertEqual(len(ports), 1)
self.assertEqual(ports, ['port2'])
def test_get_external_port(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSBridge.db_get_map',
side_effect=[None, {'opts': 'opts_val'}]),
mock.patch(self._AGENT_NAME + '.OVSBridge.get_ofport',
return_value=1),
mock.patch('neutron.agent.linux.ovs_lib.VifPort')
) as (mock_db, mock_ofport, mock_vif):
br = self.mod_agent.OVSBridge('br_name', 'helper')
vifport = br._get_external_port('iface')
mock_db.assert_has_calls([
mock.call('Interface', 'iface', 'external_ids'),
mock.call('Interface', 'iface', 'options'),
])
mock_ofport.assert_has_calls([
mock.call('iface')
])
mock_vif.assert_has_calls([
mock.call('iface', 1, None, None, br)
])
self.assertEqual(vifport, mock_vif.return_value)
def test_get_external_port_vmport(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSBridge.db_get_map',
side_effect=[{'extids': 'extid_val'},
{'opts': 'opts_val'}]),
mock.patch(self._AGENT_NAME + '.OVSBridge.get_ofport',
return_value=1),
mock.patch('neutron.agent.linux.ovs_lib.VifPort')
) as (mock_db, mock_ofport, mock_vif):
br = self.mod_agent.OVSBridge('br_name', 'helper')
vifport = br._get_external_port('iface')
mock_db.assert_has_calls([
mock.call('Interface', 'iface', 'external_ids'),
])
self.assertEqual(mock_ofport.call_count, 0)
self.assertEqual(mock_vif.call_count, 0)
self.assertIsNone(vifport)
def test_get_external_port_tunnel(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSBridge.db_get_map',
side_effect=[None, {'remote_ip': '0.0.0.0'}]),
mock.patch(self._AGENT_NAME + '.OVSBridge.get_ofport',
return_value=1),
mock.patch('neutron.agent.linux.ovs_lib.VifPort')
) as (mock_db, mock_ofport, mock_vif):
br = self.mod_agent.OVSBridge('br_name', 'helper')
vifport = br._get_external_port('iface')
mock_db.assert_has_calls([
mock.call('Interface', 'iface', 'external_ids'),
mock.call('Interface', 'iface', 'options'),
])
self.assertEqual(mock_ofport.call_count, 0)
self.assertEqual(mock_vif.call_count, 0)
self.assertIsNone(vifport)
def test_get_external_ports(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSBridge._get_external_port'),
mock.patch(self._AGENT_NAME + '.OVSBridge._get_ports')
) as (mock_extport, mock_port):
br = self.mod_agent.OVSBridge('br_name', 'helper')
br.get_external_ports()
mock_port.assert_has_calls([
mock.call(mock_extport)
])
class TestRyuNeutronAgent(RyuAgentTestCase):
def test_get_my_ip(self):
sock_attrs = {
'return_value.getsockname.return_value': ['1.2.3.4', '']}
with mock.patch('socket.socket', **sock_attrs):
addr = self.mod_agent._get_my_ip()
self.assertEqual(addr, '1.2.3.4')
def test_get_ip_from_nic(self):
mock_device = mock.Mock()
mock_device.addr.list = mock.Mock(
return_value=[{'ip_version': 6, 'cidr': '::ffff:1.2.3.4'},
{'ip_version': 4, 'cidr': '1.2.3.4/8'}])
mock_ip_wrapper = mock.Mock()
mock_ip_wrapper.device = mock.Mock(return_value=mock_device)
with mock.patch(self._AGENT_NAME + '.ip_lib.IPWrapper',
return_value=mock_ip_wrapper):
addr = self.mod_agent._get_ip_from_nic('eth0')
self.assertEqual(addr, '1.2.3.4')
def test_get_ip_from_nic_empty(self):
mock_device = mock.Mock()
mock_device.addr.list = mock.Mock(return_value=[])
mock_ip_wrapper = mock.Mock()
mock_ip_wrapper.device = mock.Mock(return_value=mock_device)
with mock.patch(self._AGENT_NAME + '.ip_lib.IPWrapper',
return_value=mock_ip_wrapper):
addr = self.mod_agent._get_ip_from_nic('eth0')
self.assertIsNone(addr)
def test_get_ip_ip(self):
cfg_attrs = {'CONF.OVS.cfg_ip': '1.2.3.4',
'CONF.OVS.cfg_iface': 'eth0'}
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.cfg', **cfg_attrs),
mock.patch(self._AGENT_NAME + '._get_ip_from_nic',
return_value='10.0.0.1'),
mock.patch(self._AGENT_NAME + '._get_my_ip',
return_value='172.16.0.1')
) as (_cfg, mock_nicip, mock_myip):
ip = self.mod_agent._get_ip('cfg_ip', 'cfg_iface')
self.assertEqual(mock_nicip.call_count, 0)
self.assertEqual(mock_myip.call_count, 0)
self.assertEqual(ip, '1.2.3.4')
def test_get_ip_nic(self):
cfg_attrs = {'CONF.OVS.cfg_ip': None,
'CONF.OVS.cfg_iface': 'eth0'}
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.cfg', **cfg_attrs),
mock.patch(self._AGENT_NAME + '._get_ip_from_nic',
return_value='10.0.0.1'),
mock.patch(self._AGENT_NAME + '._get_my_ip',
return_value='172.16.0.1')
) as (_cfg, mock_nicip, mock_myip):
ip = self.mod_agent._get_ip('cfg_ip', 'cfg_iface')
mock_nicip.assert_has_calls([
mock.call('eth0')
])
self.assertEqual(mock_myip.call_count, 0)
self.assertEqual(ip, '10.0.0.1')
def test_get_ip_myip(self):
cfg_attrs = {'CONF.OVS.cfg_ip': None,
'CONF.OVS.cfg_iface': None}
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.cfg', **cfg_attrs),
mock.patch(self._AGENT_NAME + '._get_ip_from_nic',
return_value='10.0.0.1'),
mock.patch(self._AGENT_NAME + '._get_my_ip',
return_value='172.16.0.1')
) as (_cfg, mock_nicip, mock_myip):
ip = self.mod_agent._get_ip('cfg_ip', 'cfg_iface')
self.assertEqual(mock_nicip.call_count, 0)
mock_myip.assert_has_calls([
mock.call()
])
self.assertEqual(ip, '172.16.0.1')
def test_get_ip_nic_myip(self):
cfg_attrs = {'CONF.OVS.cfg_ip': None,
'CONF.OVS.cfg_iface': 'eth0'}
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.cfg', **cfg_attrs),
mock.patch(self._AGENT_NAME + '._get_ip_from_nic',
return_value=None),
mock.patch(self._AGENT_NAME + '._get_my_ip',
return_value='172.16.0.1')
) as (_cfg, mock_nicip, mock_myip):
ip = self.mod_agent._get_ip('cfg_ip', 'cfg_iface')
mock_nicip.assert_has_calls([
mock.call('eth0')
])
mock_myip.assert_has_calls([
mock.call()
])
self.assertEqual(ip, '172.16.0.1')
def test_get_tunnel_ip(self):
with mock.patch(self._AGENT_NAME + '._get_ip',
return_value='1.2.3.4') as mock_getip:
ip = self.mod_agent._get_tunnel_ip()
mock_getip.assert_has_calls([
mock.call('tunnel_ip', 'tunnel_interface')
])
self.assertEqual(ip, '1.2.3.4')
def test_get_ovsdb_ip(self):
with mock.patch(self._AGENT_NAME + '._get_ip',
return_value='1.2.3.4') as mock_getip:
ip = self.mod_agent._get_ovsdb_ip()
mock_getip.assert_has_calls([
mock.call('ovsdb_ip', 'ovsdb_interface')
])
self.assertEqual(ip, '1.2.3.4')
def mock_main(self):
cfg_attrs = {'CONF.OVS.integration_bridge': 'integ_br',
'CONF.OVS.ovsdb_port': 16634,
'CONF.AGENT.polling_interval': 2,
'CONF.AGENT.root_helper': 'helper'}
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.cfg', **cfg_attrs),
mock.patch(self._AGENT_NAME + '.common_config'),
mock.patch(self._AGENT_NAME + '._get_tunnel_ip',
return_value='10.0.0.1'),
mock.patch(self._AGENT_NAME + '._get_ovsdb_ip',
return_value='172.16.0.1'),
) as (mock_conf, mock_common_conf, _tun, _ovsdb):
self.mod_agent.main()
mock_common_conf.assert_has_calls([
mock.call(mock_conf)
])
def test_main(self):
agent_attrs = {'daemon_loop.side_effect': SystemExit(0)}
with mock.patch(self._AGENT_NAME + '.OVSNeutronOFPRyuAgent',
**agent_attrs) as mock_agent:
self.assertRaises(SystemExit, self.mock_main)
mock_agent.assert_has_calls([
mock.call('integ_br', '10.0.0.1', '172.16.0.1', 16634, 2,
'helper'),
mock.call().daemon_loop()
])
def test_main_raise(self):
with contextlib.nested(
mock.patch(self._AGENT_NAME + '.OVSNeutronOFPRyuAgent',
side_effect=httplib.HTTPException('boom')),
mock.patch('sys.exit', side_effect=SystemExit(0))
) as (mock_agent, mock_exit):
self.assertRaises(SystemExit, self.mock_main)
mock_agent.assert_has_calls([
mock.call('integ_br', '10.0.0.1', '172.16.0.1', 16634, 2,
'helper')
])
mock_exit.assert_has_calls([
mock.call(1)
])

View File

@ -1,54 +0,0 @@
# Copyright 2012 Isaku Yamahata <yamahata at private email ne jp>
# 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 contextlib
import operator
from neutron.db import api as db
from neutron.plugins.ryu.common import config # noqa
from neutron.plugins.ryu.db import api_v2 as db_api_v2
from neutron.tests.unit import test_db_plugin as test_plugin
class RyuDBTest(test_plugin.NeutronDbPluginV2TestCase):
@staticmethod
def _tunnel_key_sort(key_list):
key_list.sort(key=operator.attrgetter('tunnel_key'))
return [(key.network_id, key.tunnel_key) for key in key_list]
def test_key_allocation(self):
tunnel_key = db_api_v2.TunnelKey()
session = db.get_session()
with contextlib.nested(self.network('network-0'),
self.network('network-1')
) as (network_0, network_1):
network_id0 = network_0['network']['id']
key0 = tunnel_key.allocate(session, network_id0)
network_id1 = network_1['network']['id']
key1 = tunnel_key.allocate(session, network_id1)
key_list = tunnel_key.all_list()
self.assertEqual(len(key_list), 2)
expected_list = [(network_id0, key0), (network_id1, key1)]
self.assertEqual(self._tunnel_key_sort(key_list),
expected_list)
tunnel_key.delete(session, network_id0)
key_list = tunnel_key.all_list()
self.assertEqual(self._tunnel_key_sort(key_list),
[(network_id1, key1)])
tunnel_key.delete(session, network_id1)
self.assertEqual(tunnel_key.all_list(), [])

View File

@ -1,50 +0,0 @@
# Copyright (c) 2012 OpenStack Foundation.
#
# 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 import manager
from neutron.tests.unit.ryu import fake_ryu
from neutron.tests.unit import test_db_plugin as test_plugin
class RyuPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
_plugin_name = 'neutron.plugins.ryu.ryu_neutron_plugin.RyuNeutronPluginV2'
def setUp(self):
self.ryu_patcher = fake_ryu.patch_fake_ryu_client()
self.ryu_patcher.start()
super(RyuPluginV2TestCase, self).setUp(self._plugin_name)
self.addCleanup(self.ryu_patcher.stop)
plugin = manager.NeutronManager.get_plugin()
plugin.notifier = mock.Mock()
class TestRyuBasicGet(test_plugin.TestBasicGet, RyuPluginV2TestCase):
pass
class TestRyuV2HTTPResponse(test_plugin.TestV2HTTPResponse,
RyuPluginV2TestCase):
pass
class TestRyuPortsV2(test_plugin.TestPortsV2, RyuPluginV2TestCase):
pass
class TestRyuNetworksV2(test_plugin.TestNetworksV2, RyuPluginV2TestCase):
pass

View File

@ -1,86 +0,0 @@
# Copyright 2012, Nachi Ueno, NTT MCL, Inc.
# 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 contextlib
import mock
from neutron.api.v2 import attributes
from neutron.extensions import securitygroup as ext_sg
from neutron import manager
from neutron.tests.unit.ryu import fake_ryu
from neutron.tests.unit import test_extension_security_group as test_sg
from neutron.tests.unit import test_security_groups_rpc as test_sg_rpc
PLUGIN_NAME = ('neutron.plugins.ryu.'
'ryu_neutron_plugin.RyuNeutronPluginV2')
NOTIFIER = ('neutron.plugins.ryu.'
'ryu_neutron_plugin.AgentNotifierApi')
class RyuSecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase):
_plugin_name = PLUGIN_NAME
def setUp(self, plugin=None):
test_sg_rpc.set_firewall_driver(test_sg_rpc.FIREWALL_HYBRID_DRIVER)
self.fake_ryu = fake_ryu.patch_fake_ryu_client().start()
self.notifier = mock.patch(NOTIFIER).start().return_value
self._attribute_map_bk_ = {}
for item in attributes.RESOURCE_ATTRIBUTE_MAP:
self._attribute_map_bk_[item] = (attributes.
RESOURCE_ATTRIBUTE_MAP[item].
copy())
super(RyuSecurityGroupsTestCase, self).setUp(PLUGIN_NAME)
def tearDown(self):
super(RyuSecurityGroupsTestCase, self).tearDown()
attributes.RESOURCE_ATTRIBUTE_MAP = self._attribute_map_bk_
class TestRyuSecurityGroups(RyuSecurityGroupsTestCase,
test_sg.TestSecurityGroups,
test_sg_rpc.SGNotificationTestMixin):
def test_security_group_get_port_from_device(self):
with contextlib.nested(self.network(),
self.security_group()) as (n, sg):
with self.subnet(n):
security_group_id = sg['security_group']['id']
res = self._create_port(self.fmt, n['network']['id'])
port = self.deserialize(self.fmt, res)
fixed_ips = port['port']['fixed_ips']
data = {'port': {'fixed_ips': fixed_ips,
'name': port['port']['name'],
ext_sg.SECURITYGROUPS:
[security_group_id]}}
req = self.new_update_request('ports', data,
port['port']['id'])
res = self.deserialize(self.fmt,
req.get_response(self.api))
port_id = res['port']['id']
plugin = manager.NeutronManager.get_plugin()
port_dict = plugin.get_port_from_device(port_id)
self.assertEqual(port_id, port_dict['id'])
self.assertEqual([security_group_id],
port_dict[ext_sg.SECURITYGROUPS])
self.assertEqual([], port_dict['security_group_rules'])
self.assertEqual([fixed_ips[0]['ip_address']],
port_dict['fixed_ips'])
self._delete('ports', port_id)
def test_security_group_get_port_from_device_with_no_port(self):
plugin = manager.NeutronManager.get_plugin()
port_dict = plugin.get_port_from_device('bad_device_id')
self.assertIsNone(port_dict)

View File

@ -45,7 +45,6 @@ data_files =
etc/neutron/rootwrap.d/nec-plugin.filters
etc/neutron/rootwrap.d/ofagent.filters
etc/neutron/rootwrap.d/openvswitch-plugin.filters
etc/neutron/rootwrap.d/ryu-plugin.filters
etc/neutron/rootwrap.d/vpnaas.filters
etc/init.d = etc/init.d/neutron-server
etc/neutron/plugins/bigswitch =
@ -85,7 +84,6 @@ data_files =
etc/neutron/plugins/oneconvergence = etc/neutron/plugins/oneconvergence/nvsdplugin.ini
etc/neutron/plugins/openvswitch = etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini
etc/neutron/plugins/plumgrid = etc/neutron/plugins/plumgrid/plumgrid.ini
etc/neutron/plugins/ryu = etc/neutron/plugins/ryu/ryu.ini
etc/neutron/plugins/vmware = etc/neutron/plugins/vmware/nsx.ini
etc/neutron/plugins/opencontrail = etc/neutron/plugins/opencontrail/contrailplugin.ini
scripts =
@ -119,7 +117,6 @@ console_scripts =
neutron-openvswitch-agent = neutron.plugins.openvswitch.agent.ovs_neutron_agent:main
neutron-ovs-cleanup = neutron.agent.ovs_cleanup_util:main
neutron-restproxy-agent = neutron.plugins.bigswitch.agent.restproxy_agent:main
neutron-ryu-agent = neutron.plugins.ryu.agent.ryu_neutron_agent:main
neutron-server = neutron.server:main
neutron-rootwrap = oslo.rootwrap.cmd:main
neutron-usage-audit = neutron.cmd.usage_audit:main
@ -143,7 +140,6 @@ neutron.core_plugins =
metaplugin = neutron.plugins.metaplugin.meta_neutron_plugin:MetaPluginV2
oneconvergence = neutron.plugins.oneconvergence.plugin:OneConvergencePluginV2
plumgrid = neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin:NeutronPluginPLUMgridV2
ryu = neutron.plugins.ryu.ryu_neutron_plugin:RyuNeutronPluginV2
vmware = neutron.plugins.vmware.plugin:NsxPlugin
neutron.service_plugins =
dummy = neutron.tests.unit.dummy_plugin:DummyServicePlugin