Merge "Remove OneConvergence plugin from the source tree"
This commit is contained in:
commit
371c37f2f6
@ -1,35 +0,0 @@
|
||||
[nvsd]
|
||||
# Configure the NVSD controller. The plugin proxies the api calls using
|
||||
# to NVSD controller which implements the required functionality.
|
||||
|
||||
# IP address of NVSD controller api server
|
||||
# nvsd_ip = <ip address of nvsd controller>
|
||||
|
||||
# Port number of NVSD controller api server
|
||||
# nvsd_port = 8082
|
||||
|
||||
# Authentication credentials to access the api server
|
||||
# nvsd_user = <nvsd controller username>
|
||||
# nvsd_passwd = <password>
|
||||
|
||||
# API request timeout in seconds
|
||||
# request_timeout = <default request timeout>
|
||||
|
||||
# Maximum number of retry attempts to login to the NVSD controller
|
||||
# Specify 0 to retry until success (default)
|
||||
# nvsd_retries = 0
|
||||
|
||||
[securitygroup]
|
||||
# Specify firewall_driver option, if neutron security groups are disabled,
|
||||
# then NoopFirewallDriver otherwise OVSHybridIptablesFirewallDriver.
|
||||
# firewall_driver = neutron.agent.firewall.NoopFirewallDriver
|
||||
|
||||
# Controls if neutron security group is enabled or not.
|
||||
# It should be false when you use nova security group.
|
||||
# enable_security_group = True
|
||||
|
||||
[agent]
|
||||
# root_helper = sudo /usr/local/bin/neutron-rootwrap /etc/neutron/rootwrap.conf
|
||||
|
||||
[database]
|
||||
# connection = mysql+pymysql://root:<passwd>@127.0.0.1/<neutron_db>?charset=utf8
|
@ -1,32 +0,0 @@
|
||||
One Convergence Neutron Plugin to implement the Neutron v2.0 API. The plugin
|
||||
works with One Convergence NVSD controller to provide network virtualization
|
||||
functionality.
|
||||
|
||||
The plugin is enabled with the following configuration line in neutron.conf:
|
||||
|
||||
core_plugin = neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2
|
||||
|
||||
The configuration parameters required for the plugin are specified in the file
|
||||
etc/neutron/plugins/oneconvergence/nvsdplugin.ini. The configuration file contains
|
||||
description of the different parameters.
|
||||
|
||||
To enable One Convergence Neutron Plugin with devstack and configure the required
|
||||
parameters, use the following lines in localrc:
|
||||
|
||||
Q_PLUGIN=oneconvergence
|
||||
|
||||
disable_service n-net
|
||||
enable_service q-agt
|
||||
enable_service q-dhcp
|
||||
enable_service q-svc
|
||||
enable_service q-l3
|
||||
enable_service q-meta
|
||||
enable_service neutron
|
||||
|
||||
NVSD_IP=
|
||||
NVSD_PORT=
|
||||
NVSD_USER=
|
||||
NVSD_PASSWD=
|
||||
|
||||
The NVSD controller configuration should be specified in nvsdplugin.ini before
|
||||
invoking stack.sh.
|
@ -1,156 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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.
|
||||
|
||||
"""NVSD agent code for security group events."""
|
||||
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
|
||||
import eventlet
|
||||
eventlet.monkey_patch()
|
||||
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging
|
||||
|
||||
from neutron.agent.common 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 topics
|
||||
from neutron import context as n_context
|
||||
from neutron.extensions import securitygroup as ext_sg
|
||||
from neutron.i18n import _LE, _LI
|
||||
from neutron.plugins.oneconvergence.lib import config
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NVSDAgentRpcCallback(object):
|
||||
|
||||
target = oslo_messaging.Target(version='1.0')
|
||||
|
||||
def __init__(self, context, agent, sg_agent):
|
||||
super(NVSDAgentRpcCallback, self).__init__()
|
||||
self.context = context
|
||||
self.agent = agent
|
||||
self.sg_agent = sg_agent
|
||||
|
||||
def port_update(self, context, **kwargs):
|
||||
LOG.debug("port_update received: %s", kwargs)
|
||||
port = kwargs.get('port')
|
||||
# Validate that port is on OVS
|
||||
vif_port = self.agent.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()
|
||||
|
||||
|
||||
class SecurityGroupAgentRpcCallback(sg_rpc.SecurityGroupAgentRpcCallbackMixin):
|
||||
|
||||
target = oslo_messaging.Target(version=sg_rpc.SG_RPC_VERSION)
|
||||
|
||||
def __init__(self, context, sg_agent):
|
||||
super(SecurityGroupAgentRpcCallback, self).__init__()
|
||||
self.context = context
|
||||
self.sg_agent = sg_agent
|
||||
|
||||
|
||||
class NVSDNeutronAgent(object):
|
||||
# history
|
||||
# 1.0 Initial version
|
||||
# 1.1 Support Security Group RPC
|
||||
target = oslo_messaging.Target(version='1.1')
|
||||
|
||||
def __init__(self, integ_br, polling_interval):
|
||||
super(NVSDNeutronAgent, self).__init__()
|
||||
self.int_br = ovs_lib.OVSBridge(integ_br)
|
||||
self.polling_interval = polling_interval
|
||||
self.setup_rpc()
|
||||
self.ports = set()
|
||||
|
||||
def setup_rpc(self):
|
||||
|
||||
self.host = socket.gethostname()
|
||||
self.agent_id = 'nvsd-q-agent.%s' % self.host
|
||||
LOG.info(_LI("RPC agent_id: %s"), self.agent_id)
|
||||
|
||||
self.topic = topics.AGENT
|
||||
self.context = n_context.get_admin_context_without_session()
|
||||
self.sg_plugin_rpc = sg_rpc.SecurityGroupServerRpcApi(topics.PLUGIN)
|
||||
self.sg_agent = sg_rpc.SecurityGroupAgentRpc(self.context,
|
||||
self.sg_plugin_rpc)
|
||||
|
||||
# RPC network init
|
||||
# Handle updates from service
|
||||
self.callback_oc = NVSDAgentRpcCallback(self.context,
|
||||
self, self.sg_agent)
|
||||
self.callback_sg = SecurityGroupAgentRpcCallback(self.context,
|
||||
self.sg_agent)
|
||||
self.endpoints = [self.callback_oc, self.callback_sg]
|
||||
# Define the listening consumer for the agent
|
||||
consumers = [[topics.PORT, topics.UPDATE],
|
||||
[topics.SECURITY_GROUP, topics.UPDATE]]
|
||||
self.connection = agent_rpc.create_consumers(self.endpoints,
|
||||
self.topic,
|
||||
consumers)
|
||||
|
||||
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):
|
||||
"""Main processing loop for OC Plugin Agent."""
|
||||
|
||||
ports = set()
|
||||
while True:
|
||||
try:
|
||||
port_info = self._update_ports(ports)
|
||||
if port_info:
|
||||
LOG.debug("Port list is updated")
|
||||
self._process_devices_filter(port_info)
|
||||
ports = port_info['current']
|
||||
self.ports = ports
|
||||
except Exception:
|
||||
LOG.exception(_LE("Error in agent event loop"))
|
||||
|
||||
LOG.debug("AGENT looping.....")
|
||||
time.sleep(self.polling_interval)
|
||||
|
||||
|
||||
def main():
|
||||
common_config.init(sys.argv[1:])
|
||||
common_config.setup_logging()
|
||||
|
||||
integ_br = config.AGENT.integration_bridge
|
||||
polling_interval = config.AGENT.polling_interval
|
||||
agent = NVSDNeutronAgent(integ_br, polling_interval)
|
||||
LOG.info(_LI("NVSD Agent initialized successfully, now running... "))
|
||||
|
||||
# Start everything.
|
||||
agent.daemon_loop()
|
@ -1,53 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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.
|
||||
#
|
||||
|
||||
""" Register the configuration options"""
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
|
||||
NVSD_OPT = [
|
||||
cfg.StrOpt('nvsd_ip',
|
||||
default='127.0.0.1',
|
||||
help=_("NVSD Controller IP address")),
|
||||
cfg.IntOpt('nvsd_port',
|
||||
default=8082,
|
||||
help=_("NVSD Controller Port number")),
|
||||
cfg.StrOpt('nvsd_user',
|
||||
default='ocplugin',
|
||||
help=_("NVSD Controller username")),
|
||||
cfg.StrOpt('nvsd_passwd',
|
||||
default='oc123', secret=True,
|
||||
help=_("NVSD Controller password")),
|
||||
cfg.IntOpt('request_timeout',
|
||||
default=30,
|
||||
help=_("NVSD controller REST API request timeout in seconds")),
|
||||
cfg.IntOpt('nvsd_retries', default=0,
|
||||
help=_("Number of login retries to NVSD controller"))
|
||||
]
|
||||
|
||||
agent_opts = [
|
||||
cfg.StrOpt('integration_bridge', default='br-int',
|
||||
help=_("integration bridge")),
|
||||
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(NVSD_OPT, "nvsd")
|
||||
cfg.CONF.register_opts(agent_opts, "AGENT")
|
||||
|
||||
CONF = cfg.CONF
|
||||
AGENT = cfg.CONF.AGENT
|
@ -1,55 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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.
|
||||
#
|
||||
|
||||
"""NVSD Exception Definitions."""
|
||||
|
||||
from neutron.common import exceptions as n_exc
|
||||
|
||||
|
||||
class NVSDAPIException(n_exc.NeutronException):
|
||||
'''Base NVSDplugin Exception.'''
|
||||
message = _("An unknown nvsd plugin exception occurred: %(reason)s")
|
||||
|
||||
|
||||
class RequestTimeout(NVSDAPIException):
|
||||
message = _("The request has timed out.")
|
||||
|
||||
|
||||
class UnAuthorizedException(NVSDAPIException):
|
||||
message = _("Invalid access credentials to the Server.")
|
||||
|
||||
|
||||
class NotFoundException(NVSDAPIException):
|
||||
message = _("A resource is not found: %(reason)s")
|
||||
|
||||
|
||||
class BadRequestException(NVSDAPIException):
|
||||
message = _("Request sent to server is invalid: %(reason)s")
|
||||
|
||||
|
||||
class ServerException(NVSDAPIException):
|
||||
message = _("Internal Server Error: %(reason)s")
|
||||
|
||||
|
||||
class ConnectionClosedException(NVSDAPIException):
|
||||
message = _("Connection is closed by the server.")
|
||||
|
||||
|
||||
class ForbiddenException(NVSDAPIException):
|
||||
message = _("The request is forbidden access to the resource: %(reason)s")
|
||||
|
||||
|
||||
class InternalServerError(NVSDAPIException):
|
||||
message = _("Internal Server Error from NVSD controller: %(reason)s")
|
@ -1,43 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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.
|
||||
|
||||
from neutron.db import 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
|
||||
|
||||
|
||||
def get_port_from_device(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 tport, 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
|
@ -1,353 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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.
|
||||
|
||||
"""Intermidiate NVSD Library."""
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import excutils
|
||||
|
||||
import neutron.plugins.oneconvergence.lib.exception as nvsdexception
|
||||
from neutron.plugins.oneconvergence.lib import plugin_helper
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
NETWORKS_URI = "/pluginhandler/ocplugin/tenant/%s/lnetwork/"
|
||||
NETWORK_URI = NETWORKS_URI + "%s"
|
||||
GET_ALL_NETWORKS = "/pluginhandler/ocplugin/tenant/getallnetworks"
|
||||
|
||||
SUBNETS_URI = NETWORK_URI + "/lsubnet/"
|
||||
SUBNET_URI = SUBNETS_URI + "%s"
|
||||
GET_ALL_SUBNETS = "/pluginhandler/ocplugin/tenant/getallsubnets"
|
||||
|
||||
PORTS_URI = NETWORK_URI + "/lport/"
|
||||
PORT_URI = PORTS_URI + "%s"
|
||||
|
||||
EXT_URI = "/pluginhandler/ocplugin/ext/tenant/%s"
|
||||
FLOATING_IPS_URI = EXT_URI + "/floatingip/"
|
||||
FLOATING_IP_URI = FLOATING_IPS_URI + "%s"
|
||||
|
||||
ROUTERS_URI = EXT_URI + "/lrouter/"
|
||||
ROUTER_URI = ROUTERS_URI + "%s"
|
||||
|
||||
METHODS = {"POST": "create",
|
||||
"PUT": "update",
|
||||
"DELETE": "delete",
|
||||
"GET": "get"}
|
||||
|
||||
|
||||
class NVSDApi(object):
|
||||
|
||||
def build_error_msg(self, method, resource, tenant_id, resource_id):
|
||||
if method == "POST":
|
||||
msg = _("Could not create a %(resource)s under tenant "
|
||||
"%(tenant_id)s") % {'resource': resource,
|
||||
'tenant_id': tenant_id}
|
||||
elif resource_id:
|
||||
msg = _("Failed to %(method)s %(resource)s "
|
||||
"id=%(resource_id)s") % {'method': METHODS[method],
|
||||
'resource': resource,
|
||||
'resource_id': resource_id
|
||||
}
|
||||
else:
|
||||
msg = _("Failed to %(method)s %(resource)s") % {
|
||||
'method': METHODS[method], 'resource': resource}
|
||||
return msg
|
||||
|
||||
def set_connection(self):
|
||||
self.nvsdcontroller = plugin_helper.initialize_plugin_helper()
|
||||
self.nvsdcontroller.login()
|
||||
|
||||
def send_request(self, method, uri, body=None, resource=None,
|
||||
tenant_id='', resource_id=None):
|
||||
"""Issue a request to NVSD controller."""
|
||||
|
||||
try:
|
||||
result = self.nvsdcontroller.request(method, uri, body=body)
|
||||
except nvsdexception.NVSDAPIException as e:
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
msg = self.build_error_msg(method, resource, tenant_id,
|
||||
resource_id)
|
||||
LOG.error(msg)
|
||||
# Modifying the reason message without disturbing the exception
|
||||
# info
|
||||
ctxt.value = type(e)(reason=msg)
|
||||
return result
|
||||
|
||||
def create_network(self, network):
|
||||
|
||||
tenant_id = network['tenant_id']
|
||||
router_external = network['router:external'] is True
|
||||
|
||||
network_obj = {
|
||||
"name": network['name'],
|
||||
"tenant_id": tenant_id,
|
||||
"shared": network['shared'],
|
||||
"admin_state_up": network['admin_state_up'],
|
||||
"router:external": router_external
|
||||
}
|
||||
|
||||
uri = NETWORKS_URI % tenant_id
|
||||
|
||||
response = self.send_request("POST", uri,
|
||||
body=jsonutils.dumps(network_obj),
|
||||
resource='network', tenant_id=tenant_id)
|
||||
|
||||
nvsd_net = response.json()
|
||||
|
||||
LOG.debug("Network %(id)s created under tenant %(tenant_id)s",
|
||||
{'id': nvsd_net['id'], 'tenant_id': tenant_id})
|
||||
|
||||
return nvsd_net
|
||||
|
||||
def update_network(self, network, network_update):
|
||||
|
||||
tenant_id = network['tenant_id']
|
||||
network_id = network['id']
|
||||
|
||||
uri = NETWORK_URI % (tenant_id, network_id)
|
||||
|
||||
self.send_request("PUT", uri,
|
||||
body=jsonutils.dumps(network_update),
|
||||
resource='network', tenant_id=tenant_id,
|
||||
resource_id=network_id)
|
||||
|
||||
LOG.debug("Network %(id)s updated under tenant %(tenant_id)s",
|
||||
{'id': network_id, 'tenant_id': tenant_id})
|
||||
|
||||
def delete_network(self, network, subnets=[]):
|
||||
|
||||
tenant_id = network['tenant_id']
|
||||
network_id = network['id']
|
||||
|
||||
ports = self._get_ports(tenant_id, network_id)
|
||||
|
||||
for port in ports:
|
||||
self.delete_port(port['id'], port)
|
||||
|
||||
for subnet in subnets:
|
||||
self.delete_subnet(subnet)
|
||||
|
||||
path = NETWORK_URI % (tenant_id, network_id)
|
||||
|
||||
self.send_request("DELETE", path, resource='network',
|
||||
tenant_id=tenant_id, resource_id=network_id)
|
||||
|
||||
LOG.debug("Network %(id)s deleted under tenant %(tenant_id)s",
|
||||
{'id': network_id, 'tenant_id': tenant_id})
|
||||
|
||||
def create_subnet(self, subnet):
|
||||
|
||||
tenant_id = subnet['tenant_id']
|
||||
network_id = subnet['network_id']
|
||||
|
||||
uri = SUBNETS_URI % (tenant_id, network_id)
|
||||
|
||||
self.send_request("POST", uri, body=jsonutils.dumps(subnet),
|
||||
resource='subnet', tenant_id=tenant_id)
|
||||
|
||||
LOG.debug("Subnet %(id)s created under tenant %(tenant_id)s",
|
||||
{'id': subnet['id'], 'tenant_id': tenant_id})
|
||||
|
||||
def delete_subnet(self, subnet):
|
||||
|
||||
tenant_id = subnet['tenant_id']
|
||||
network_id = subnet['network_id']
|
||||
subnet_id = subnet['id']
|
||||
|
||||
uri = SUBNET_URI % (tenant_id, network_id, subnet_id)
|
||||
|
||||
self.send_request("DELETE", uri, resource='subnet',
|
||||
tenant_id=tenant_id, resource_id=subnet_id)
|
||||
|
||||
LOG.debug("Subnet %(id)s deleted under tenant %(tenant_id)s",
|
||||
{'id': subnet_id, 'tenant_id': tenant_id})
|
||||
|
||||
def update_subnet(self, subnet, subnet_update):
|
||||
|
||||
tenant_id = subnet['tenant_id']
|
||||
network_id = subnet['network_id']
|
||||
subnet_id = subnet['id']
|
||||
|
||||
uri = SUBNET_URI % (tenant_id, network_id, subnet_id)
|
||||
|
||||
self.send_request("PUT", uri,
|
||||
body=jsonutils.dumps(subnet_update),
|
||||
resource='subnet', tenant_id=tenant_id,
|
||||
resource_id=subnet_id)
|
||||
|
||||
LOG.debug("Subnet %(id)s updated under tenant %(tenant_id)s",
|
||||
{'id': subnet_id, 'tenant_id': tenant_id})
|
||||
|
||||
def create_port(self, tenant_id, port):
|
||||
|
||||
network_id = port["network_id"]
|
||||
fixed_ips = port.get("fixed_ips")
|
||||
ip_address = None
|
||||
subnet_id = None
|
||||
|
||||
if fixed_ips:
|
||||
ip_address = fixed_ips[0].get("ip_address")
|
||||
subnet_id = fixed_ips[0].get("subnet_id")
|
||||
|
||||
lport = {
|
||||
"id": port["id"],
|
||||
"name": port["name"],
|
||||
"device_id": port["device_id"],
|
||||
"device_owner": port["device_owner"],
|
||||
"mac_address": port["mac_address"],
|
||||
"ip_address": ip_address,
|
||||
"subnet_id": subnet_id,
|
||||
"admin_state_up": port["admin_state_up"],
|
||||
"network_id": network_id,
|
||||
"status": port["status"]
|
||||
}
|
||||
|
||||
path = PORTS_URI % (tenant_id, network_id)
|
||||
|
||||
self.send_request("POST", path, body=jsonutils.dumps(lport),
|
||||
resource='port', tenant_id=tenant_id)
|
||||
|
||||
LOG.debug("Port %(id)s created under tenant %(tenant_id)s",
|
||||
{'id': port['id'], 'tenant_id': tenant_id})
|
||||
|
||||
def update_port(self, tenant_id, port, port_update):
|
||||
|
||||
network_id = port['network_id']
|
||||
port_id = port['id']
|
||||
|
||||
lport = {}
|
||||
for k in ('admin_state_up', 'name', 'device_id', 'device_owner'):
|
||||
if k in port_update:
|
||||
lport[k] = port_update[k]
|
||||
|
||||
fixed_ips = port_update.get('fixed_ips', None)
|
||||
if fixed_ips:
|
||||
lport["ip_address"] = fixed_ips[0].get("ip_address")
|
||||
lport["subnet_id"] = fixed_ips[0].get("subnet_id")
|
||||
|
||||
uri = PORT_URI % (tenant_id, network_id, port_id)
|
||||
|
||||
self.send_request("PUT", uri, body=jsonutils.dumps(lport),
|
||||
resource='port', tenant_id=tenant_id,
|
||||
resource_id=port_id)
|
||||
|
||||
LOG.debug("Port %(id)s updated under tenant %(tenant_id)s",
|
||||
{'id': port_id, 'tenant_id': tenant_id})
|
||||
|
||||
def delete_port(self, port_id, port):
|
||||
|
||||
tenant_id = port['tenant_id']
|
||||
network_id = port['network_id']
|
||||
|
||||
uri = PORT_URI % (tenant_id, network_id, port_id)
|
||||
|
||||
self.send_request("DELETE", uri, resource='port', tenant_id=tenant_id,
|
||||
resource_id=port_id)
|
||||
|
||||
LOG.debug("Port %(id)s deleted under tenant %(tenant_id)s",
|
||||
{'id': port_id, 'tenant_id': tenant_id})
|
||||
|
||||
def _get_ports(self, tenant_id, network_id):
|
||||
|
||||
uri = PORTS_URI % (tenant_id, network_id)
|
||||
|
||||
response = self.send_request("GET", uri, resource='ports',
|
||||
tenant_id=tenant_id)
|
||||
|
||||
return response.json()
|
||||
|
||||
def create_floatingip(self, floating_ip):
|
||||
|
||||
tenant_id = floating_ip['tenant_id']
|
||||
|
||||
uri = FLOATING_IPS_URI % tenant_id
|
||||
|
||||
self.send_request("POST", uri, body=jsonutils.dumps(floating_ip),
|
||||
resource='floating_ip',
|
||||
tenant_id=tenant_id)
|
||||
|
||||
LOG.debug("Flatingip %(id)s created under tenant %(tenant_id)s",
|
||||
{'id': floating_ip['id'], 'tenant_id': tenant_id})
|
||||
|
||||
def update_floatingip(self, floating_ip, floating_ip_update):
|
||||
|
||||
tenant_id = floating_ip['tenant_id']
|
||||
|
||||
floating_ip_id = floating_ip['id']
|
||||
|
||||
uri = FLOATING_IP_URI % (tenant_id, floating_ip_id)
|
||||
|
||||
self.send_request("PUT", uri,
|
||||
body=jsonutils.dumps(
|
||||
floating_ip_update['floatingip']),
|
||||
resource='floating_ip',
|
||||
tenant_id=tenant_id,
|
||||
resource_id=floating_ip_id)
|
||||
|
||||
LOG.debug("Flatingip %(id)s updated under tenant %(tenant_id)s",
|
||||
{'id': floating_ip_id, 'tenant_id': tenant_id})
|
||||
|
||||
def delete_floatingip(self, floating_ip):
|
||||
|
||||
tenant_id = floating_ip['tenant_id']
|
||||
|
||||
floating_ip_id = floating_ip['id']
|
||||
|
||||
uri = FLOATING_IP_URI % (tenant_id, floating_ip_id)
|
||||
|
||||
self.send_request("DELETE", uri, resource='floating_ip',
|
||||
tenant_id=tenant_id, resource_id=floating_ip_id)
|
||||
|
||||
LOG.debug("Flatingip %(id)s deleted under tenant %(tenant_id)s",
|
||||
{'id': floating_ip_id, 'tenant_id': tenant_id})
|
||||
|
||||
def create_router(self, router):
|
||||
|
||||
tenant_id = router['tenant_id']
|
||||
|
||||
uri = ROUTERS_URI % tenant_id
|
||||
|
||||
self.send_request("POST", uri, body=jsonutils.dumps(router),
|
||||
resource='router',
|
||||
tenant_id=tenant_id)
|
||||
|
||||
LOG.debug("Router %(id)s created under tenant %(tenant_id)s",
|
||||
{'id': router['id'], 'tenant_id': tenant_id})
|
||||
|
||||
def update_router(self, router):
|
||||
|
||||
tenant_id = router['tenant_id']
|
||||
|
||||
router_id = router['id']
|
||||
|
||||
uri = ROUTER_URI % (tenant_id, router_id)
|
||||
|
||||
self.send_request("PUT", uri,
|
||||
body=jsonutils.dumps(router),
|
||||
resource='router', tenant_id=tenant_id,
|
||||
resource_id=router_id)
|
||||
|
||||
LOG.debug("Router %(id)s updated under tenant %(tenant_id)s",
|
||||
{'id': router_id, 'tenant_id': tenant_id})
|
||||
|
||||
def delete_router(self, tenant_id, router_id):
|
||||
|
||||
uri = ROUTER_URI % (tenant_id, router_id)
|
||||
|
||||
self.send_request("DELETE", uri, resource='router',
|
||||
tenant_id=tenant_id, resource_id=router_id)
|
||||
|
||||
LOG.debug("Router %(id)s deleted under tenant %(tenant_id)s",
|
||||
{'id': router_id, 'tenant_id': tenant_id})
|
@ -1,184 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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.
|
||||
|
||||
"""Library to talk to NVSD controller."""
|
||||
|
||||
from six.moves import http_client as httplib
|
||||
import time
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
import requests
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from neutron.i18n import _LE, _LW
|
||||
import neutron.plugins.oneconvergence.lib.exception as exception
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def initialize_plugin_helper():
|
||||
nvsdcontroller = NVSDController()
|
||||
return nvsdcontroller
|
||||
|
||||
|
||||
class NVSDController(object):
|
||||
|
||||
"""Encapsulates the NVSD Controller details."""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self._host = cfg.CONF.nvsd.nvsd_ip
|
||||
self._port = cfg.CONF.nvsd.nvsd_port
|
||||
self._user = cfg.CONF.nvsd.nvsd_user
|
||||
self._password = cfg.CONF.nvsd.nvsd_passwd
|
||||
self._retries = cfg.CONF.nvsd.nvsd_retries
|
||||
self._request_timeout = float(cfg.CONF.nvsd.request_timeout)
|
||||
self.api_url = 'http://' + self._host + ':' + str(self._port)
|
||||
|
||||
self.pool = requests.Session()
|
||||
|
||||
self.auth_token = None
|
||||
|
||||
def do_request(self, method, url=None, headers=None, data=None):
|
||||
response = self.pool.request(method, url=url,
|
||||
headers=headers, data=data,
|
||||
timeout=self._request_timeout)
|
||||
return response
|
||||
|
||||
def login(self):
|
||||
"""Login to NVSD Controller."""
|
||||
|
||||
headers = {"Content-Type": "application/json"}
|
||||
|
||||
login_url = parse.urljoin(self.api_url,
|
||||
"/pluginhandler/ocplugin/authmgmt/login")
|
||||
|
||||
data = jsonutils.dumps({"user_name": self._user,
|
||||
"passwd": self._password})
|
||||
|
||||
attempts = 0
|
||||
|
||||
while True:
|
||||
if attempts < self._retries:
|
||||
attempts += 1
|
||||
elif self._retries == 0:
|
||||
attempts = 0
|
||||
else:
|
||||
msg = _("Unable to connect to NVSD controller. Exiting after "
|
||||
"%(retries)s attempts") % {'retries': self._retries}
|
||||
LOG.error(msg)
|
||||
raise exception.ServerException(reason=msg)
|
||||
try:
|
||||
response = self.do_request("POST", url=login_url,
|
||||
headers=headers, data=data)
|
||||
break
|
||||
except Exception as e:
|
||||
LOG.error(_LE("Login Failed: %s"), e)
|
||||
LOG.error(_LE("Unable to establish connection"
|
||||
" with Controller %s"), self.api_url)
|
||||
LOG.error(_LE("Retrying after 1 second..."))
|
||||
time.sleep(1)
|
||||
|
||||
if response.status_code == requests.codes.ok:
|
||||
LOG.debug("Login Successful %(uri)s "
|
||||
"%(status)s", {'uri': self.api_url,
|
||||
'status': response.status_code})
|
||||
self.auth_token = jsonutils.loads(response.content)["session_uuid"]
|
||||
LOG.debug("AuthToken = %s", self.auth_token)
|
||||
else:
|
||||
LOG.error(_LE("login failed"))
|
||||
|
||||
return
|
||||
|
||||
def request(self, method, url, body="", content_type="application/json"):
|
||||
"""Issue a request to NVSD controller."""
|
||||
|
||||
if self.auth_token is None:
|
||||
LOG.warning(_LW("No Token, Re-login"))
|
||||
self.login()
|
||||
|
||||
headers = {"Content-Type": content_type}
|
||||
|
||||
uri = parse.urljoin(url, "?authToken=%s" % self.auth_token)
|
||||
|
||||
url = parse.urljoin(self.api_url, uri)
|
||||
|
||||
request_ok = False
|
||||
response = None
|
||||
|
||||
try:
|
||||
response = self.do_request(method, url=url,
|
||||
headers=headers, data=body)
|
||||
|
||||
LOG.debug("request: %(method)s %(uri)s successful",
|
||||
{'method': method, 'uri': self.api_url + uri})
|
||||
request_ok = True
|
||||
except httplib.IncompleteRead as e:
|
||||
response = e.partial
|
||||
request_ok = True
|
||||
except Exception as e:
|
||||
LOG.error(_LE("request: Request failed from "
|
||||
"Controller side :%s"), e)
|
||||
|
||||
if response is None:
|
||||
# Timeout.
|
||||
LOG.error(_LE("Response is Null, Request timed out: %(method)s to "
|
||||
"%(uri)s"), {'method': method, 'uri': uri})
|
||||
self.auth_token = None
|
||||
raise exception.RequestTimeout()
|
||||
|
||||
status = response.status_code
|
||||
if status == requests.codes.unauthorized:
|
||||
self.auth_token = None
|
||||
# Raise an exception to inform that the request failed.
|
||||
raise exception.UnAuthorizedException()
|
||||
|
||||
if status in self.error_codes:
|
||||
LOG.error(_LE("Request %(method)s %(uri)s body = %(body)s failed "
|
||||
"with status %(status)s. Reason: %(reason)s)"),
|
||||
{'method': method,
|
||||
'uri': uri, 'body': body,
|
||||
'status': status,
|
||||
'reason': response.reason})
|
||||
raise self.error_codes[status]()
|
||||
elif status not in (requests.codes.ok, requests.codes.created,
|
||||
requests.codes.no_content):
|
||||
LOG.error(_LE("%(method)s to %(url)s, unexpected response code: "
|
||||
"%(status)d"), {'method': method, 'url': url,
|
||||
'status': status})
|
||||
return
|
||||
|
||||
if not request_ok:
|
||||
LOG.error(_LE("Request failed from Controller side with "
|
||||
"Status=%s"), status)
|
||||
raise exception.ServerException()
|
||||
else:
|
||||
LOG.debug("Success: %(method)s %(url)s status=%(status)s",
|
||||
{'method': method, 'url': self.api_url + uri,
|
||||
'status': status})
|
||||
response.body = response.content
|
||||
return response
|
||||
|
||||
error_codes = {
|
||||
404: exception.NotFoundException,
|
||||
409: exception.BadRequestException,
|
||||
500: exception.InternalServerError,
|
||||
503: exception.ServerException,
|
||||
403: exception.ForbiddenException,
|
||||
301: exception.NVSDAPIException,
|
||||
307: exception.NVSDAPIException,
|
||||
400: exception.NVSDAPIException,
|
||||
}
|
@ -1,438 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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.
|
||||
|
||||
"""Implementation of OneConvergence Neutron Plugin."""
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import importutils
|
||||
|
||||
from neutron.agent import securitygroups_rpc as sg_rpc
|
||||
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
|
||||
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
|
||||
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 n_const
|
||||
from neutron.common import exceptions as nexception
|
||||
from neutron.common import rpc as n_rpc
|
||||
from neutron.common import topics
|
||||
from neutron.db import agents_db
|
||||
from neutron.db import agentschedulers_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_agentschedulers_db
|
||||
from neutron.db import l3_gwmode_db
|
||||
from neutron.db import portbindings_base
|
||||
from neutron.db import securitygroups_rpc_base as sg_db_rpc
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.i18n import _LE
|
||||
from neutron.plugins.common import constants as svc_constants
|
||||
import neutron.plugins.oneconvergence.lib.config # noqa
|
||||
import neutron.plugins.oneconvergence.lib.exception as nvsdexception
|
||||
import neutron.plugins.oneconvergence.lib.nvsd_db as nvsd_db
|
||||
from neutron.plugins.oneconvergence.lib import nvsdlib as nvsd_lib
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
IPv6 = 6
|
||||
|
||||
|
||||
class SecurityGroupServerRpcMixin(sg_db_rpc.SecurityGroupServerRpcMixin):
|
||||
|
||||
@staticmethod
|
||||
def get_port_from_device(context, device):
|
||||
port = nvsd_db.get_port_from_device(device)
|
||||
if port:
|
||||
port['device'] = device
|
||||
return port
|
||||
|
||||
|
||||
class NVSDPluginV2AgentNotifierApi(sg_rpc.SecurityGroupAgentRpcApiMixin):
|
||||
|
||||
def __init__(self, topic):
|
||||
self.topic = topic
|
||||
self.topic_port_update = topics.get_topic_name(topic, topics.PORT,
|
||||
topics.UPDATE)
|
||||
target = oslo_messaging.Target(topic=topic, version='1.0')
|
||||
self.client = n_rpc.get_client(target)
|
||||
|
||||
def port_update(self, context, port):
|
||||
cctxt = self.client.prepare(topic=self.topic_port_update, fanout=True)
|
||||
cctxt.cast(context, 'port_update', port=port)
|
||||
|
||||
|
||||
class OneConvergencePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
extraroute_db.ExtraRoute_db_mixin,
|
||||
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
|
||||
agentschedulers_db.DhcpAgentSchedulerDbMixin,
|
||||
external_net_db.External_net_db_mixin,
|
||||
l3_gwmode_db.L3_NAT_db_mixin,
|
||||
portbindings_base.PortBindingBaseMixin,
|
||||
SecurityGroupServerRpcMixin):
|
||||
|
||||
"""L2 Virtual Network Plugin.
|
||||
|
||||
OneConvergencePluginV2 is a Neutron plugin that provides L2 Virtual Network
|
||||
functionality.
|
||||
"""
|
||||
|
||||
__native_bulk_support = True
|
||||
__native_pagination_support = True
|
||||
__native_sorting_support = True
|
||||
|
||||
_supported_extension_aliases = ['agent',
|
||||
'binding',
|
||||
'dhcp_agent_scheduler',
|
||||
'ext-gw-mode',
|
||||
'external-net',
|
||||
'extraroute',
|
||||
'l3_agent_scheduler',
|
||||
'quotas',
|
||||
'router',
|
||||
'security-group'
|
||||
]
|
||||
|
||||
@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):
|
||||
|
||||
super(OneConvergencePluginV2, self).__init__()
|
||||
|
||||
self.oneconvergence_init()
|
||||
|
||||
self.base_binding_dict = {
|
||||
portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
|
||||
portbindings.VIF_DETAILS: {
|
||||
portbindings.CAP_PORT_FILTER:
|
||||
'security-group' in self.supported_extension_aliases}}
|
||||
|
||||
portbindings_base.register_port_dict_function()
|
||||
|
||||
self.setup_rpc()
|
||||
|
||||
self.network_scheduler = importutils.import_object(
|
||||
cfg.CONF.network_scheduler_driver)
|
||||
self.router_scheduler = importutils.import_object(
|
||||
cfg.CONF.router_scheduler_driver)
|
||||
self.start_periodic_dhcp_agent_status_check()
|
||||
|
||||
def oneconvergence_init(self):
|
||||
"""Initialize the connections and set the log levels for the plugin."""
|
||||
|
||||
self.nvsdlib = nvsd_lib.NVSDApi()
|
||||
self.nvsdlib.set_connection()
|
||||
|
||||
def setup_rpc(self):
|
||||
# RPC support
|
||||
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 = NVSDPluginV2AgentNotifierApi(topics.AGENT)
|
||||
self.agent_notifiers[n_const.AGENT_TYPE_DHCP] = (
|
||||
dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
|
||||
)
|
||||
self.agent_notifiers[n_const.AGENT_TYPE_L3] = (
|
||||
l3_rpc_agent_api.L3AgentNotifyAPI()
|
||||
)
|
||||
self.endpoints = [securitygroups_rpc.SecurityGroupServerRpcCallback(),
|
||||
dhcp_rpc.DhcpRpcCallback(),
|
||||
l3_rpc.L3RpcCallback(),
|
||||
agents_db.AgentExtRpcCallback(),
|
||||
metadata_rpc.MetadataRpcCallback()]
|
||||
for svc_topic in self.service_topics.values():
|
||||
self.conn.create_consumer(svc_topic, self.endpoints, fanout=False)
|
||||
|
||||
# Consume from all consumers in threads
|
||||
self.conn.consume_in_threads()
|
||||
|
||||
def create_network(self, context, network):
|
||||
|
||||
tenant_id = self._get_tenant_id_for_create(
|
||||
context, network['network'])
|
||||
self._ensure_default_security_group(context, tenant_id)
|
||||
|
||||
net = self.nvsdlib.create_network(network['network'])
|
||||
|
||||
network['network']['id'] = net['id']
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
try:
|
||||
neutron_net = super(OneConvergencePluginV2,
|
||||
self).create_network(context, network)
|
||||
|
||||
#following call checks whether the network is external or not
|
||||
#and if it is external then adds this network to
|
||||
#externalnetworks table of neutron db
|
||||
self._process_l3_create(context, neutron_net,
|
||||
network['network'])
|
||||
except nvsdexception.NVSDAPIException:
|
||||
with excutils.save_and_reraise_exception():
|
||||
self.nvsdlib.delete_network(net)
|
||||
|
||||
return neutron_net
|
||||
|
||||
def update_network(self, context, net_id, network):
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
neutron_net = super(OneConvergencePluginV2,
|
||||
self).update_network(context, net_id, network)
|
||||
|
||||
self.nvsdlib.update_network(neutron_net, network['network'])
|
||||
# updates neutron database e.g. externalnetworks table.
|
||||
self._process_l3_update(context, neutron_net, network['network'])
|
||||
|
||||
return neutron_net
|
||||
|
||||
def delete_network(self, context, net_id):
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
network = self._get_network(context, net_id)
|
||||
#get all the subnets under the network to delete them
|
||||
subnets = self._get_subnets_by_network(context, net_id)
|
||||
|
||||
self._process_l3_delete(context, net_id)
|
||||
super(OneConvergencePluginV2, self).delete_network(context,
|
||||
net_id)
|
||||
|
||||
self.nvsdlib.delete_network(network, subnets)
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
|
||||
if subnet['subnet']['ip_version'] == IPv6:
|
||||
raise nexception.InvalidInput(
|
||||
error_message="NVSDPlugin doesn't support IPv6.")
|
||||
|
||||
neutron_subnet = super(OneConvergencePluginV2,
|
||||
self).create_subnet(context, subnet)
|
||||
|
||||
try:
|
||||
self.nvsdlib.create_subnet(neutron_subnet)
|
||||
except nvsdexception.NVSDAPIException:
|
||||
with excutils.save_and_reraise_exception():
|
||||
#Log the message and delete the subnet from the neutron
|
||||
super(OneConvergencePluginV2,
|
||||
self).delete_subnet(context, neutron_subnet['id'])
|
||||
LOG.error(_LE("Failed to create subnet, "
|
||||
"deleting it from neutron"))
|
||||
|
||||
return neutron_subnet
|
||||
|
||||
def delete_subnet(self, context, subnet_id):
|
||||
|
||||
neutron_subnet = self._get_subnet(context, subnet_id)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
super(OneConvergencePluginV2, self).delete_subnet(context,
|
||||
subnet_id)
|
||||
|
||||
self.nvsdlib.delete_subnet(neutron_subnet)
|
||||
|
||||
def update_subnet(self, context, subnet_id, subnet):
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
neutron_subnet = super(OneConvergencePluginV2,
|
||||
self).update_subnet(context, subnet_id,
|
||||
subnet)
|
||||
|
||||
self.nvsdlib.update_subnet(neutron_subnet, subnet)
|
||||
return neutron_subnet
|
||||
|
||||
def create_port(self, context, port):
|
||||
|
||||
self._ensure_default_security_group_on_port(context, port)
|
||||
|
||||
sgids = self._get_security_groups_on_port(context, port)
|
||||
|
||||
network = {}
|
||||
|
||||
network_id = port['port']['network_id']
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
# Invoke the Neutron API for creating port
|
||||
neutron_port = super(OneConvergencePluginV2,
|
||||
self).create_port(context, port)
|
||||
|
||||
self._process_portbindings_create_and_update(context,
|
||||
port['port'],
|
||||
neutron_port)
|
||||
|
||||
self._process_port_create_security_group(context, neutron_port,
|
||||
sgids)
|
||||
if port['port']['device_owner'] in ('network:router_gateway',
|
||||
'network:floatingip'):
|
||||
# for l3 requests, tenant_id will be None/''
|
||||
network = self._get_network(context, network_id)
|
||||
|
||||
tenant_id = network['tenant_id']
|
||||
else:
|
||||
tenant_id = port['port']['tenant_id']
|
||||
|
||||
port_id = neutron_port['id']
|
||||
|
||||
try:
|
||||
self.nvsdlib.create_port(tenant_id, neutron_port)
|
||||
except nvsdexception.NVSDAPIException:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Deleting newly created "
|
||||
"neutron port %s"), port_id)
|
||||
super(OneConvergencePluginV2, self).delete_port(context,
|
||||
port_id)
|
||||
|
||||
self.notify_security_groups_member_updated(context, neutron_port)
|
||||
|
||||
return neutron_port
|
||||
|
||||
def update_port(self, context, port_id, port):
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
old_port = super(OneConvergencePluginV2, self).get_port(context,
|
||||
port_id)
|
||||
|
||||
neutron_port = super(OneConvergencePluginV2,
|
||||
self).update_port(context, port_id, port)
|
||||
|
||||
if neutron_port['tenant_id'] == '':
|
||||
network = self._get_network(context,
|
||||
neutron_port['network_id'])
|
||||
tenant_id = network['tenant_id']
|
||||
else:
|
||||
tenant_id = neutron_port['tenant_id']
|
||||
|
||||
self.nvsdlib.update_port(tenant_id, neutron_port, port['port'])
|
||||
|
||||
self._process_portbindings_create_and_update(context,
|
||||
port['port'],
|
||||
neutron_port)
|
||||
need_port_update_notify = self.update_security_group_on_port(
|
||||
context, port_id, port, old_port, neutron_port)
|
||||
|
||||
if need_port_update_notify:
|
||||
self.notifier.port_update(context, neutron_port)
|
||||
|
||||
return neutron_port
|
||||
|
||||
def delete_port(self, context, port_id, l3_port_check=True):
|
||||
|
||||
if l3_port_check:
|
||||
self.prevent_l3_port_deletion(context, port_id)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
neutron_port = super(OneConvergencePluginV2,
|
||||
self).get_port(context, port_id)
|
||||
|
||||
router_ids = self.disassociate_floatingips(
|
||||
context, port_id, do_notify=False)
|
||||
|
||||
super(OneConvergencePluginV2, self).delete_port(context, port_id)
|
||||
|
||||
network = self._get_network(context, neutron_port['network_id'])
|
||||
neutron_port['tenant_id'] = network['tenant_id']
|
||||
|
||||
self.nvsdlib.delete_port(port_id, neutron_port)
|
||||
|
||||
# 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, neutron_port)
|
||||
|
||||
def create_floatingip(self, context, floatingip):
|
||||
|
||||
neutron_floatingip = super(OneConvergencePluginV2,
|
||||
self).create_floatingip(context,
|
||||
floatingip)
|
||||
try:
|
||||
self.nvsdlib.create_floatingip(neutron_floatingip)
|
||||
except nvsdexception.NVSDAPIException:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Failed to create floatingip"))
|
||||
super(OneConvergencePluginV2,
|
||||
self).delete_floatingip(context,
|
||||
neutron_floatingip['id'])
|
||||
|
||||
return neutron_floatingip
|
||||
|
||||
def update_floatingip(self, context, fip_id, floatingip):
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
neutron_floatingip = super(OneConvergencePluginV2,
|
||||
self).update_floatingip(context,
|
||||
fip_id,
|
||||
floatingip)
|
||||
|
||||
self.nvsdlib.update_floatingip(neutron_floatingip, floatingip)
|
||||
|
||||
return neutron_floatingip
|
||||
|
||||
def delete_floatingip(self, context, floating_ip_id):
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
floating_ip = self._get_floatingip(context, floating_ip_id)
|
||||
|
||||
super(OneConvergencePluginV2,
|
||||
self).delete_floatingip(context, floating_ip_id)
|
||||
|
||||
self.nvsdlib.delete_floatingip(floating_ip)
|
||||
|
||||
def create_router(self, context, router):
|
||||
|
||||
neutron_router = super(OneConvergencePluginV2,
|
||||
self).create_router(context, router)
|
||||
try:
|
||||
self.nvsdlib.create_router(neutron_router)
|
||||
except nvsdexception.NVSDAPIException:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Failed to create router"))
|
||||
super(OneConvergencePluginV2,
|
||||
self).delete_router(context, neutron_router['id'])
|
||||
|
||||
return neutron_router
|
||||
|
||||
def update_router(self, context, router_id, router):
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
neutron_router = super(OneConvergencePluginV2,
|
||||
self).update_router(context, router_id,
|
||||
router)
|
||||
|
||||
self.nvsdlib.update_router(neutron_router)
|
||||
|
||||
return neutron_router
|
||||
|
||||
def delete_router(self, context, router_id):
|
||||
|
||||
tenant_id = self._get_router(context, router_id)['tenant_id']
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
super(OneConvergencePluginV2, self).delete_router(context,
|
||||
router_id)
|
||||
|
||||
self.nvsdlib.delete_router(tenant_id, router_id)
|
@ -1,176 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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 time
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from six import moves
|
||||
import testtools
|
||||
|
||||
from neutron.agent.common import ovs_lib
|
||||
from neutron.agent import securitygroups_rpc as sg_rpc
|
||||
from neutron.common import topics
|
||||
from neutron.extensions import securitygroup as ext_sg
|
||||
from neutron.plugins.oneconvergence.agent import nvsd_neutron_agent
|
||||
from neutron.tests import base
|
||||
|
||||
DAEMON_LOOP_COUNT = 5
|
||||
|
||||
|
||||
class TestOneConvergenceAgentBase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOneConvergenceAgentBase, self).setUp()
|
||||
cfg.CONF.set_default('firewall_driver',
|
||||
'neutron.agent.firewall.NoopFirewallDriver',
|
||||
group='SECURITYGROUP')
|
||||
with mock.patch('oslo_service.loopingcall.'
|
||||
'FixedIntervalLoopingCall') as loopingcall:
|
||||
kwargs = {'integ_br': 'integration_bridge',
|
||||
'polling_interval': 5}
|
||||
context = mock.Mock()
|
||||
self.agent = nvsd_neutron_agent.NVSDNeutronAgent(**kwargs)
|
||||
sg_plugin_rpc = sg_rpc.SecurityGroupServerRpcApi(topics.PLUGIN)
|
||||
self.sg_agent = sg_rpc.SecurityGroupAgentRpc(context,
|
||||
sg_plugin_rpc)
|
||||
self.callback_nvsd = nvsd_neutron_agent.NVSDAgentRpcCallback(
|
||||
context, self.agent, self.sg_agent)
|
||||
self.loopingcall = loopingcall
|
||||
|
||||
|
||||
class TestOneConvergenceAgentCallback(TestOneConvergenceAgentBase):
|
||||
|
||||
def test_port_update(self):
|
||||
with mock.patch.object(ovs_lib.OVSBridge,
|
||||
'get_vif_port_by_id') as get_vif_port_by_id,\
|
||||
mock.patch.object(self.sg_agent,
|
||||
'refresh_firewall') as refresh_firewall:
|
||||
context = mock.Mock()
|
||||
vifport = ovs_lib.VifPort('port1', '1', 'id-1', 'mac-1',
|
||||
self.agent.int_br)
|
||||
|
||||
# The OVS port does not exist.
|
||||
get_vif_port_by_id.return_value = None
|
||||
port = {'id': 'update-port-1'}
|
||||
self.callback_nvsd.port_update(context, port=port)
|
||||
self.assertEqual(get_vif_port_by_id.call_count, 1)
|
||||
self.assertFalse(refresh_firewall.call_count)
|
||||
|
||||
# The OVS port exists but no security group is associated.
|
||||
get_vif_port_by_id.return_value = vifport
|
||||
port = {'id': 'update-port-1'}
|
||||
self.callback_nvsd.port_update(context, port=port)
|
||||
self.assertEqual(get_vif_port_by_id.call_count, 2)
|
||||
self.assertFalse(refresh_firewall.call_count)
|
||||
|
||||
# The OVS port exists but a security group is associated.
|
||||
get_vif_port_by_id.return_value = vifport
|
||||
port = {'id': 'update-port-1',
|
||||
ext_sg.SECURITYGROUPS: ['default']}
|
||||
self.callback_nvsd.port_update(context, port=port)
|
||||
self.assertEqual(get_vif_port_by_id.call_count, 3)
|
||||
self.assertEqual(refresh_firewall.call_count, 1)
|
||||
|
||||
get_vif_port_by_id.return_value = None
|
||||
port = {'id': 'update-port-1',
|
||||
ext_sg.SECURITYGROUPS: ['default']}
|
||||
self.callback_nvsd.port_update(context, port=port)
|
||||
self.assertEqual(get_vif_port_by_id.call_count, 4)
|
||||
self.assertEqual(refresh_firewall.call_count, 1)
|
||||
|
||||
|
||||
class TestNVSDAgent(TestOneConvergenceAgentBase):
|
||||
|
||||
def _setup_mock(self):
|
||||
self.get_vif_ports = mock.patch.object(
|
||||
ovs_lib.OVSBridge, 'get_vif_port_set',
|
||||
return_value=set(['id-1', 'id-2'])).start()
|
||||
self.prepare_devices_filter = mock.patch.object(
|
||||
self.agent.sg_agent, 'prepare_devices_filter').start()
|
||||
self.remove_devices_filter = mock.patch.object(
|
||||
self.agent.sg_agent, 'remove_devices_filter').start()
|
||||
|
||||
def test_daemon_loop(self):
|
||||
|
||||
def state_check(index):
|
||||
self.assertEqual(len(self.vif_ports_scenario[index]),
|
||||
len(self.agent.ports))
|
||||
|
||||
# Fake time.sleep to stop the infinite loop in daemon_loop()
|
||||
self.sleep_count = 0
|
||||
|
||||
def sleep_mock(*args, **kwargs):
|
||||
state_check(self.sleep_count)
|
||||
self.sleep_count += 1
|
||||
if self.sleep_count >= DAEMON_LOOP_COUNT:
|
||||
raise RuntimeError()
|
||||
|
||||
self.vif_ports_scenario = [set(), set(), set(), set(['id-1', 'id-2']),
|
||||
set(['id-2', 'id-3'])]
|
||||
|
||||
# Ensure vif_ports_scenario is longer than DAEMON_LOOP_COUNT
|
||||
if len(self.vif_ports_scenario) < DAEMON_LOOP_COUNT:
|
||||
self.vif_ports_scenario.extend(
|
||||
[] for _i in moves.range(DAEMON_LOOP_COUNT -
|
||||
len(self.vif_ports_scenario)))
|
||||
|
||||
with mock.patch.object(time,
|
||||
'sleep',
|
||||
side_effect=sleep_mock) as sleep,\
|
||||
mock.patch.object(ovs_lib.OVSBridge,
|
||||
'get_vif_port_set') as get_vif_port_set,\
|
||||
mock.patch.object(
|
||||
self.agent.sg_agent,
|
||||
'prepare_devices_filter') as prepare_devices_filter,\
|
||||
mock.patch.object(
|
||||
self.agent.sg_agent,
|
||||
'remove_devices_filter') as remove_devices_filter:
|
||||
get_vif_port_set.side_effect = self.vif_ports_scenario
|
||||
|
||||
with testtools.ExpectedException(RuntimeError):
|
||||
self.agent.daemon_loop()
|
||||
self.assertEqual(sleep.call_count, DAEMON_LOOP_COUNT)
|
||||
|
||||
expected = [mock.call(set(['id-1', 'id-2'])),
|
||||
mock.call(set(['id-3']))]
|
||||
|
||||
self.assertEqual(prepare_devices_filter.call_count, 2)
|
||||
prepare_devices_filter.assert_has_calls(expected)
|
||||
|
||||
expected = [mock.call(set([])), mock.call(set(['id-1']))]
|
||||
|
||||
self.assertEqual(remove_devices_filter.call_count, 2)
|
||||
remove_devices_filter.assert_has_calls(expected)
|
||||
|
||||
sleep.assert_called_with(self.agent.polling_interval)
|
||||
|
||||
|
||||
class TestOneConvergenceAgentMain(base.BaseTestCase):
|
||||
def test_main(self):
|
||||
with mock.patch.object(nvsd_neutron_agent,
|
||||
'NVSDNeutronAgent') as agent,\
|
||||
mock.patch.object(nvsd_neutron_agent,
|
||||
'common_config') as common_config,\
|
||||
mock.patch.object(nvsd_neutron_agent, 'config') as config:
|
||||
config.AGENT.integration_bridge = 'br-int-dummy'
|
||||
config.AGENT.polling_interval = 5
|
||||
|
||||
nvsd_neutron_agent.main()
|
||||
|
||||
self.assertTrue(common_config.setup_logging.called)
|
||||
agent.assert_has_calls([
|
||||
mock.call('br-int-dummy', 5),
|
||||
mock.call().daemon_loop()
|
||||
])
|
@ -1,123 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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.
|
||||
#
|
||||
|
||||
"""Test Library for OneConvergencePlugin."""
|
||||
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
|
||||
from neutron import context
|
||||
from neutron.extensions import portbindings
|
||||
from neutron import manager
|
||||
from neutron.plugins.oneconvergence import plugin as nvsd_plugin
|
||||
from neutron.tests.unit import _test_extension_portbindings as test_bindings
|
||||
from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
|
||||
from neutron.tests.unit.extensions import test_l3
|
||||
|
||||
PLUGIN_NAME = 'neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2'
|
||||
|
||||
|
||||
class OneConvergencePluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
_plugin_name = PLUGIN_NAME
|
||||
|
||||
def setUp(self):
|
||||
if 'v6' in self._testMethodName:
|
||||
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||
|
||||
def mocked_oneconvergence_init(self):
|
||||
def side_effect(*args, **kwargs):
|
||||
return {'id': str(uuid.uuid4())}
|
||||
|
||||
self.nvsdlib = mock.Mock()
|
||||
self.nvsdlib.create_network.side_effect = side_effect
|
||||
|
||||
with mock.patch.object(nvsd_plugin.OneConvergencePluginV2,
|
||||
'oneconvergence_init',
|
||||
new=mocked_oneconvergence_init):
|
||||
super(OneConvergencePluginV2TestCase,
|
||||
self).setUp(self._plugin_name)
|
||||
|
||||
|
||||
class TestOneConvergencePluginNetworksV2(test_plugin.TestNetworksV2,
|
||||
OneConvergencePluginV2TestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestOneConvergencePluginSubnetsV2(test_plugin.TestSubnetsV2,
|
||||
OneConvergencePluginV2TestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestOneConvergencePluginPortsV2(test_plugin.TestPortsV2,
|
||||
test_bindings.PortBindingsTestCase,
|
||||
OneConvergencePluginV2TestCase):
|
||||
VIF_TYPE = portbindings.VIF_TYPE_OVS
|
||||
|
||||
def test_port_vif_details(self):
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
with self.port(name='name') as port1:
|
||||
ctx = context.get_admin_context()
|
||||
port = plugin.get_port(ctx, port1['port']['id'])
|
||||
self.assertEqual(port['binding:vif_type'],
|
||||
portbindings.VIF_TYPE_OVS)
|
||||
|
||||
def test_ports_vif_details(self):
|
||||
cfg.CONF.set_default('allow_overlapping_ips', True)
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
with self.port(), self.port():
|
||||
ctx = context.get_admin_context()
|
||||
ports = plugin.get_ports(ctx)
|
||||
self.assertEqual(len(ports), 2)
|
||||
for port in ports:
|
||||
self.assertEqual(port['binding:vif_type'],
|
||||
portbindings.VIF_TYPE_OVS)
|
||||
|
||||
|
||||
class TestOneConvergenceBasicGet(test_plugin.TestBasicGet,
|
||||
OneConvergencePluginV2TestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestOneConvergenceV2HTTPResponse(test_plugin.TestV2HTTPResponse,
|
||||
OneConvergencePluginV2TestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestOneConvergenceL3NatTestCase(test_l3.L3NatDBIntTestCase):
|
||||
_plugin_name = PLUGIN_NAME
|
||||
|
||||
def setUp(self):
|
||||
if 'v6' in self._testMethodName:
|
||||
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||
|
||||
def mocked_oneconvergence_init(self):
|
||||
def side_effect(*args, **kwargs):
|
||||
return {'id': str(uuid.uuid4())}
|
||||
|
||||
self.nvsdlib = mock.Mock()
|
||||
self.nvsdlib.create_network.side_effect = side_effect
|
||||
|
||||
ext_mgr = test_l3.L3TestExtensionManager()
|
||||
|
||||
with mock.patch.object(nvsd_plugin.OneConvergencePluginV2,
|
||||
'oneconvergence_init',
|
||||
new=mocked_oneconvergence_init):
|
||||
super(TestOneConvergenceL3NatTestCase,
|
||||
self).setUp(plugin=self._plugin_name, ext_mgr=ext_mgr)
|
||||
|
||||
def test_floatingip_with_invalid_create_port(self):
|
||||
self._test_floatingip_with_invalid_create_port(self._plugin_name)
|
@ -1,267 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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 mock
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from neutron.plugins.oneconvergence.lib import nvsdlib
|
||||
from neutron.tests import base
|
||||
|
||||
NETWORKS_URI = "/pluginhandler/ocplugin/tenant/%s/lnetwork/"
|
||||
NETWORK_URI = NETWORKS_URI + "%s"
|
||||
GET_ALL_NETWORKS = "/pluginhandler/ocplugin/tenant/getallnetworks"
|
||||
|
||||
SUBNETS_URI = NETWORK_URI + "/lsubnet/"
|
||||
SUBNET_URI = SUBNETS_URI + "%s"
|
||||
GET_ALL_SUBNETS = "/pluginhandler/ocplugin/tenant/getallsubnets"
|
||||
|
||||
PORTS_URI = NETWORK_URI + "/lport/"
|
||||
PORT_URI = PORTS_URI + "%s"
|
||||
|
||||
EXT_URI = "/pluginhandler/ocplugin/ext/tenant/%s"
|
||||
FLOATING_IPS_URI = EXT_URI + "/floatingip/"
|
||||
FLOATING_IP_URI = FLOATING_IPS_URI + "%s"
|
||||
|
||||
ROUTERS_URI = EXT_URI + "/lrouter/"
|
||||
ROUTER_URI = ROUTERS_URI + "%s"
|
||||
|
||||
TEST_NET = 'test-network'
|
||||
TEST_SUBNET = 'test-subnet'
|
||||
TEST_PORT = 'test-port'
|
||||
TEST_FIP = 'test-floatingip'
|
||||
TEST_ROUTER = 'test-router'
|
||||
TEST_TENANT = 'test-tenant'
|
||||
|
||||
|
||||
class TestNVSDApi(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNVSDApi, self).setUp()
|
||||
self.nvsdlib = nvsdlib.NVSDApi()
|
||||
|
||||
def test_create_network(self):
|
||||
network_obj = {
|
||||
"name": 'test-net',
|
||||
"tenant_id": TEST_TENANT,
|
||||
"shared": False,
|
||||
"admin_state_up": True,
|
||||
"router:external": False
|
||||
}
|
||||
resp = mock.Mock()
|
||||
resp.json.return_value = {'id': 'uuid'}
|
||||
with mock.patch.object(self.nvsdlib, 'send_request',
|
||||
return_value=resp) as send_request:
|
||||
uri = NETWORKS_URI % TEST_TENANT
|
||||
net = self.nvsdlib.create_network(network_obj)
|
||||
send_request.assert_called_once_with(
|
||||
"POST", uri,
|
||||
body=jsonutils.dumps(network_obj),
|
||||
resource='network',
|
||||
tenant_id=TEST_TENANT)
|
||||
self.assertEqual(net, {'id': 'uuid'})
|
||||
|
||||
def test_update_network(self):
|
||||
network = {'id': TEST_NET,
|
||||
'tenant_id': TEST_TENANT}
|
||||
update_network = {'name': 'new_name'}
|
||||
uri = NETWORK_URI % (TEST_TENANT, TEST_NET)
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.update_network(network, update_network)
|
||||
send_request.assert_called_once_with(
|
||||
"PUT", uri, body=jsonutils.dumps(update_network),
|
||||
resource='network', tenant_id=TEST_TENANT,
|
||||
resource_id=TEST_NET)
|
||||
|
||||
def test_delete_network(self):
|
||||
network = {'id': TEST_NET,
|
||||
'tenant_id': TEST_TENANT}
|
||||
|
||||
uri = NETWORK_URI % (TEST_TENANT, TEST_NET)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
with mock.patch.object(self.nvsdlib, '_get_ports'):
|
||||
self.nvsdlib.delete_network(network)
|
||||
send_request.assert_called_once_with(
|
||||
"DELETE", uri, resource='network',
|
||||
tenant_id=TEST_TENANT, resource_id=TEST_NET)
|
||||
|
||||
def test_create_port(self):
|
||||
path = PORTS_URI % (TEST_TENANT, TEST_NET)
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
fixed_ips = [{'ip_address': '10.0.0.2',
|
||||
'subnet_id': TEST_SUBNET}]
|
||||
|
||||
lport = {
|
||||
"id": TEST_PORT,
|
||||
"name": 'test',
|
||||
"device_id": "device_id",
|
||||
"device_owner": "device_owner",
|
||||
"mac_address": "mac_address",
|
||||
"fixed_ips": fixed_ips,
|
||||
"admin_state_up": True,
|
||||
"network_id": TEST_NET,
|
||||
"status": 'ACTIVE'
|
||||
}
|
||||
self.nvsdlib.create_port(TEST_TENANT, lport)
|
||||
expected = {"id": TEST_PORT, "name": 'test',
|
||||
"device_id": "device_id",
|
||||
"device_owner": "device_owner",
|
||||
"mac_address": "mac_address",
|
||||
"ip_address": '10.0.0.2',
|
||||
"subnet_id": TEST_SUBNET,
|
||||
"admin_state_up": True,
|
||||
"network_id": TEST_NET,
|
||||
"status": 'ACTIVE'}
|
||||
send_request.assert_called_once_with(
|
||||
"POST", path,
|
||||
body=jsonutils.dumps(expected),
|
||||
resource='port',
|
||||
tenant_id=TEST_TENANT)
|
||||
|
||||
def test_update_port(self):
|
||||
port = {'id': TEST_PORT,
|
||||
'network_id': TEST_NET}
|
||||
|
||||
port_update = {'name': 'new-name'}
|
||||
uri = PORT_URI % (TEST_TENANT, TEST_NET, TEST_PORT)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.update_port(TEST_TENANT, port, port_update)
|
||||
send_request.assert_called_once_with(
|
||||
"PUT", uri,
|
||||
body=jsonutils.dumps(port_update),
|
||||
resource='port',
|
||||
resource_id='test-port',
|
||||
tenant_id=TEST_TENANT)
|
||||
|
||||
def test_delete_port(self):
|
||||
port = {'network_id': TEST_NET,
|
||||
'tenant_id': TEST_TENANT}
|
||||
uri = PORT_URI % (TEST_TENANT, TEST_NET, TEST_PORT)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.delete_port(TEST_PORT, port)
|
||||
send_request.assert_called_once_with("DELETE", uri,
|
||||
resource='port',
|
||||
tenant_id=TEST_TENANT,
|
||||
resource_id=TEST_PORT)
|
||||
|
||||
def test_create_subnet(self):
|
||||
subnet = {'id': TEST_SUBNET,
|
||||
'tenant_id': TEST_TENANT,
|
||||
'network_id': TEST_NET}
|
||||
uri = SUBNETS_URI % (TEST_TENANT, TEST_NET)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.create_subnet(subnet)
|
||||
send_request.assert_called_once_with("POST", uri,
|
||||
body=jsonutils.dumps(subnet),
|
||||
resource='subnet',
|
||||
tenant_id=TEST_TENANT)
|
||||
|
||||
def test_update_subnet(self):
|
||||
subnet = {'id': TEST_SUBNET,
|
||||
'tenant_id': TEST_TENANT,
|
||||
'network_id': TEST_NET}
|
||||
subnet_update = {'name': 'new-name'}
|
||||
uri = SUBNET_URI % (TEST_TENANT, TEST_NET, TEST_SUBNET)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.update_subnet(subnet, subnet_update)
|
||||
send_request.assert_called_once_with(
|
||||
"PUT", uri,
|
||||
body=jsonutils.dumps(subnet_update), resource='subnet',
|
||||
tenant_id=TEST_TENANT, resource_id=TEST_SUBNET)
|
||||
|
||||
def test_delete_subnet(self):
|
||||
subnet = {'id': TEST_SUBNET,
|
||||
'tenant_id': TEST_TENANT,
|
||||
'network_id': TEST_NET}
|
||||
uri = SUBNET_URI % (TEST_TENANT, TEST_NET, TEST_SUBNET)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.delete_subnet(subnet)
|
||||
send_request.assert_called_once_with("DELETE", uri,
|
||||
resource='subnet',
|
||||
tenant_id=TEST_TENANT,
|
||||
resource_id=TEST_SUBNET)
|
||||
|
||||
def test_create_floatingip(self):
|
||||
floatingip = {'id': TEST_FIP,
|
||||
'tenant_id': TEST_TENANT}
|
||||
uri = FLOATING_IPS_URI % TEST_TENANT
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.create_floatingip(floatingip)
|
||||
send_request.assert_called_once_with(
|
||||
"POST", uri,
|
||||
body=jsonutils.dumps(floatingip),
|
||||
resource='floating_ip',
|
||||
tenant_id=TEST_TENANT)
|
||||
|
||||
def test_update_floatingip(self):
|
||||
floatingip = {'id': TEST_FIP,
|
||||
'tenant_id': TEST_TENANT}
|
||||
uri = FLOATING_IP_URI % (TEST_TENANT, TEST_FIP)
|
||||
|
||||
floatingip_update = {'floatingip': {'router_id': TEST_ROUTER}}
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.update_floatingip(floatingip, floatingip_update)
|
||||
send_request.assert_called_once_with(
|
||||
"PUT", uri,
|
||||
body=jsonutils.dumps(floatingip_update['floatingip']),
|
||||
resource='floating_ip', tenant_id=TEST_TENANT,
|
||||
resource_id=TEST_FIP)
|
||||
|
||||
def test_delete_floatingip(self):
|
||||
floatingip = {'id': TEST_FIP,
|
||||
'tenant_id': TEST_TENANT}
|
||||
uri = FLOATING_IP_URI % (TEST_TENANT, TEST_FIP)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.delete_floatingip(floatingip)
|
||||
send_request.assert_called_once_with(
|
||||
"DELETE", uri, resource='floating_ip', tenant_id=TEST_TENANT,
|
||||
resource_id=TEST_FIP)
|
||||
|
||||
def test_create_router(self):
|
||||
router = {'id': TEST_ROUTER, 'tenant_id': TEST_TENANT}
|
||||
uri = ROUTERS_URI % TEST_TENANT
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.create_router(router)
|
||||
send_request.assert_called_once_with(
|
||||
"POST", uri, body=jsonutils.dumps(router), resource='router',
|
||||
tenant_id=TEST_TENANT)
|
||||
|
||||
def test_update_router(self):
|
||||
router = {'id': TEST_ROUTER, 'tenant_id': TEST_TENANT}
|
||||
uri = ROUTER_URI % (TEST_TENANT, TEST_ROUTER)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.update_router(router)
|
||||
send_request.assert_called_once_with(
|
||||
"PUT", uri, body=jsonutils.dumps(router),
|
||||
resource='router', tenant_id=TEST_TENANT,
|
||||
resource_id=TEST_ROUTER)
|
||||
|
||||
def test_delete_router(self):
|
||||
uri = ROUTER_URI % (TEST_TENANT, TEST_ROUTER)
|
||||
|
||||
with mock.patch.object(self.nvsdlib, 'send_request') as send_request:
|
||||
self.nvsdlib.delete_router(TEST_TENANT, TEST_ROUTER)
|
||||
send_request.assert_called_once_with(
|
||||
"DELETE", uri, resource='router',
|
||||
tenant_id=TEST_TENANT, resource_id=TEST_ROUTER)
|
@ -1,59 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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 mock
|
||||
from oslo_serialization import jsonutils
|
||||
import requests
|
||||
|
||||
from neutron.plugins.oneconvergence.lib import config # noqa
|
||||
from neutron.plugins.oneconvergence.lib import plugin_helper as client
|
||||
from neutron.tests import base
|
||||
|
||||
|
||||
class TestPluginHelper(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestPluginHelper, self).setUp()
|
||||
self.nvsdcontroller = client.NVSDController()
|
||||
|
||||
def get_response(self, *args, **kwargs):
|
||||
response = mock.Mock()
|
||||
response.status_code = requests.codes.ok
|
||||
response.content = jsonutils.dumps({'session_uuid': 'new_auth_token'})
|
||||
return response
|
||||
|
||||
def test_login(self):
|
||||
login_url = ('http://127.0.0.1:8082/pluginhandler/ocplugin/'
|
||||
'authmgmt/login')
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
data = jsonutils.dumps({"user_name": "ocplugin", "passwd": "oc123"})
|
||||
timeout = 30.0
|
||||
|
||||
with mock.patch.object(self.nvsdcontroller.pool, 'request',
|
||||
side_effect=self.get_response) as request:
|
||||
self.nvsdcontroller.login()
|
||||
request.assert_called_once_with('POST', url=login_url,
|
||||
headers=headers, data=data,
|
||||
timeout=timeout)
|
||||
|
||||
def test_request(self):
|
||||
with mock.patch.object(self.nvsdcontroller.pool, 'request',
|
||||
side_effect=self.get_response) as request:
|
||||
self.nvsdcontroller.login()
|
||||
self.nvsdcontroller.request("POST", "/some_url")
|
||||
self.assertEqual(request.call_count, 2)
|
||||
request.assert_called_with(
|
||||
'POST',
|
||||
url='http://127.0.0.1:8082/some_url?authToken=new_auth_token',
|
||||
headers={'Content-Type': 'application/json'}, data='',
|
||||
timeout=30.0)
|
@ -1,106 +0,0 @@
|
||||
# Copyright 2014 OneConvergence, 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 uuid
|
||||
|
||||
import mock
|
||||
|
||||
from neutron.extensions import securitygroup as ext_sg
|
||||
from neutron import manager
|
||||
from neutron.plugins.oneconvergence import plugin as nvsd_plugin
|
||||
from neutron.tests import tools
|
||||
from neutron.tests.unit.agent import test_securitygroups_rpc as test_sg_rpc
|
||||
from neutron.tests.unit.extensions import test_securitygroup as test_sg
|
||||
|
||||
PLUGIN_NAME = ('neutron.plugins.oneconvergence.'
|
||||
'plugin.OneConvergencePluginV2')
|
||||
AGENTNOTIFIER = ('neutron.plugins.oneconvergence.'
|
||||
'plugin.NVSDPluginV2AgentNotifierApi')
|
||||
DUMMY_NVSD_LIB = ('neutron.tests.unit.plugins.oneconvergence.'
|
||||
'dummynvsdlib.NVSDApi')
|
||||
|
||||
|
||||
class OneConvergenceSecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase):
|
||||
_plugin_name = PLUGIN_NAME
|
||||
|
||||
def setUp(self):
|
||||
if 'v6' in self._testMethodName:
|
||||
self.skipTest("NVSD Plugin does not support IPV6.")
|
||||
|
||||
def mocked_oneconvergence_init(self):
|
||||
def side_effect(*args, **kwargs):
|
||||
return {'id': str(uuid.uuid4())}
|
||||
|
||||
self.nvsdlib = mock.Mock()
|
||||
self.nvsdlib.create_network.side_effect = side_effect
|
||||
|
||||
test_sg_rpc.set_firewall_driver(test_sg_rpc.FIREWALL_HYBRID_DRIVER)
|
||||
notifier_cls = mock.patch(AGENTNOTIFIER).start()
|
||||
self.notifier = mock.Mock()
|
||||
notifier_cls.return_value = self.notifier
|
||||
self.useFixture(tools.AttributeMapMemento())
|
||||
with mock.patch.object(nvsd_plugin.OneConvergencePluginV2,
|
||||
'oneconvergence_init',
|
||||
new=mocked_oneconvergence_init):
|
||||
super(OneConvergenceSecurityGroupsTestCase,
|
||||
self).setUp(PLUGIN_NAME)
|
||||
|
||||
def tearDown(self):
|
||||
super(OneConvergenceSecurityGroupsTestCase, self).tearDown()
|
||||
|
||||
|
||||
class TestOneConvergenceSGServerRpcCallBack(
|
||||
OneConvergenceSecurityGroupsTestCase,
|
||||
test_sg_rpc.SGServerRpcCallBackTestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestOneConvergenceSecurityGroups(OneConvergenceSecurityGroupsTestCase,
|
||||
test_sg.TestSecurityGroups,
|
||||
test_sg_rpc.SGNotificationTestMixin):
|
||||
|
||||
def test_security_group_get_port_from_device(self):
|
||||
with self.network() as n:
|
||||
with self.subnet(n):
|
||||
with self.security_group() as sg:
|
||||
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(mock.Mock(),
|
||||
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(mock.Mock(), 'bad_device_id')
|
||||
self.assertIsNone(port_dict)
|
@ -66,7 +66,6 @@ data_files =
|
||||
etc/neutron/plugins/ml2/sriov_agent.ini
|
||||
etc/neutron/plugins/mlnx = etc/neutron/plugins/mlnx/mlnx_conf.ini
|
||||
etc/neutron/plugins/nuage = etc/neutron/plugins/nuage/nuage_plugin.ini
|
||||
etc/neutron/plugins/oneconvergence = etc/neutron/plugins/oneconvergence/nvsdplugin.ini
|
||||
etc/neutron/plugins/ovsvapp = etc/neutron/plugins/ovsvapp/ovsvapp_agent.ini
|
||||
scripts =
|
||||
bin/neutron-rootwrap-xen-dom0
|
||||
@ -87,7 +86,6 @@ console_scripts =
|
||||
neutron-netns-cleanup = neutron.cmd.netns_cleanup:main
|
||||
neutron-ns-metadata-proxy = neutron.cmd.eventlet.agents.metadata_proxy:main
|
||||
neutron-ovsvapp-agent = neutron.cmd.eventlet.plugins.ovsvapp_neutron_agent:main
|
||||
neutron-nvsd-agent = neutron.plugins.oneconvergence.agent.nvsd_neutron_agent:main
|
||||
neutron-openvswitch-agent = neutron.cmd.eventlet.plugins.ovs_neutron_agent:main
|
||||
neutron-ovs-cleanup = neutron.cmd.ovs_cleanup:main
|
||||
neutron-pd-notify = neutron.cmd.pd_notify:main
|
||||
@ -107,7 +105,6 @@ neutron.core_plugins =
|
||||
embrane = neutron.plugins.embrane.plugins.embrane_ml2_plugin:EmbraneMl2Plugin
|
||||
ml2 = neutron.plugins.ml2.plugin:Ml2Plugin
|
||||
nuage = neutron.plugins.nuage.plugin:NuagePlugin
|
||||
oneconvergence = neutron.plugins.oneconvergence.plugin:OneConvergencePluginV2
|
||||
neutron.service_plugins =
|
||||
dummy = neutron.tests.unit.dummy_plugin:DummyServicePlugin
|
||||
router = neutron.services.l3_router.l3_router_plugin:L3RouterPlugin
|
||||
|
@ -16,7 +16,6 @@ ignore_regexes=(
|
||||
"^plugins/brocade.*$"
|
||||
"^plugins/embrane.*$"
|
||||
"^plugins/ibm.*$"
|
||||
"^plugins/oneconvergence.*$"
|
||||
# The following open source plugin tests are not actually unit
|
||||
# tests and are ignored pending their relocation to the functional
|
||||
# test tree.
|
||||
|
Loading…
Reference in New Issue
Block a user