PLUMgrid plugin v2
This commit implements blueprint plumgrid-plugin-v2 Includes PLUMlib Library Fake PLUMLib library for Unit Tests Remove the use of topologies Includes IOVISOR VIF driver Implements External Networks Change-Id: I8ba90862e5a416d04d3327b46fcb0f6f3fa65248
This commit is contained in:
parent
a28087d5e6
commit
76c68adaea
@ -1,16 +1,13 @@
|
||||
# Config file for Neutron PLUMgrid plugin
|
||||
# Config file for Neutron PLUMgrid Plugin
|
||||
|
||||
[plumgridnos]
|
||||
# This line should be pointing to the NOS server,
|
||||
# for the PLUMgrid platform. In other deployments,
|
||||
# this is known as controller
|
||||
# nos_server=<nos-ip-address>
|
||||
# nos_server_port=<nos-port>
|
||||
# Authentification parameters for the NOS server.
|
||||
[PLUMgridDirector]
|
||||
# This line should be pointing to the PLUMgrid Director,
|
||||
# for the PLUMgrid platform.
|
||||
# director_server=<director-ip-address>
|
||||
# director_server_port=<director-port>
|
||||
# Authentification parameters for the Director.
|
||||
# These are the admin credentials to manage and control
|
||||
# the NOS server.
|
||||
# username=<nos-admin-username>
|
||||
# password=<nos-admin-password>
|
||||
# the PLUMgrid Director server.
|
||||
# username=<director-admin-username>
|
||||
# password=<director-admin-password>
|
||||
# servertimeout=5
|
||||
# Name of the network topology to be deployed by NOS
|
||||
# topologyname=<nos-topology-name>
|
||||
|
@ -37,6 +37,7 @@ CAP_PORT_FILTER = 'port_filter'
|
||||
|
||||
VIF_TYPE_UNBOUND = 'unbound'
|
||||
VIF_TYPE_BINDING_FAILED = 'binding_failed'
|
||||
VIF_TYPE_IOVISOR = 'iovisor'
|
||||
VIF_TYPE_OVS = 'ovs'
|
||||
VIF_TYPE_IVS = 'ivs'
|
||||
VIF_TYPE_BRIDGE = 'bridge'
|
||||
|
@ -1,7 +1,8 @@
|
||||
PLUMgrid Neutron Virtual Network Plugin
|
||||
PLUMgrid Neutron Plugin for Virtual Network Infrastructure (VNI)
|
||||
|
||||
This plugin implements Neutron v2 APIs and helps configure
|
||||
L2/L3 virtual networks consisting of PLUMgrid Platform.
|
||||
Implements External Networks and Port Binding Extension
|
||||
|
||||
For more details on use please refer to:
|
||||
http://wiki.openstack.org/plumgrid-neutron
|
||||
http://wiki.openstack.org/PLUMgrid-Neutron
|
||||
|
@ -28,4 +28,4 @@ class PLUMgridException(base_exec.NeutronException):
|
||||
|
||||
|
||||
class PLUMgridConnectionFailed(PLUMgridException):
|
||||
message = _("Connection failed with PLUMgrid NOS: %(err_msg)s")
|
||||
message = _("Connection failed with PLUMgrid Director: %(err_msg)s")
|
||||
|
16
neutron/plugins/plumgrid/drivers/__init__.py
Normal file
16
neutron/plugins/plumgrid/drivers/__init__.py
Normal file
@ -0,0 +1,16 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2013 PLUMgrid, 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.
|
||||
#
|
||||
# @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc.
|
79
neutron/plugins/plumgrid/drivers/fake_plumlib.py
Normal file
79
neutron/plugins/plumgrid/drivers/fake_plumlib.py
Normal file
@ -0,0 +1,79 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2013 PLUMgrid, 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.
|
||||
#
|
||||
# @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc.
|
||||
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Plumlib():
|
||||
"""
|
||||
Class PLUMgrid Fake Library. This library is a by-pass implementation
|
||||
for the PLUMgrid Library. This class is being used by the unit test
|
||||
integration in Neutron.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
LOG.info('Python PLUMgrid Fake Library Started ')
|
||||
pass
|
||||
|
||||
def director_conn(self, director_plumgrid, director_port, timeout):
|
||||
LOG.info('Fake Director: %s', director_plumgrid + ':' + director_port)
|
||||
pass
|
||||
|
||||
def create_network(self, tenant_id, net_db):
|
||||
pass
|
||||
|
||||
def update_network(self, tenant_id, net_id):
|
||||
pass
|
||||
|
||||
def delete_network(self, net_db, net_id):
|
||||
pass
|
||||
|
||||
def create_subnet(self, sub_db, net_db, ipnet):
|
||||
pass
|
||||
|
||||
def update_subnet(self, org_sub_db, new_sub_db, ipnet):
|
||||
pass
|
||||
|
||||
def delete_subnet(self, tenant_id, net_db, net_id):
|
||||
pass
|
||||
|
||||
def create_port(self, port_db, router_db):
|
||||
pass
|
||||
|
||||
def update_port(self, port_db, router_db):
|
||||
pass
|
||||
|
||||
def delete_port(self, port_db, router_db):
|
||||
pass
|
||||
|
||||
def create_router(self, tenant_id, router_db):
|
||||
pass
|
||||
|
||||
def update_router(self, router_db, router_id):
|
||||
pass
|
||||
|
||||
def delete_router(self, tenant_id, router_id):
|
||||
pass
|
||||
|
||||
def add_router_interface(self, tenant_id, router_id, port_db, ipnet):
|
||||
pass
|
||||
|
||||
def remove_router_interface(self, tenant_id, net_id, router_id):
|
||||
pass
|
85
neutron/plugins/plumgrid/drivers/plumlib.py
Normal file
85
neutron/plugins/plumgrid/drivers/plumlib.py
Normal file
@ -0,0 +1,85 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2013 PLUMgrid, 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.
|
||||
#
|
||||
# @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc.
|
||||
|
||||
"""
|
||||
Neutron Plug-in for PLUMgrid Virtual Networking Infrastructure (VNI)
|
||||
This plugin will forward authenticated REST API calls
|
||||
to the PLUMgrid Network Management System called Director
|
||||
"""
|
||||
|
||||
from plumgridlib import plumlib
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Plumlib(object):
|
||||
"""
|
||||
Class PLUMgrid Python Library. This library is a third-party tool
|
||||
needed by PLUMgrid plugin to implement all core API in Neutron.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
LOG.info('Python PLUMgrid Library Started ')
|
||||
|
||||
def director_conn(self, director_plumgrid, director_port, timeout):
|
||||
self.plumlib = plumlib.Plumlib(director_plumgrid,
|
||||
director_port,
|
||||
timeout)
|
||||
|
||||
def create_network(self, tenant_id, net_db):
|
||||
self.plumlib.create_network(tenant_id, net_db)
|
||||
|
||||
def update_network(self, tenant_id, net_id):
|
||||
self.plumlib.update_network(tenant_id, net_id)
|
||||
|
||||
def delete_network(self, net_db, net_id):
|
||||
self.plumlib.delete_network(net_db, net_id)
|
||||
|
||||
def create_subnet(self, sub_db, net_db, ipnet):
|
||||
self.plumlib.create_subnet(sub_db, net_db, ipnet)
|
||||
|
||||
def update_subnet(self, org_sub_db, new_sub_db, ipnet):
|
||||
self.plumlib.update_subnet(org_sub_db, new_sub_db, ipnet)
|
||||
|
||||
def delete_subnet(self, tenant_id, net_db, net_id):
|
||||
self.plumlib.delete_subnet(tenant_id, net_db, net_id)
|
||||
|
||||
def create_port(self, port_db, router_db):
|
||||
self.plumlib.create_port(port_db, router_db)
|
||||
|
||||
def update_port(self, port_db, router_db):
|
||||
self.plumlib.update_port(port_db, router_db)
|
||||
|
||||
def delete_port(self, port_db, router_db):
|
||||
self.plumlib.delete_port(port_db, router_db)
|
||||
|
||||
def create_router(self, tenant_id, router_db):
|
||||
self.plumlib.create_router(tenant_id, router_db)
|
||||
|
||||
def update_router(self, router_db, router_id):
|
||||
self.plumlib.update_router(router_db, router_id)
|
||||
|
||||
def delete_router(self, tenant_id, router_id):
|
||||
self.plumlib.delete_router(tenant_id, router_id)
|
||||
|
||||
def add_router_interface(self, tenant_id, router_id, port_db, ipnet):
|
||||
self.plumlib.add_router_interface(tenant_id, router_id, port_db, ipnet)
|
||||
|
||||
def remove_router_interface(self, tenant_id, net_id, router_id):
|
||||
self.plumlib.remove_router_interface(tenant_id, net_id, router_id)
|
@ -1,44 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2013 PLUMgrid, 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.
|
||||
#
|
||||
# @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc.
|
||||
# @author: Brenden Blanco, bblanco@plumgrid.com, PLUMgrid, Inc.
|
||||
|
||||
"""
|
||||
Snippets needed by the PLUMgrid Plugin
|
||||
"""
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DataNOSPLUMgrid():
|
||||
|
||||
BASE_NOS_URL = '/0/connectivity/domain/'
|
||||
|
||||
def __init__(self):
|
||||
LOG.info(_('NeutronPluginPLUMgrid Status: NOS Body Data Creation'))
|
||||
|
||||
def create_domain_body_data(self, tenant_id):
|
||||
body_data = {"container_group": tenant_id}
|
||||
return body_data
|
||||
|
||||
def create_network_body_data(self, tenant_id, topology_name):
|
||||
body_data = {"config_template": "single_bridge",
|
||||
"container_group": tenant_id,
|
||||
"topology_name": topology_name}
|
||||
return body_data
|
@ -1,325 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2013 PLUMgrid, 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.
|
||||
#
|
||||
# @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc.
|
||||
|
||||
"""
|
||||
Neutron PLUMgrid Plug-in for PLUMgrid Virtual Technology
|
||||
This plugin will forward authenticated REST API calls
|
||||
to the Network Operating System by PLUMgrid called NOS
|
||||
"""
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.db import api as db
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.plumgrid.common import exceptions as plum_excep
|
||||
from neutron.plugins.plumgrid.plumgrid_nos_plugin.plugin_ver import VERSION
|
||||
from neutron.plugins.plumgrid.plumgrid_nos_plugin import plumgrid_nos_snippets
|
||||
from neutron.plugins.plumgrid.plumgrid_nos_plugin import rest_connection
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
nos_server_opts = [
|
||||
cfg.StrOpt('nos_server', default='localhost',
|
||||
help=_("PLUMgrid NOS server to connect to")),
|
||||
cfg.StrOpt('nos_server_port', default='8080',
|
||||
help=_("PLUMgrid NOS server port to connect to")),
|
||||
cfg.StrOpt('username', default='username',
|
||||
help=_("PLUMgrid NOS admin username")),
|
||||
cfg.StrOpt('password', default='password', secret=True,
|
||||
help=_("PLUMgrid NOS admin password")),
|
||||
cfg.IntOpt('servertimeout', default=5,
|
||||
help=_("PLUMgrid NOS server timeout")),
|
||||
cfg.StrOpt('topologyname', default='t1',
|
||||
help=_("PLUMgrid NOS topology name")), ]
|
||||
|
||||
|
||||
cfg.CONF.register_opts(nos_server_opts, "PLUMgridNOS")
|
||||
|
||||
|
||||
class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2):
|
||||
|
||||
def __init__(self):
|
||||
LOG.info(_('NeutronPluginPLUMgrid Status: Starting Plugin'))
|
||||
|
||||
# PLUMgrid NOS configuration
|
||||
nos_plumgrid = cfg.CONF.PLUMgridNOS.nos_server
|
||||
nos_port = cfg.CONF.PLUMgridNOS.nos_server_port
|
||||
timeout = cfg.CONF.PLUMgridNOS.servertimeout
|
||||
self.topology_name = cfg.CONF.PLUMgridNOS.topologyname
|
||||
self.snippets = plumgrid_nos_snippets.DataNOSPLUMgrid()
|
||||
|
||||
# TODO(Edgar) These are placeholders for next PLUMgrid release
|
||||
cfg.CONF.PLUMgridNOS.username
|
||||
cfg.CONF.PLUMgridNOS.password
|
||||
self.rest_conn = rest_connection.RestConnection(nos_plumgrid,
|
||||
nos_port, timeout)
|
||||
if self.rest_conn is None:
|
||||
raise SystemExit(_('NeutronPluginPLUMgrid Status: '
|
||||
'Aborting Plugin'))
|
||||
|
||||
else:
|
||||
# Plugin DB initialization
|
||||
db.configure_db()
|
||||
|
||||
# PLUMgrid NOS info validation
|
||||
LOG.info(_('NeutronPluginPLUMgrid NOS: %s'), nos_plumgrid)
|
||||
if not nos_plumgrid:
|
||||
raise SystemExit(_('NeutronPluginPLUMgrid Status: '
|
||||
'NOS value is missing in config file'))
|
||||
|
||||
LOG.debug(_('NeutronPluginPLUMgrid Status: Neutron server with '
|
||||
'PLUMgrid Plugin has started'))
|
||||
|
||||
def create_network(self, context, network):
|
||||
"""Create network core Neutron API."""
|
||||
|
||||
LOG.debug(_('NeutronPluginPLUMgrid Status: create_network() called'))
|
||||
|
||||
# Plugin DB - Network Create and validation
|
||||
tenant_id = self._get_tenant_id_for_create(context,
|
||||
network["network"])
|
||||
self._network_admin_state(network)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
net = super(NeutronPluginPLUMgridV2, self).create_network(context,
|
||||
network)
|
||||
|
||||
try:
|
||||
LOG.debug(_('NeutronPluginPLUMgrid Status: %(tenant_id)s, '
|
||||
'%(network)s, %(network_id)s'),
|
||||
dict(
|
||||
tenant_id=tenant_id,
|
||||
network=network["network"],
|
||||
network_id=net["id"],
|
||||
))
|
||||
nos_url = self.snippets.BASE_NOS_URL + net["id"]
|
||||
headers = {}
|
||||
body_data = self.snippets.create_domain_body_data(tenant_id)
|
||||
self.rest_conn.nos_rest_conn(nos_url,
|
||||
'PUT', body_data, headers)
|
||||
|
||||
except Exception:
|
||||
err_message = _("PLUMgrid NOS communication failed")
|
||||
LOG.Exception(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
|
||||
# return created network
|
||||
return net
|
||||
|
||||
def update_network(self, context, net_id, network):
|
||||
"""Update network core Neutron API."""
|
||||
|
||||
LOG.debug(_("NeutronPluginPLUMgridV2.update_network() called"))
|
||||
self._network_admin_state(network)
|
||||
tenant_id = self._get_tenant_id_for_create(context, network["network"])
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Network Update
|
||||
new_network = super(
|
||||
NeutronPluginPLUMgridV2, self).update_network(context,
|
||||
net_id, network)
|
||||
|
||||
try:
|
||||
# PLUMgrid Server does not support updating resources yet
|
||||
nos_url = self.snippets.BASE_NOS_URL + net_id
|
||||
headers = {}
|
||||
body_data = {}
|
||||
self.rest_conn.nos_rest_conn(nos_url,
|
||||
'DELETE', body_data, headers)
|
||||
nos_url = self.snippets.BASE_NOS_URL + new_network["id"]
|
||||
body_data = self.snippets.create_domain_body_data(tenant_id)
|
||||
self.rest_conn.nos_rest_conn(nos_url,
|
||||
'PUT', body_data, headers)
|
||||
except Exception:
|
||||
err_message = _("PLUMgrid NOS communication failed")
|
||||
LOG.Exception(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
|
||||
# return updated network
|
||||
return new_network
|
||||
|
||||
def delete_network(self, context, net_id):
|
||||
"""Delete network core Neutron API."""
|
||||
LOG.debug(_("NeutronPluginPLUMgrid Status: delete_network() called"))
|
||||
super(NeutronPluginPLUMgridV2, self).get_network(context, net_id)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Network Delete
|
||||
super(NeutronPluginPLUMgridV2, self).delete_network(context,
|
||||
net_id)
|
||||
|
||||
try:
|
||||
nos_url = self.snippets.BASE_NOS_URL + net_id
|
||||
headers = {}
|
||||
body_data = {}
|
||||
self.rest_conn.nos_rest_conn(nos_url,
|
||||
'DELETE', body_data, headers)
|
||||
except Exception:
|
||||
err_message = _("PLUMgrid NOS communication failed")
|
||||
LOG.Exception(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
|
||||
def create_port(self, context, port):
|
||||
"""Create port core Neutron API."""
|
||||
LOG.debug(_("NeutronPluginPLUMgrid Status: create_port() called"))
|
||||
|
||||
# Port operations on PLUMgrid NOS is an automatic operation from the
|
||||
# VIF driver operations in Nova. It requires admin_state_up to be True
|
||||
port["port"]["admin_state_up"] = True
|
||||
|
||||
# Plugin DB - Port Create and Return port
|
||||
return super(NeutronPluginPLUMgridV2, self).create_port(context,
|
||||
port)
|
||||
|
||||
def update_port(self, context, port_id, port):
|
||||
"""Update port core Neutron API."""
|
||||
LOG.debug(_("NeutronPluginPLUMgrid Status: update_port() called"))
|
||||
|
||||
# Port operations on PLUMgrid NOS is an automatic operation from the
|
||||
# VIF driver operations in Nova.
|
||||
|
||||
# Plugin DB - Port Update
|
||||
return super(NeutronPluginPLUMgridV2, self).update_port(
|
||||
context, port_id, port)
|
||||
|
||||
def delete_port(self, context, port_id):
|
||||
"""Delete port core Neutron API."""
|
||||
|
||||
LOG.debug(_("NeutronPluginPLUMgrid Status: delete_port() called"))
|
||||
|
||||
# Port operations on PLUMgrid NOS is an automatic operation from the
|
||||
# VIF driver operations in Nova.
|
||||
|
||||
# Plugin DB - Port Delete
|
||||
super(NeutronPluginPLUMgridV2, self).delete_port(context, port_id)
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
"""Create subnet core Neutron API."""
|
||||
|
||||
LOG.debug(_("NeutronPluginPLUMgrid Status: create_subnet() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Subnet Create
|
||||
subnet = super(NeutronPluginPLUMgridV2, self).create_subnet(
|
||||
context, subnet)
|
||||
subnet_details = self._get_subnet(context, subnet["id"])
|
||||
net_id = subnet_details["network_id"]
|
||||
tenant_id = subnet_details["tenant_id"]
|
||||
|
||||
try:
|
||||
nos_url = self.snippets.BASE_NOS_URL + net_id
|
||||
headers = {}
|
||||
body_data = self.snippets.create_network_body_data(
|
||||
tenant_id, self.topology_name)
|
||||
self.rest_conn.nos_rest_conn(nos_url,
|
||||
'PUT', body_data, headers)
|
||||
except Exception:
|
||||
err_message = _("PLUMgrid NOS communication failed: ")
|
||||
LOG.Exception(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
|
||||
return subnet
|
||||
|
||||
def delete_subnet(self, context, subnet_id):
|
||||
"""Delete subnet core Neutron API."""
|
||||
|
||||
LOG.debug(_("NeutronPluginPLUMgrid Status: delete_subnet() called"))
|
||||
#Collecting subnet info
|
||||
subnet_details = self._get_subnet(context, subnet_id)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Subnet Delete
|
||||
del_subnet = super(NeutronPluginPLUMgridV2, self).delete_subnet(
|
||||
context, subnet_id)
|
||||
try:
|
||||
headers = {}
|
||||
body_data = {}
|
||||
net_id = subnet_details["network_id"]
|
||||
self._cleaning_nos_subnet_structure(body_data, headers, net_id)
|
||||
except Exception:
|
||||
err_message = _("PLUMgrid NOS communication failed: ")
|
||||
LOG.Exception(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
|
||||
return del_subnet
|
||||
|
||||
def update_subnet(self, context, subnet_id, subnet):
|
||||
"""Update subnet core Neutron API."""
|
||||
|
||||
LOG.debug(_("update_subnet() called"))
|
||||
#Collecting subnet info
|
||||
initial_subnet = self._get_subnet(context, subnet_id)
|
||||
net_id = initial_subnet["network_id"]
|
||||
tenant_id = initial_subnet["tenant_id"]
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Subnet Update
|
||||
new_subnet = super(NeutronPluginPLUMgridV2, self).update_subnet(
|
||||
context, subnet_id, subnet)
|
||||
|
||||
try:
|
||||
# PLUMgrid Server does not support updating resources yet
|
||||
headers = {}
|
||||
body_data = {}
|
||||
self._cleaning_nos_subnet_structure(body_data, headers, net_id)
|
||||
nos_url = self.snippets.BASE_NOS_URL + net_id
|
||||
body_data = self.snippets.create_network_body_data(
|
||||
tenant_id, self.topology_name)
|
||||
self.rest_conn.nos_rest_conn(nos_url,
|
||||
'PUT', body_data, headers)
|
||||
|
||||
except Exception:
|
||||
err_message = _("PLUMgrid NOS communication failed: ")
|
||||
LOG.Exception(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
|
||||
return new_subnet
|
||||
|
||||
"""
|
||||
Extension API implementation
|
||||
"""
|
||||
# TODO(Edgar) Complete extensions for PLUMgrid
|
||||
|
||||
"""
|
||||
Internal PLUMgrid fuctions
|
||||
"""
|
||||
|
||||
def _get_plugin_version(self):
|
||||
return VERSION
|
||||
|
||||
def _cleaning_nos_subnet_structure(self, body_data, headers, net_id):
|
||||
domain_structure = ['/properties', '/link', '/ne']
|
||||
for structure in domain_structure:
|
||||
nos_url = self.snippets.BASE_NOS_URL + net_id + structure
|
||||
self.rest_conn.nos_rest_conn(nos_url, 'DELETE', body_data, headers)
|
||||
|
||||
def _network_admin_state(self, network):
|
||||
try:
|
||||
if network["network"].get("admin_state_up"):
|
||||
network_name = network["network"]["name"]
|
||||
if network["network"]["admin_state_up"] is False:
|
||||
LOG.warning(_("Network with admin_state_up=False are not "
|
||||
"supported yet by this plugin. Ignoring "
|
||||
"setting for network %s"), network_name)
|
||||
except Exception:
|
||||
err_message = _("Network Admin State Validation Falied: ")
|
||||
LOG.Exception(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
return network
|
@ -1,97 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2013 PLUMgrid, 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.
|
||||
#
|
||||
# @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc.
|
||||
# @author: Brenden Blanco, bblanco@plumgrid.com, PLUMgrid, Inc.
|
||||
|
||||
"""
|
||||
Neutron PLUMgrid Plug-in for PLUMgrid Virtual Technology
|
||||
This plugin will forward authenticated REST API calls
|
||||
to the Network Operating System by PLUMgrid called NOS
|
||||
"""
|
||||
|
||||
import httplib
|
||||
import urllib2
|
||||
|
||||
from neutron.openstack.common import jsonutils as json
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.plumgrid.common import exceptions as plum_excep
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RestConnection(object):
|
||||
"""REST Connection to PLUMgrid NOS Server."""
|
||||
|
||||
def __init__(self, server, port, timeout):
|
||||
LOG.debug(_('NeutronPluginPLUMgrid Status: REST Connection Started'))
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.timeout = timeout
|
||||
|
||||
def nos_rest_conn(self, nos_url, action, data, headers):
|
||||
self.nos_url = nos_url
|
||||
body_data = json.dumps(data)
|
||||
if not headers:
|
||||
headers = {}
|
||||
headers['Content-type'] = 'application/json'
|
||||
headers['Accept'] = 'application/json'
|
||||
|
||||
LOG.debug(_("PLUMgrid_NOS_Server: %(server)s %(port)s %(action)s"),
|
||||
dict(server=self.server, port=self.port, action=action))
|
||||
|
||||
conn = httplib.HTTPConnection(self.server, self.port,
|
||||
timeout=self.timeout)
|
||||
if conn is None:
|
||||
LOG.error(_('PLUMgrid_NOS_Server: Could not establish HTTP '
|
||||
'connection'))
|
||||
return
|
||||
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid_NOS_Server Sending Data: %(nos_url)s "
|
||||
"%(body_data)s %(headers)s"),
|
||||
dict(
|
||||
nos_url=nos_url,
|
||||
body_data=body_data,
|
||||
headers=headers,
|
||||
))
|
||||
conn.request(action, nos_url, body_data, headers)
|
||||
resp = conn.getresponse()
|
||||
resp_str = resp.read()
|
||||
|
||||
LOG.debug(_("PLUMgrid_NOS_Server Connection Data: %(resp)s, "
|
||||
"%(resp_str)s"), dict(resp=resp, resp_str=resp_str))
|
||||
|
||||
if resp.status is httplib.OK:
|
||||
try:
|
||||
respdata = json.loads(resp_str)
|
||||
LOG.debug(_("PLUMgrid_NOS_Server Connection RESP: %s"),
|
||||
respdata)
|
||||
pass
|
||||
except ValueError:
|
||||
err_message = _("PLUMgrid HTTP Connection Failed: ")
|
||||
LOG.Exception(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
|
||||
ret = (resp.status, resp.reason, resp_str)
|
||||
except urllib2.HTTPError:
|
||||
LOG.error(_('PLUMgrid_NOS_Server: %(action)s failure, %(e)r'))
|
||||
ret = 0, None, None, None
|
||||
conn.close()
|
||||
LOG.debug(_("PLUMgrid_NOS_Server: status=%(status)d, "
|
||||
"reason=%(reason)r, ret=%(ret)s"),
|
||||
{'status': ret[0], 'reason': ret[1], 'ret': ret[2]})
|
||||
return ret
|
@ -16,4 +16,4 @@
|
||||
#
|
||||
# @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc.
|
||||
|
||||
VERSION = "0.1"
|
||||
VERSION = "0.2"
|
546
neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py
Normal file
546
neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py
Normal file
@ -0,0 +1,546 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
# Copyright 2013 PLUMgrid, 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.
|
||||
#
|
||||
# @author: Edgar Magana, emagana@plumgrid.com, PLUMgrid, Inc.
|
||||
|
||||
"""
|
||||
Neutron Plug-in for PLUMgrid Virtual Networking Infrastructure (VNI)
|
||||
This plugin will forward authenticated REST API calls
|
||||
to the PLUMgrid Network Management System called Director
|
||||
"""
|
||||
|
||||
import netaddr
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.db import api as db
|
||||
from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import l3_db
|
||||
from neutron.db import portbindings_db
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.openstack.common import importutils
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.plumgrid.common import exceptions as plum_excep
|
||||
from neutron.plugins.plumgrid.plumgrid_plugin.plugin_ver import VERSION
|
||||
from neutron import policy
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
PLUM_DRIVER = 'neutron.plugins.plumgrid.drivers.plumlib.Plumlib'
|
||||
ERR_MESSAGE = 'PLUMgrid Director communication failed'
|
||||
|
||||
director_server_opts = [
|
||||
cfg.StrOpt('director_server', default='localhost',
|
||||
help=_("PLUMgrid Director server to connect to")),
|
||||
cfg.StrOpt('director_server_port', default='8080',
|
||||
help=_("PLUMgrid Director server port to connect to")),
|
||||
cfg.StrOpt('username', default='username',
|
||||
help=_("PLUMgrid Director admin username")),
|
||||
cfg.StrOpt('password', default='password', secret=True,
|
||||
help=_("PLUMgrid Director admin password")),
|
||||
cfg.IntOpt('servertimeout', default=5,
|
||||
help=_("PLUMgrid Director server timeout")), ]
|
||||
|
||||
cfg.CONF.register_opts(director_server_opts, "PLUMgridDirector")
|
||||
|
||||
|
||||
class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
portbindings_db.PortBindingMixin,
|
||||
l3_db.L3_NAT_db_mixin):
|
||||
|
||||
supported_extension_aliases = ["router", "binding"]
|
||||
|
||||
binding_view = "extension:port_binding:view"
|
||||
binding_set = "extension:port_binding:set"
|
||||
|
||||
def __init__(self):
|
||||
LOG.info(_('Neutron PLUMgrid Director: Starting Plugin'))
|
||||
|
||||
# Plugin DB initialization
|
||||
db.configure_db()
|
||||
|
||||
self.plumgrid_init()
|
||||
|
||||
LOG.debug(_('Neutron PLUMgrid Director: Neutron server with '
|
||||
'PLUMgrid Plugin has started'))
|
||||
|
||||
def plumgrid_init(self):
|
||||
"""PLUMgrid initialization."""
|
||||
director_plumgrid = cfg.CONF.PLUMgridDirector.director_server
|
||||
director_port = cfg.CONF.PLUMgridDirector.director_server_port
|
||||
timeout = cfg.CONF.PLUMgridDirector.servertimeout
|
||||
|
||||
# PLUMgrid Director info validation
|
||||
LOG.info(_('Neutron PLUMgrid Director: %s'), director_plumgrid)
|
||||
self._plumlib = importutils.import_object(PLUM_DRIVER)
|
||||
self._plumlib.director_conn(director_plumgrid, director_port, timeout)
|
||||
|
||||
def create_network(self, context, network):
|
||||
"""Create Neutron network.
|
||||
|
||||
Creates a PLUMgrid-based bridge.
|
||||
"""
|
||||
|
||||
LOG.debug(_('Neutron PLUMgrid Director: create_network() called'))
|
||||
|
||||
# Plugin DB - Network Create and validation
|
||||
tenant_id = self._get_tenant_id_for_create(context,
|
||||
network["network"])
|
||||
self._network_admin_state(network)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
net_db = super(NeutronPluginPLUMgridV2,
|
||||
self).create_network(context, network)
|
||||
# Propagate all L3 data into DB
|
||||
self._process_l3_create(context, net_db, network['network'])
|
||||
|
||||
try:
|
||||
LOG.debug(_('PLUMgrid Library: create_network() called'))
|
||||
self._plumlib.create_network(tenant_id, net_db)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
# Return created network
|
||||
return net_db
|
||||
|
||||
def update_network(self, context, net_id, network):
|
||||
"""Update Neutron network.
|
||||
|
||||
Updates a PLUMgrid-based bridge.
|
||||
"""
|
||||
|
||||
LOG.debug(_("Neutron PLUMgrid Director: update_network() called"))
|
||||
self._network_admin_state(network)
|
||||
tenant_id = self._get_tenant_id_for_create(context, network["network"])
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Network Update
|
||||
net_db = super(
|
||||
NeutronPluginPLUMgridV2, self).update_network(context,
|
||||
net_id, network)
|
||||
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: update_network() called"))
|
||||
self._plumlib.update_network(tenant_id, net_id)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
# Return updated network
|
||||
return net_db
|
||||
|
||||
def delete_network(self, context, net_id):
|
||||
"""Delete Neutron network.
|
||||
|
||||
Deletes a PLUMgrid-based bridge.
|
||||
"""
|
||||
|
||||
LOG.debug(_("Neutron PLUMgrid Director: delete_network() called"))
|
||||
net_db = super(NeutronPluginPLUMgridV2,
|
||||
self).get_network(context, net_id)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Network Delete
|
||||
super(NeutronPluginPLUMgridV2, self).delete_network(context,
|
||||
net_id)
|
||||
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: update_network() called"))
|
||||
self._plumlib.delete_network(net_db, net_id)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
def create_port(self, context, port):
|
||||
"""Create Neutron port.
|
||||
|
||||
Creates a PLUMgrid-based port on the specific Virtual Network
|
||||
Function (VNF).
|
||||
"""
|
||||
LOG.debug(_("Neutron PLUMgrid Director: create_port() called"))
|
||||
|
||||
# Port operations on PLUMgrid Director is an automatic operation
|
||||
# from the VIF driver operations in Nova.
|
||||
# It requires admin_state_up to be True
|
||||
|
||||
port["port"]["admin_state_up"] = True
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Port Create and Return port
|
||||
port_db = super(NeutronPluginPLUMgridV2, self).create_port(context,
|
||||
port)
|
||||
device_id = port_db["device_id"]
|
||||
if port_db["device_owner"] == "network:router_gateway":
|
||||
router_db = self._get_router(context, device_id)
|
||||
else:
|
||||
router_db = None
|
||||
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: create_port() called"))
|
||||
self._plumlib.create_port(port_db, router_db)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
# Plugin DB - Port Create and Return port
|
||||
return self._port_viftype_binding(context, port_db)
|
||||
|
||||
def update_port(self, context, port_id, port):
|
||||
"""Update Neutron port.
|
||||
|
||||
Updates a PLUMgrid-based port on the specific Virtual Network
|
||||
Function (VNF).
|
||||
"""
|
||||
LOG.debug(_("Neutron PLUMgrid Director: update_port() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Port Create and Return port
|
||||
port_db = super(NeutronPluginPLUMgridV2, self).update_port(
|
||||
context, port_id, port)
|
||||
device_id = port_db["device_id"]
|
||||
if port_db["device_owner"] == "network:router_gateway":
|
||||
router_db = self._get_router(context, device_id)
|
||||
else:
|
||||
router_db = None
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: create_port() called"))
|
||||
self._plumlib.update_port(port_db, router_db)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
# Plugin DB - Port Update
|
||||
return self._port_viftype_binding(context, port_db)
|
||||
|
||||
def delete_port(self, context, port_id, l3_port_check=True):
|
||||
"""Delete Neutron port.
|
||||
|
||||
Deletes a PLUMgrid-based port on the specific Virtual Network
|
||||
Function (VNF).
|
||||
"""
|
||||
|
||||
LOG.debug(_("Neutron PLUMgrid Director: delete_port() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Port Create and Return port
|
||||
port_db = super(NeutronPluginPLUMgridV2,
|
||||
self).get_port(context, port_id)
|
||||
super(NeutronPluginPLUMgridV2, self).delete_port(context, port_id)
|
||||
|
||||
if port_db["device_owner"] == "network:router_gateway":
|
||||
device_id = port_db["device_id"]
|
||||
router_db = self._get_router(context, device_id)
|
||||
else:
|
||||
router_db = None
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: delete_port() called"))
|
||||
self._plumlib.delete_port(port_db, router_db)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
def get_port(self, context, id, fields=None):
|
||||
with context.session.begin(subtransactions=True):
|
||||
port_db = super(NeutronPluginPLUMgridV2,
|
||||
self).get_port(context, id, fields)
|
||||
|
||||
self._port_viftype_binding(context, port_db)
|
||||
return self._fields(port_db, fields)
|
||||
|
||||
def get_ports(self, context, filters=None, fields=None):
|
||||
with context.session.begin(subtransactions=True):
|
||||
ports_db = super(NeutronPluginPLUMgridV2,
|
||||
self).get_ports(context, filters, fields)
|
||||
for port_db in ports_db:
|
||||
self._port_viftype_binding(context, port_db)
|
||||
return [self._fields(port, fields) for port in ports_db]
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
"""Create Neutron subnet.
|
||||
|
||||
Creates a PLUMgrid-based DHCP and NAT Virtual Network
|
||||
Functions (VNFs).
|
||||
"""
|
||||
|
||||
LOG.debug(_("Neutron PLUMgrid Director: create_subnet() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Subnet Create
|
||||
net_db = super(NeutronPluginPLUMgridV2, self).get_network(
|
||||
context, subnet['subnet']['network_id'], fields=None)
|
||||
s = subnet['subnet']
|
||||
ipnet = netaddr.IPNetwork(s['cidr'])
|
||||
|
||||
# PLUMgrid Director reserves the last IP address for GW
|
||||
# when is not defined
|
||||
if s['gateway_ip'] is attributes.ATTR_NOT_SPECIFIED:
|
||||
gw_ip = str(netaddr.IPAddress(ipnet.last - 1))
|
||||
subnet['subnet']['gateway_ip'] = gw_ip
|
||||
|
||||
# PLUMgrid reserves the first IP
|
||||
if s['allocation_pools'] == attributes.ATTR_NOT_SPECIFIED:
|
||||
allocation_pool = self._allocate_pools_for_subnet(context, s)
|
||||
subnet['subnet']['allocation_pools'] = allocation_pool
|
||||
|
||||
sub_db = super(NeutronPluginPLUMgridV2, self).create_subnet(
|
||||
context, subnet)
|
||||
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: create_subnet() called"))
|
||||
self._plumlib.create_subnet(sub_db, net_db, ipnet)
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
return sub_db
|
||||
|
||||
def delete_subnet(self, context, subnet_id):
|
||||
"""Delete subnet core Neutron API."""
|
||||
|
||||
LOG.debug(_("Neutron PLUMgrid Director: delete_subnet() called"))
|
||||
# Collecting subnet info
|
||||
sub_db = self._get_subnet(context, subnet_id)
|
||||
tenant_id = self._get_tenant_id_for_create(context, subnet_id)
|
||||
net_id = sub_db["network_id"]
|
||||
net_db = self.get_network(context, net_id)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Subnet Delete
|
||||
super(NeutronPluginPLUMgridV2, self).delete_subnet(
|
||||
context, subnet_id)
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: delete_subnet() called"))
|
||||
self._plumlib.delete_subnet(tenant_id, net_db, net_id)
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
def update_subnet(self, context, subnet_id, subnet):
|
||||
"""Update subnet core Neutron API."""
|
||||
|
||||
LOG.debug(_("update_subnet() called"))
|
||||
# Collecting subnet info
|
||||
org_sub_db = self._get_subnet(context, subnet_id)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Plugin DB - Subnet Update
|
||||
new_sub_db = super(NeutronPluginPLUMgridV2,
|
||||
self).update_subnet(context, subnet_id, subnet)
|
||||
ipnet = netaddr.IPNetwork(new_sub_db['cidr'])
|
||||
|
||||
try:
|
||||
# PLUMgrid Server does not support updating resources yet
|
||||
LOG.debug(_("PLUMgrid Library: update_network() called"))
|
||||
self._plumlib.update_subnet(org_sub_db, new_sub_db, ipnet)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
return new_sub_db
|
||||
|
||||
def create_router(self, context, router):
|
||||
"""
|
||||
Create router extension Neutron API
|
||||
"""
|
||||
LOG.debug(_("Neutron PLUMgrid Director: create_router() called"))
|
||||
|
||||
tenant_id = self._get_tenant_id_for_create(context, router["router"])
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
|
||||
# Create router in DB
|
||||
router_db = super(NeutronPluginPLUMgridV2,
|
||||
self).create_router(context, router)
|
||||
# Create router on the network controller
|
||||
try:
|
||||
# Add Router to VND
|
||||
LOG.debug(_("PLUMgrid Library: create_router() called"))
|
||||
self._plumlib.create_router(tenant_id, router_db)
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
# Return created router
|
||||
return router_db
|
||||
|
||||
def update_router(self, context, router_id, router):
|
||||
|
||||
LOG.debug(_("Neutron PLUMgrid Director: update_router() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
router_db = super(NeutronPluginPLUMgridV2,
|
||||
self).update_router(context, router_id, router)
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: update_router() called"))
|
||||
self._plumlib.update_router(router_db, router_id)
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
# Return updated router
|
||||
return router_db
|
||||
|
||||
def delete_router(self, context, router_id):
|
||||
LOG.debug(_("Neutron PLUMgrid Director: delete_router() called"))
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
orig_router = self._get_router(context, router_id)
|
||||
tenant_id = orig_router["tenant_id"]
|
||||
|
||||
super(NeutronPluginPLUMgridV2, self).delete_router(context,
|
||||
router_id)
|
||||
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: delete_router() called"))
|
||||
self._plumlib.delete_router(tenant_id, router_id)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
def add_router_interface(self, context, router_id, interface_info):
|
||||
|
||||
LOG.debug(_("Neutron PLUMgrid Director: "
|
||||
"add_router_interface() called"))
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Validate args
|
||||
router_db = self._get_router(context, router_id)
|
||||
tenant_id = router_db['tenant_id']
|
||||
|
||||
# Create interface in DB
|
||||
int_router = super(NeutronPluginPLUMgridV2,
|
||||
self).add_router_interface(context,
|
||||
router_id,
|
||||
interface_info)
|
||||
port_db = self._get_port(context, int_router['port_id'])
|
||||
subnet_id = port_db["fixed_ips"][0]["subnet_id"]
|
||||
subnet_db = super(NeutronPluginPLUMgridV2,
|
||||
self)._get_subnet(context, subnet_id)
|
||||
ipnet = netaddr.IPNetwork(subnet_db['cidr'])
|
||||
|
||||
# Create interface on the network controller
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: add_router_interface() called"))
|
||||
self._plumlib.add_router_interface(tenant_id, router_id,
|
||||
port_db, ipnet)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
return int_router
|
||||
|
||||
def remove_router_interface(self, context, router_id, int_info):
|
||||
|
||||
LOG.debug(_("Neutron PLUMgrid Director: "
|
||||
"remove_router_interface() called"))
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Validate args
|
||||
router_db = self._get_router(context, router_id)
|
||||
tenant_id = router_db['tenant_id']
|
||||
if 'port_id' in int_info:
|
||||
port = self._get_port(context, int_info['port_id'])
|
||||
net_id = port['network_id']
|
||||
|
||||
elif 'subnet_id' in int_info:
|
||||
subnet_id = int_info['subnet_id']
|
||||
subnet = self._get_subnet(context, subnet_id)
|
||||
net_id = subnet['network_id']
|
||||
|
||||
# Remove router in DB
|
||||
del_int_router = super(NeutronPluginPLUMgridV2,
|
||||
self).remove_router_interface(context,
|
||||
router_id,
|
||||
int_info)
|
||||
|
||||
try:
|
||||
LOG.debug(_("PLUMgrid Library: "
|
||||
"remove_router_interface() called"))
|
||||
self._plumlib.remove_router_interface(tenant_id,
|
||||
net_id, router_id)
|
||||
|
||||
except Exception:
|
||||
LOG.error(ERR_MESSAGE)
|
||||
raise plum_excep.PLUMgridException(err_msg=ERR_MESSAGE)
|
||||
|
||||
return del_int_router
|
||||
|
||||
"""
|
||||
Internal PLUMgrid Fuctions
|
||||
"""
|
||||
|
||||
def _get_plugin_version(self):
|
||||
return VERSION
|
||||
|
||||
def _port_viftype_binding(self, context, port):
|
||||
if self._check_view_auth(context, port, self.binding_view):
|
||||
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_IOVISOR
|
||||
port[portbindings.CAPABILITIES] = {
|
||||
portbindings.CAP_PORT_FILTER:
|
||||
'security-group' in self.supported_extension_aliases}
|
||||
return port
|
||||
|
||||
def _check_view_auth(self, context, resource, action):
|
||||
return policy.check(context, action, resource)
|
||||
|
||||
def _network_admin_state(self, network):
|
||||
try:
|
||||
if network["network"].get("admin_state_up"):
|
||||
network_name = network["network"]["name"]
|
||||
if network["network"]["admin_state_up"] is False:
|
||||
LOG.warning(_("Network with admin_state_up=False are not "
|
||||
"supported yet by this plugin. Ignoring "
|
||||
"setting for network %s"), network_name)
|
||||
except Exception:
|
||||
err_message = _("Network Admin State Validation Falied: ")
|
||||
LOG.error(err_message)
|
||||
raise plum_excep.PLUMgridException(err_msg=err_message)
|
||||
return network
|
||||
|
||||
def _allocate_pools_for_subnet(self, context, subnet):
|
||||
"""Create IP allocation pools for a given subnet
|
||||
|
||||
Pools are defined by the 'allocation_pools' attribute,
|
||||
a list of dict objects with 'start' and 'end' keys for
|
||||
defining the pool range.
|
||||
Modified from Neutron DB based class
|
||||
|
||||
"""
|
||||
|
||||
pools = []
|
||||
# Auto allocate the pool around gateway_ip
|
||||
net = netaddr.IPNetwork(subnet['cidr'])
|
||||
first_ip = net.first + 2
|
||||
last_ip = net.last - 1
|
||||
gw_ip = int(netaddr.IPAddress(subnet['gateway_ip'] or net.last))
|
||||
# Use the gw_ip to find a point for splitting allocation pools
|
||||
# for this subnet
|
||||
split_ip = min(max(gw_ip, net.first), net.last)
|
||||
if split_ip > first_ip:
|
||||
pools.append({'start': str(netaddr.IPAddress(first_ip)),
|
||||
'end': str(netaddr.IPAddress(split_ip - 1))})
|
||||
if split_ip < last_ip:
|
||||
pools.append({'start': str(netaddr.IPAddress(split_ip + 1)),
|
||||
'end': str(netaddr.IPAddress(last_ip))})
|
||||
# return auto-generated pools
|
||||
# no need to check for their validity
|
||||
return pools
|
@ -19,53 +19,84 @@
|
||||
Test cases for Neutron PLUMgrid Plug-in
|
||||
"""
|
||||
|
||||
from mock import patch
|
||||
import mock
|
||||
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.manager import NeutronManager
|
||||
from neutron.openstack.common import importutils
|
||||
from neutron.plugins.plumgrid.plumgrid_plugin import plumgrid_plugin
|
||||
from neutron.tests.unit import _test_extension_portbindings as test_bindings
|
||||
from neutron.tests.unit import test_db_plugin as test_plugin
|
||||
|
||||
|
||||
class PLUMgridPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
PLUM_DRIVER = ('neutron.plugins.plumgrid.drivers.fake_plumlib.Plumlib')
|
||||
FAKE_DIRECTOR = '1.1.1.1'
|
||||
FAKE_PORT = '1234'
|
||||
FAKE_TIMEOUT = '0'
|
||||
|
||||
_plugin_name = ('neutron.plugins.plumgrid.plumgrid_nos_plugin.'
|
||||
|
||||
class PLUMgridPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
_plugin_name = ('neutron.plugins.plumgrid.plumgrid_plugin.'
|
||||
'plumgrid_plugin.NeutronPluginPLUMgridV2')
|
||||
|
||||
def setUp(self):
|
||||
self.restHTTPConnection = patch('httplib.HTTPConnection')
|
||||
self.restHTTPConnection.start()
|
||||
def mocked_plumlib_init(self):
|
||||
director_plumgrid = FAKE_DIRECTOR
|
||||
director_port = FAKE_PORT
|
||||
timeout = FAKE_TIMEOUT
|
||||
self._plumlib = importutils.import_object(PLUM_DRIVER)
|
||||
self._plumlib.director_conn(director_plumgrid,
|
||||
director_port, timeout)
|
||||
|
||||
with mock.patch.object(plumgrid_plugin.NeutronPluginPLUMgridV2,
|
||||
'plumgrid_init', new=mocked_plumlib_init):
|
||||
super(PLUMgridPluginV2TestCase, self).setUp(self._plugin_name)
|
||||
|
||||
def tearDown(self):
|
||||
super(PLUMgridPluginV2TestCase, self).tearDown()
|
||||
self.restHTTPConnection.stop()
|
||||
|
||||
|
||||
class TestPlumgridPluginV2HTTPResponse(test_plugin.TestV2HTTPResponse,
|
||||
class TestPlumgridPluginNetworksV2(test_plugin.TestNetworksV2,
|
||||
PLUMgridPluginV2TestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestPlumgridV2HTTPResponse(test_plugin.TestV2HTTPResponse,
|
||||
PLUMgridPluginV2TestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestPlumgridPluginPortsV2(test_plugin.TestPortsV2,
|
||||
PLUMgridPluginV2TestCase):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TestPlumgridPluginNetworksV2(test_plugin.TestNetworksV2,
|
||||
PLUMgridPluginV2TestCase):
|
||||
|
||||
pass
|
||||
def test_range_allocation(self):
|
||||
self.skipTest("Plugin does not support Neutron allocation process")
|
||||
|
||||
|
||||
class TestPlumgridPluginSubnetsV2(test_plugin.TestSubnetsV2,
|
||||
PLUMgridPluginV2TestCase):
|
||||
def test_create_subnet_default_gw_conflict_allocation_pool_returns_409(
|
||||
self):
|
||||
self.skipTest("Plugin does not support Neutron allocation process")
|
||||
|
||||
pass
|
||||
def test_create_subnet_defaults(self):
|
||||
self.skipTest("Plugin does not support Neutron allocation process")
|
||||
|
||||
def test_create_subnet_gw_values(self):
|
||||
self.skipTest("Plugin does not support Neutron allocation process")
|
||||
|
||||
def test_update_subnet_gateway_in_allocation_pool_returns_409(self):
|
||||
self.skipTest("Plugin does not support Neutron allocation process")
|
||||
|
||||
|
||||
class TestPlumgridPluginPortBinding(PLUMgridPluginV2TestCase,
|
||||
test_bindings.PortBindingsTestCase):
|
||||
VIF_TYPE = portbindings.VIF_TYPE_IOVISOR
|
||||
|
||||
def setUp(self):
|
||||
super(TestPlumgridPluginPortBinding, self).setUp()
|
||||
|
||||
|
||||
class TestPlumgridNetworkAdminState(PLUMgridPluginV2TestCase):
|
||||
|
||||
def test_network_admin_state(self):
|
||||
name = 'network_test'
|
||||
admin_status_up = False
|
||||
@ -75,3 +106,18 @@ class TestPlumgridNetworkAdminState(PLUMgridPluginV2TestCase):
|
||||
'tenant_id': tenant_id}}
|
||||
plugin = NeutronManager.get_plugin()
|
||||
self.assertEqual(plugin._network_admin_state(network), network)
|
||||
|
||||
|
||||
class TestPlumgridAllocationPool(PLUMgridPluginV2TestCase):
|
||||
def test_allocate_pools_for_subnet(self):
|
||||
cidr = '10.0.0.0/24'
|
||||
gateway_ip = '10.0.0.254'
|
||||
subnet = {'gateway_ip': gateway_ip,
|
||||
'cidr': cidr,
|
||||
'ip_version': 4}
|
||||
allocation_pool = [{"start": '10.0.0.2',
|
||||
"end": '10.0.0.253'}]
|
||||
context = None
|
||||
plugin = NeutronManager.get_plugin()
|
||||
pool = plugin._allocate_pools_for_subnet(context, subnet)
|
||||
self.assertEqual(allocation_pool, pool)
|
||||
|
Loading…
Reference in New Issue
Block a user