Embrane Neutron Plugin
Implements blueprint embrane-neutron-plugin This commit implements the main Embrane plugin, which covers route and extratoute extensions. The plugin will rely on existing plugins for leveraging L2 networks, for now it only supports OpenVSwitch and vlan networks, but more supports are to come if the model is approved (or a different one is suggested). Change-Id: I90aff8ec4324bd3a7c59c411374db6a118d1a72b
This commit is contained in:
parent
5fec791ace
commit
3c95d18311
41
etc/neutron/plugins/embrane/heleos_conf.ini
Normal file
41
etc/neutron/plugins/embrane/heleos_conf.ini
Normal file
@ -0,0 +1,41 @@
|
||||
[heleos]
|
||||
#configure the ESM management address
|
||||
#in the first version of this plugin, only one ESM can be specified
|
||||
#Example:
|
||||
#esm_mgmt=
|
||||
|
||||
#configure admin username and password
|
||||
#admin_username=
|
||||
#admin_password=
|
||||
|
||||
#router image id
|
||||
#Example:
|
||||
#router_image=932ce713-e210-3d54-a0a5-518b0b5ee1b0
|
||||
|
||||
#mgmt shared security zone id
|
||||
#defines the shared management security zone. Each tenant can have a private one configured through the ESM
|
||||
#Example:
|
||||
#mgmt_id=c0bc9b6c-f110-46cf-bb01-733bfe4b5a1a
|
||||
|
||||
#in-band shared security zone id
|
||||
#defines the shared in-band security zone. Each tenant can have a private one configured through the ESM
|
||||
#Example:
|
||||
#inband_id=a6b7999d-3806-4b04-81f6-e0c5c8271afc
|
||||
|
||||
#oob-band shared security zone id
|
||||
#defines the shared out-of-band security zone. Each tenant can have a private one configured through the ESM
|
||||
#Example:
|
||||
#oob_id=e7eda5cc-b977-46cb-9c14-cab43c1b7871
|
||||
|
||||
#dummy security zone id
|
||||
#defines the dummy security zone ID. this security zone will be used by the DVAs with no neutron interfaces
|
||||
#Example:
|
||||
#dummy_utif_id=d9911310-25fc-4733-a2e0-c0eda024ef08
|
||||
|
||||
#resource pool id
|
||||
#define the shared resource pool. Each tenant can have a private one configured through the ESM
|
||||
#Example
|
||||
#resource_pool_id=
|
||||
|
||||
#define if the requests have to be executed asynchronously by the plugin or not
|
||||
#async_requests=
|
9
neutron/plugins/embrane/README
Normal file
9
neutron/plugins/embrane/README
Normal file
@ -0,0 +1,9 @@
|
||||
Embrane Neutron Plugin
|
||||
|
||||
This plugin interfaces OpenStack Neutron with Embrane's heleos platform, which
|
||||
provides layer 3-7 network services for cloud environments.
|
||||
|
||||
L2 connectivity is leveraged by one of the supported existing plugins.
|
||||
|
||||
For more details on use, configuration and implementation please refer to:
|
||||
http://wiki.openstack.org/wiki/Neutron/EmbraneNeutronPlugin
|
18
neutron/plugins/embrane/__init__.py
Normal file
18
neutron/plugins/embrane/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
18
neutron/plugins/embrane/agent/__init__.py
Normal file
18
neutron/plugins/embrane/agent/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
145
neutron/plugins/embrane/agent/dispatcher.py
Normal file
145
neutron/plugins/embrane/agent/dispatcher.py
Normal file
@ -0,0 +1,145 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from eventlet import greenthread
|
||||
from eventlet import queue
|
||||
from heleosapi import constants as h_con
|
||||
from heleosapi import exceptions as h_exc
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.embrane.agent.operations import router_operations
|
||||
from neutron.plugins.embrane.common import constants as p_con
|
||||
from neutron.plugins.embrane.common import contexts as ctx
|
||||
from neutron.plugins.embrane.common import exceptions as plugin_exc
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _validate_operation(event, status, item_id):
|
||||
if status and event not in p_con.operation_filter[status]:
|
||||
raise plugin_exc.StateConstraintException(operation=event,
|
||||
dva_id=item_id, state=status)
|
||||
|
||||
|
||||
class Dispatcher(object):
|
||||
|
||||
def __init__(self, plugin, async=True):
|
||||
self._async = async
|
||||
self._plugin = plugin
|
||||
self.sync_items = dict()
|
||||
|
||||
def dispatch_l3(self, d_context, args=(), kwargs={}):
|
||||
item = d_context.item
|
||||
event = d_context.event
|
||||
q_context = d_context.q_context
|
||||
chain = d_context.chain
|
||||
|
||||
item_id = item["id"]
|
||||
# First round validation (Controller level)
|
||||
_validate_operation(event, item["status"], item_id)
|
||||
|
||||
handlers = router_operations.handlers
|
||||
if event in handlers:
|
||||
for f in handlers[event]:
|
||||
first_run = False
|
||||
if item_id not in self.sync_items:
|
||||
self.sync_items[item_id] = queue.Queue()
|
||||
first_run = True
|
||||
self.sync_items[item_id].put(
|
||||
ctx.OperationContext(event, q_context, item, chain, f,
|
||||
args, kwargs))
|
||||
if first_run:
|
||||
t = greenthread.spawn(self._consume_l3,
|
||||
item_id,
|
||||
self.sync_items[item_id],
|
||||
self._plugin)
|
||||
if not self._async:
|
||||
t.wait()
|
||||
|
||||
def _consume_l3(self, sync_item, sync_queue, plugin):
|
||||
current_state = None
|
||||
while True:
|
||||
try:
|
||||
# If the DVA is deleted, the thread (and the associated queue)
|
||||
# can die as well
|
||||
if current_state == p_con.Status.DELETED:
|
||||
del self.sync_items[sync_item]
|
||||
return
|
||||
try:
|
||||
operation_context = sync_queue.get(
|
||||
timeout=p_con.QUEUE_TIMEOUT)
|
||||
except queue.Empty:
|
||||
del self.sync_items[sync_item]
|
||||
return
|
||||
# Second round validation (enqueued level)
|
||||
_validate_operation(operation_context.event,
|
||||
current_state,
|
||||
operation_context.item["id"])
|
||||
# Execute the preliminary operations
|
||||
(operation_context.chain and
|
||||
operation_context.chain.execute_all())
|
||||
# Execute the main operation, a transient state is maintained
|
||||
# so that the consumer can decide if it has
|
||||
# to be burned to the DB
|
||||
transient_state = None
|
||||
try:
|
||||
dva_state = operation_context.function(
|
||||
plugin._esm_api,
|
||||
operation_context.q_context.tenant_id,
|
||||
operation_context.item,
|
||||
*operation_context.args,
|
||||
**operation_context.kwargs)
|
||||
if dva_state == p_con.Status.DELETED:
|
||||
transient_state = dva_state
|
||||
else:
|
||||
if not dva_state:
|
||||
transient_state = p_con.Status.ERROR
|
||||
elif dva_state == h_con.DvaState.POWER_ON:
|
||||
transient_state = p_con.Status.ACTIVE
|
||||
else:
|
||||
transient_state = p_con.Status.READY
|
||||
|
||||
except (h_exc.PendingDva, h_exc.DvaNotFound,
|
||||
h_exc.BrokenInterface, h_exc.DvaCreationFailed,
|
||||
h_exc.DvaCreationPending, h_exc.BrokenDva,
|
||||
h_exc.ConfigurationFailed) as ex:
|
||||
LOG.warning(p_con.error_map[type(ex)] % ex.message)
|
||||
transient_state = p_con.Status.ERROR
|
||||
except h_exc.DvaDeleteFailed as ex:
|
||||
LOG.warning(p_con.error_map[type(ex)] % ex.message)
|
||||
transient_state = p_con.Status.DELETED
|
||||
finally:
|
||||
# if the returned transient state is None, no operations
|
||||
# are required on the DVA status
|
||||
if transient_state:
|
||||
if transient_state == p_con.Status.DELETED:
|
||||
current_state = plugin._delete_router(
|
||||
operation_context.q_context,
|
||||
operation_context.item["id"])
|
||||
# Error state cannot be reverted
|
||||
elif current_state != p_con.Status.ERROR:
|
||||
current_state = plugin._update_neutron_state(
|
||||
operation_context.q_context,
|
||||
operation_context.item,
|
||||
transient_state)
|
||||
except plugin_exc.StateConstraintException as e:
|
||||
LOG.error(_("%s"), e.message)
|
||||
except Exception:
|
||||
LOG.exception(_("Unhandled exception occurred"))
|
18
neutron/plugins/embrane/agent/operations/__init__.py
Normal file
18
neutron/plugins/embrane/agent/operations/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
154
neutron/plugins/embrane/agent/operations/router_operations.py
Normal file
154
neutron/plugins/embrane/agent/operations/router_operations.py
Normal file
@ -0,0 +1,154 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from functools import wraps
|
||||
|
||||
from heleosapi import exceptions as h_exc
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.embrane.common import constants as p_con
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
handlers = dict()
|
||||
|
||||
|
||||
def handler(event, handler):
|
||||
def wrap(f):
|
||||
if event not in handler.keys():
|
||||
new_func_list = [f]
|
||||
handler[event] = new_func_list
|
||||
else:
|
||||
handler[event].append(f)
|
||||
|
||||
@wraps(f)
|
||||
def wrapped_f(*args, **kwargs):
|
||||
return f(*args, **kwargs)
|
||||
return wrapped_f
|
||||
return wrap
|
||||
|
||||
|
||||
@handler(p_con.Events.CREATE_ROUTER, handlers)
|
||||
def _create_dva_and_assign_address(api, tenant_id, neutron_router,
|
||||
flavor, utif_info=None,
|
||||
ip_allocation_info=None):
|
||||
"""Creates a new router, and assign the gateway interface if any."""
|
||||
|
||||
dva = api.create_router(tenant_id=tenant_id,
|
||||
router_id=neutron_router["id"],
|
||||
name=neutron_router["name"],
|
||||
flavor=flavor,
|
||||
up=neutron_router["admin_state_up"])
|
||||
try:
|
||||
if utif_info:
|
||||
api.grow_interface(utif_info, neutron_router["admin_state_up"],
|
||||
tenant_id, neutron_router["id"])
|
||||
if ip_allocation_info:
|
||||
dva = api.allocate_address(neutron_router["id"],
|
||||
neutron_router["admin_state_up"],
|
||||
ip_allocation_info)
|
||||
except h_exc.PreliminaryOperationsFailed as ex:
|
||||
raise h_exc.BrokenInterface(err_msg=ex.message)
|
||||
|
||||
state = api.extract_dva_state(dva)
|
||||
return state
|
||||
|
||||
|
||||
@handler(p_con.Events.UPDATE_ROUTER, handlers)
|
||||
def _update_dva_and_assign_address(api, tenant_id, neutron_router,
|
||||
utif_info=None, ip_allocation_info=None,
|
||||
routes_info=[]):
|
||||
name = neutron_router["name"]
|
||||
up = neutron_router["admin_state_up"]
|
||||
r_id = neutron_router["id"]
|
||||
if ip_allocation_info or routes_info:
|
||||
up = True
|
||||
dva = api.update_dva(tenant_id=tenant_id, router_id=r_id, name=name,
|
||||
up=up, utif_info=utif_info)
|
||||
if ip_allocation_info:
|
||||
api.allocate_address(r_id, up, ip_allocation_info)
|
||||
|
||||
if routes_info:
|
||||
api.delete_extra_routes(r_id, up)
|
||||
api.set_extra_routes(r_id, neutron_router["admin_state_up"],
|
||||
routes_info)
|
||||
|
||||
return api.extract_dva_state(dva)
|
||||
|
||||
|
||||
@handler(p_con.Events.DELETE_ROUTER, handlers)
|
||||
def _delete_dva(api, tenant_id, neutron_router):
|
||||
try:
|
||||
api.delete_dva(tenant_id, neutron_router["id"])
|
||||
except h_exc.DvaNotFound:
|
||||
LOG.warning(_("The router %s had no physical representation,"
|
||||
"likely already deleted"), neutron_router["id"])
|
||||
return p_con.Status.DELETED
|
||||
|
||||
|
||||
@handler(p_con.Events.GROW_ROUTER_IF, handlers)
|
||||
def _grow_dva_iface_and_assign_address(api, tenant_id, neutron_router,
|
||||
utif_info=None,
|
||||
ip_allocation_info=None):
|
||||
try:
|
||||
dva = api.grow_interface(utif_info, neutron_router["admin_state_up"],
|
||||
tenant_id, neutron_router["id"])
|
||||
if ip_allocation_info:
|
||||
dva = api.allocate_address(neutron_router["id"],
|
||||
neutron_router["admin_state_up"],
|
||||
ip_allocation_info)
|
||||
except h_exc.PreliminaryOperationsFailed as ex:
|
||||
raise h_exc.BrokenInterface(err_msg=ex.message)
|
||||
|
||||
state = api.extract_dva_state(dva)
|
||||
return state
|
||||
|
||||
|
||||
@handler(p_con.Events.SHRINK_ROUTER_IF, handlers)
|
||||
def _shrink_dva_iface(api, tenant_id, neutron_router, port_id):
|
||||
try:
|
||||
dva = api.shrink_interface(tenant_id, neutron_router["id"],
|
||||
neutron_router["admin_state_up"], port_id)
|
||||
except h_exc.InterfaceNotFound:
|
||||
LOG.warning(_("Interface %s not found in the heleos back-end,"
|
||||
"likely already deleted"), port_id)
|
||||
except h_exc.PreliminaryOperationsFailed as ex:
|
||||
raise h_exc.BrokenInterface(err_msg=ex.message)
|
||||
state = api.extract_dva_state(dva)
|
||||
return state
|
||||
|
||||
|
||||
@handler(p_con.Events.SET_NAT_RULE, handlers)
|
||||
def _create_nat_rule(api, tenant_id, neutron_router, nat_info=None):
|
||||
|
||||
dva = api.create_nat_entry(neutron_router["id"],
|
||||
neutron_router["admin_state_up"], nat_info)
|
||||
|
||||
state = api.extract_dva_state(dva)
|
||||
return state
|
||||
|
||||
|
||||
@handler(p_con.Events.RESET_NAT_RULE, handlers)
|
||||
def _delete_nat_rule(api, tenant_id, neutron_router, floating_ip_id):
|
||||
|
||||
dva = api.remove_nat_entry(neutron_router["id"],
|
||||
neutron_router["admin_state_up"],
|
||||
floating_ip_id)
|
||||
|
||||
state = api.extract_dva_state(dva)
|
||||
return state
|
364
neutron/plugins/embrane/base_plugin.py
Normal file
364
neutron/plugins/embrane/base_plugin.py
Normal file
@ -0,0 +1,364 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from heleosapi import backend_operations as h_op
|
||||
from heleosapi import constants as h_con
|
||||
from heleosapi import exceptions as h_exc
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.common import constants as l3_constants
|
||||
from neutron.common import exceptions as neutron_exc
|
||||
from neutron.db import extraroute_db
|
||||
from neutron.db import l3_db
|
||||
from neutron.db import models_v2
|
||||
from neutron.extensions import l3
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.embrane.agent import dispatcher
|
||||
from neutron.plugins.embrane.common import config # noqa
|
||||
from neutron.plugins.embrane.common import constants as p_con
|
||||
from neutron.plugins.embrane.common import contexts as embrane_ctx
|
||||
from neutron.plugins.embrane.common import exceptions as c_exc
|
||||
from neutron.plugins.embrane.common import operation
|
||||
from neutron.plugins.embrane.common import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
conf = cfg.CONF.heleos
|
||||
|
||||
|
||||
class EmbranePlugin(object):
|
||||
"""Embrane Neutron plugin.
|
||||
|
||||
uses the heleos(c) platform and a support L2 plugin to leverage networking
|
||||
in cloud environments.
|
||||
|
||||
"""
|
||||
_l3super = extraroute_db.ExtraRoute_db_mixin
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def _run_embrane_config(self):
|
||||
# read configurations
|
||||
config_esm_mgmt = conf.esm_mgmt
|
||||
config_admin_username = conf.admin_username
|
||||
config_admin_password = conf.admin_password
|
||||
config_router_image_id = conf.router_image
|
||||
config_security_zones = {h_con.SzType.IB: conf.inband_id,
|
||||
h_con.SzType.OOB: conf.oob_id,
|
||||
h_con.SzType.MGMT: conf.mgmt_id,
|
||||
h_con.SzType.DUMMY: conf.dummy_utif_id}
|
||||
config_resource_pool = conf.resource_pool_id
|
||||
self._embrane_async = conf.async_requests
|
||||
self._esm_api = h_op.BackendOperations(
|
||||
esm_mgmt=config_esm_mgmt,
|
||||
admin_username=config_admin_username,
|
||||
admin_password=config_admin_password,
|
||||
router_image_id=config_router_image_id,
|
||||
security_zones=config_security_zones,
|
||||
resource_pool=config_resource_pool)
|
||||
self._dispatcher = dispatcher.Dispatcher(self, self._embrane_async)
|
||||
|
||||
def _make_router_dict(self, *args, **kwargs):
|
||||
return self._l3super._make_router_dict(self, *args, **kwargs)
|
||||
|
||||
def _delete_router(self, context, router_id):
|
||||
self._l3super.delete_router(self, context, router_id)
|
||||
|
||||
def _update_db_router_state(self, context, neutron_router, dva_state):
|
||||
if not dva_state:
|
||||
new_state = p_con.Status.ERROR
|
||||
elif dva_state == h_con.DvaState.POWER_ON:
|
||||
new_state = p_con.Status.ACTIVE
|
||||
else:
|
||||
new_state = p_con.Status.READY
|
||||
self._set_db_router_state(context, neutron_router, new_state)
|
||||
return new_state
|
||||
|
||||
def _set_db_router_state(self, context, neutron_router, new_state):
|
||||
return utils.set_db_item_state(context, neutron_router, new_state)
|
||||
|
||||
def _update_db_interfaces_state(self, context, neutron_router):
|
||||
router_ports = self.get_ports(context,
|
||||
{"device_id": [neutron_router["id"]]})
|
||||
self._esm_api.update_ports_status(neutron_router["id"], router_ports)
|
||||
for port in router_ports:
|
||||
db_port = self._get_port(context, port["id"])
|
||||
db_port["status"] = port["status"]
|
||||
context.session.merge(db_port)
|
||||
|
||||
def _update_neutron_state(self, context, neutron_router, state):
|
||||
try:
|
||||
self._update_db_interfaces_state(context, neutron_router)
|
||||
except Exception:
|
||||
LOG.exception(_("Unhandled exception occurred"))
|
||||
return self._set_db_router_state(context, neutron_router, state)
|
||||
|
||||
def _retrieve_prefix_from_port(self, context, neutron_port):
|
||||
subnet_id = neutron_port["fixed_ips"][0]["subnet_id"]
|
||||
subnet = self._get_subnet(context, subnet_id)
|
||||
prefix = subnet["cidr"].split("/")[1]
|
||||
return prefix
|
||||
|
||||
# L3 extension
|
||||
def create_router(self, context, router):
|
||||
r = router["router"]
|
||||
self._get_tenant_id_for_create(context, r)
|
||||
with context.session.begin(subtransactions=True):
|
||||
neutron_router = self._l3super.create_router(self, context, router)
|
||||
network_id = None
|
||||
gw_port = None
|
||||
ext_gw_info = neutron_router.get(l3_db.EXTERNAL_GW_INFO)
|
||||
if ext_gw_info:
|
||||
network_id = ext_gw_info.get("network_id")
|
||||
if network_id:
|
||||
gw_ports = self.get_ports(
|
||||
context,
|
||||
{"device_id": [id],
|
||||
"device_owner": ["network:router_gateway"]})
|
||||
if len(gw_ports) != 1:
|
||||
raise c_exc.EmbranePluginException(
|
||||
err_msg=_("there must be only one gateway port "
|
||||
"per router at once"))
|
||||
gw_port = gw_ports[0]
|
||||
|
||||
# For now, only small flavor is used
|
||||
utif_info = (self._plugin_support.retrieve_utif_info(context,
|
||||
gw_port)
|
||||
if network_id else None)
|
||||
ip_allocation_info = (utils.retrieve_ip_allocation_info(self,
|
||||
context,
|
||||
gw_port)
|
||||
if network_id else None)
|
||||
neutron_router = self._l3super._get_router(self, context,
|
||||
neutron_router["id"])
|
||||
neutron_router["status"] = p_con.Status.CREATING
|
||||
self._dispatcher.dispatch_l3(
|
||||
d_context=embrane_ctx.DispatcherContext(
|
||||
p_con.Events.CREATE_ROUTER, neutron_router, context, None),
|
||||
args=(h_con.Flavor.SMALL, utif_info, ip_allocation_info))
|
||||
return self._make_router_dict(neutron_router)
|
||||
|
||||
def update_router(self, context, id, router):
|
||||
with context.session.begin(subtransactions=True):
|
||||
db_router = self._l3super.update_router(self, context, id, router)
|
||||
gw_port = None
|
||||
ext_gw_info = db_router.get(l3_db.EXTERNAL_GW_INFO)
|
||||
if ext_gw_info:
|
||||
ext_gw_info = db_router[l3_db.EXTERNAL_GW_INFO]
|
||||
network_id = (ext_gw_info.get("network_id")
|
||||
if ext_gw_info else None)
|
||||
if network_id:
|
||||
gw_ports = self.get_ports(
|
||||
context,
|
||||
{"device_id": [id],
|
||||
"device_owner": ["network:router_gateway"]})
|
||||
if len(gw_ports) != 1:
|
||||
raise c_exc.EmbranePluginException(
|
||||
err_msg=_("there must be only one gateway port"
|
||||
" per router at once"))
|
||||
gw_port = gw_ports[0]
|
||||
|
||||
utif_info = (self._plugin_support.retrieve_utif_info(context,
|
||||
gw_port)
|
||||
if gw_port else None)
|
||||
ip_allocation_info = (utils.retrieve_ip_allocation_info(self,
|
||||
context,
|
||||
gw_port)
|
||||
if gw_port else None)
|
||||
|
||||
routes_info = router["router"].get("routes")
|
||||
|
||||
neutron_router = self._l3super._get_router(self, context, id)
|
||||
state_change = operation.Operation(
|
||||
self._set_db_router_state,
|
||||
args=(context, neutron_router, p_con.Status.UPDATING))
|
||||
self._dispatcher.dispatch_l3(
|
||||
d_context=embrane_ctx.DispatcherContext(
|
||||
p_con.Events.UPDATE_ROUTER, neutron_router, context,
|
||||
state_change),
|
||||
args=(utif_info, ip_allocation_info, routes_info))
|
||||
return self._make_router_dict(neutron_router)
|
||||
|
||||
def get_router(self, context, id, fields=None):
|
||||
"""Ensures that id does exist in the ESM."""
|
||||
neutron_router = self._get_router(context, id)
|
||||
|
||||
try:
|
||||
if neutron_router["status"] != p_con.Status.CREATING:
|
||||
self._esm_api.get_dva(id)
|
||||
except h_exc.DvaNotFound:
|
||||
|
||||
LOG.error(_("The following routers have not physical match: %s"),
|
||||
id)
|
||||
self._set_db_router_state(context, neutron_router,
|
||||
p_con.Status.ERROR)
|
||||
|
||||
LOG.debug(_("Requested router: %s"), neutron_router)
|
||||
return self._make_router_dict(neutron_router, fields)
|
||||
|
||||
def get_routers(self, context, filters=None, fields=None, sorts=None,
|
||||
limit=None, marker=None, page_reverse=False):
|
||||
"""Retrieves the router list defined by the incoming filters."""
|
||||
router_query = self._apply_filters_to_query(
|
||||
self._model_query(context, l3_db.Router),
|
||||
l3_db.Router, filters)
|
||||
id_list = [x["id"] for x in router_query
|
||||
if x["status"] != p_con.Status.CREATING]
|
||||
try:
|
||||
self._esm_api.get_dvas(id_list)
|
||||
except h_exc.DvaNotFound:
|
||||
LOG.error(_("The following routers have not physical match: %s"),
|
||||
repr(id_list))
|
||||
error_routers = []
|
||||
for id in id_list:
|
||||
try:
|
||||
error_routers.append(self._get_router(context, id))
|
||||
except l3.RouterNotFound:
|
||||
pass
|
||||
for error_router in error_routers:
|
||||
self._set_db_router_state(context, error_router,
|
||||
p_con.Status.ERROR)
|
||||
return [self._make_router_dict(router, fields)
|
||||
for router in router_query]
|
||||
|
||||
def delete_router(self, context, id):
|
||||
"""Deletes the DVA with the specific router id."""
|
||||
# Copy of the parent validation code, shouldn't the base modules
|
||||
# provide functions for validating operations?
|
||||
with context.session.begin(subtransactions=True):
|
||||
DEVICE_OWNER_ROUTER_INTF = l3_constants.DEVICE_OWNER_ROUTER_INTF
|
||||
fips = self.get_floatingips_count(context.elevated(),
|
||||
filters={"router_id": [id]})
|
||||
if fips:
|
||||
raise l3.RouterInUse(router_id=id)
|
||||
|
||||
device_filter = {"device_id": [id],
|
||||
"device_owner": [DEVICE_OWNER_ROUTER_INTF]}
|
||||
ports = self.get_ports_count(context.elevated(),
|
||||
filters=device_filter)
|
||||
if ports:
|
||||
raise l3.RouterInUse(router_id=id)
|
||||
neutron_router = self._get_router(context, id)
|
||||
state_change = operation.Operation(self._set_db_router_state,
|
||||
args=(context, neutron_router,
|
||||
p_con.Status.DELETING))
|
||||
self._dispatcher.dispatch_l3(
|
||||
d_context=embrane_ctx.DispatcherContext(
|
||||
p_con.Events.DELETE_ROUTER, neutron_router, context,
|
||||
state_change), args=())
|
||||
LOG.debug(_("Deleting router=%s"), neutron_router)
|
||||
return neutron_router
|
||||
|
||||
def add_router_interface(self, context, router_id, interface_info):
|
||||
"""Grows DVA interface in the specified subnet."""
|
||||
with context.session.begin(subtransactions=True):
|
||||
neutron_router = self._get_router(context, router_id)
|
||||
rport_qry = context.session.query(models_v2.Port)
|
||||
ports = rport_qry.filter_by(
|
||||
device_id=router_id).all()
|
||||
if len(ports) >= p_con.UTIF_LIMIT:
|
||||
raise neutron_exc.BadRequest(
|
||||
resource=router_id,
|
||||
msg=("this router doesn't support more than "
|
||||
+ str(p_con.UTIF_LIMIT) + " interfaces"))
|
||||
neutron_router_iface = self._l3super.add_router_interface(
|
||||
self, context, router_id, interface_info)
|
||||
port = self._get_port(context, neutron_router_iface["port_id"])
|
||||
utif_info = self._plugin_support.retrieve_utif_info(context, port)
|
||||
ip_allocation_info = utils.retrieve_ip_allocation_info(self,
|
||||
context,
|
||||
port)
|
||||
state_change = operation.Operation(self._set_db_router_state,
|
||||
args=(context, neutron_router,
|
||||
p_con.Status.UPDATING))
|
||||
self._dispatcher.dispatch_l3(
|
||||
d_context=embrane_ctx.DispatcherContext(
|
||||
p_con.Events.GROW_ROUTER_IF, neutron_router, context,
|
||||
state_change),
|
||||
args=(utif_info, ip_allocation_info))
|
||||
return neutron_router_iface
|
||||
|
||||
def remove_router_interface(self, context, router_id, interface_info):
|
||||
port_id = None
|
||||
if "port_id" in interface_info:
|
||||
port_id = interface_info["port_id"]
|
||||
elif "subnet_id" in interface_info:
|
||||
subnet_id = interface_info["subnet_id"]
|
||||
subnet = self._get_subnet(context, subnet_id)
|
||||
rport_qry = context.session.query(models_v2.Port)
|
||||
ports = rport_qry.filter_by(
|
||||
device_id=router_id,
|
||||
device_owner=l3_constants.DEVICE_OWNER_ROUTER_INTF,
|
||||
network_id=subnet["network_id"])
|
||||
for p in ports:
|
||||
if p["fixed_ips"][0]["subnet_id"] == subnet_id:
|
||||
port_id = p["id"]
|
||||
break
|
||||
neutron_router = self._get_router(context, router_id)
|
||||
self._l3super.remove_router_interface(self, context, router_id,
|
||||
interface_info)
|
||||
state_change = operation.Operation(self._set_db_router_state,
|
||||
args=(context, neutron_router,
|
||||
p_con.Status.UPDATING))
|
||||
self._dispatcher.dispatch_l3(
|
||||
d_context=embrane_ctx.DispatcherContext(
|
||||
p_con.Events.SHRINK_ROUTER_IF, neutron_router, context,
|
||||
state_change),
|
||||
args=(port_id,))
|
||||
|
||||
def update_floatingip(self, context, id, floatingip):
|
||||
with context.session.begin(subtransactions=True):
|
||||
db_fip = self._l3super.get_floatingip(self, context, id)
|
||||
result = self._l3super.update_floatingip(self, context, id,
|
||||
floatingip)
|
||||
|
||||
if db_fip["port_id"]:
|
||||
neutron_router = self._get_router(context, db_fip["router_id"])
|
||||
fip_id = db_fip["id"]
|
||||
state_change = operation.Operation(
|
||||
self._set_db_router_state,
|
||||
args=(context, neutron_router, p_con.Status.UPDATING))
|
||||
|
||||
self._dispatcher.dispatch_l3(
|
||||
d_context=embrane_ctx.DispatcherContext(
|
||||
p_con.Events.RESET_NAT_RULE, neutron_router, context,
|
||||
state_change),
|
||||
args=(fip_id,))
|
||||
if floatingip["floatingip"]["port_id"]:
|
||||
neutron_router = self._get_router(context, result["router_id"])
|
||||
db_fixed_port = self._get_port(context, result["port_id"])
|
||||
fixed_prefix = self._retrieve_prefix_from_port(context,
|
||||
db_fixed_port)
|
||||
db_floating_port = neutron_router["gw_port"]
|
||||
floating_prefix = self._retrieve_prefix_from_port(
|
||||
context, db_floating_port)
|
||||
nat_info = utils.retrieve_nat_info(context, result,
|
||||
fixed_prefix,
|
||||
floating_prefix,
|
||||
neutron_router)
|
||||
state_change = operation.Operation(
|
||||
self._set_db_router_state,
|
||||
args=(context, neutron_router, p_con.Status.UPDATING))
|
||||
|
||||
self._dispatcher.dispatch_l3(
|
||||
d_context=embrane_ctx.DispatcherContext(
|
||||
p_con.Events.SET_NAT_RULE, neutron_router, context,
|
||||
state_change),
|
||||
args=(nat_info,))
|
||||
return result
|
18
neutron/plugins/embrane/common/__init__.py
Normal file
18
neutron/plugins/embrane/common/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
50
neutron/plugins/embrane/common/config.py
Normal file
50
neutron/plugins/embrane/common/config.py
Normal file
@ -0,0 +1,50 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
|
||||
heleos_opts = [
|
||||
cfg.StrOpt('esm_mgmt',
|
||||
default=None,
|
||||
help=_('ESM management root address')),
|
||||
cfg.StrOpt('admin_username', default='admin',
|
||||
help=_('ESM admin username.')),
|
||||
cfg.StrOpt('admin_password', default=None,
|
||||
secret=True,
|
||||
help=_('ESM admin password.')),
|
||||
cfg.StrOpt('router_image', default=None,
|
||||
help=_('Router image id (Embrane FW/VPN)')),
|
||||
cfg.StrOpt('inband_id', default=None,
|
||||
help=_('In band Security Zone id')),
|
||||
cfg.StrOpt('oob_id', default=None,
|
||||
help=_('Out of band Security Zone id')),
|
||||
cfg.StrOpt('mgmt_id', default=None,
|
||||
help=_('Management Security Zone id')),
|
||||
cfg.StrOpt('dummy_utif_id', default=None,
|
||||
help=_('Dummy user traffic Security Zone id')),
|
||||
cfg.StrOpt('resource_pool_id', default='default',
|
||||
help=_('Shared resource pool id')),
|
||||
cfg.BoolOpt('async_requests', default=True,
|
||||
help=_('define if the requests have '
|
||||
'run asynchronously or not')),
|
||||
]
|
||||
|
||||
|
||||
cfg.CONF.register_opts(heleos_opts, "heleos")
|
84
neutron/plugins/embrane/common/constants.py
Normal file
84
neutron/plugins/embrane/common/constants.py
Normal file
@ -0,0 +1,84 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from heleosapi import exceptions as h_exc
|
||||
|
||||
from neutron.plugins.common import constants
|
||||
|
||||
|
||||
# Router specific constants
|
||||
UTIF_LIMIT = 7
|
||||
QUEUE_TIMEOUT = 300
|
||||
|
||||
|
||||
class Status:
|
||||
# Transient
|
||||
CREATING = constants.PENDING_CREATE
|
||||
UPDATING = constants.PENDING_UPDATE
|
||||
DELETING = constants.PENDING_DELETE
|
||||
# Final
|
||||
ACTIVE = constants.ACTIVE
|
||||
ERROR = constants.ERROR
|
||||
READY = constants.INACTIVE
|
||||
DELETED = "DELETED" # not visible
|
||||
|
||||
|
||||
class Events:
|
||||
CREATE_ROUTER = "create_router"
|
||||
UPDATE_ROUTER = "update_router"
|
||||
DELETE_ROUTER = "delete_router"
|
||||
GROW_ROUTER_IF = "grow_router_if"
|
||||
SHRINK_ROUTER_IF = "shrink_router_if"
|
||||
SET_NAT_RULE = "set_nat_rule"
|
||||
RESET_NAT_RULE = "reset_nat_rule"
|
||||
|
||||
operation_filter = {
|
||||
Status.ACTIVE: [Events.DELETE_ROUTER, Events.GROW_ROUTER_IF,
|
||||
Events.SHRINK_ROUTER_IF, Events.UPDATE_ROUTER,
|
||||
Events.SET_NAT_RULE, Events.RESET_NAT_RULE],
|
||||
Status.READY: [Events.DELETE_ROUTER, Events.GROW_ROUTER_IF,
|
||||
Events.SHRINK_ROUTER_IF, Events.UPDATE_ROUTER],
|
||||
Status.ERROR: [Events.DELETE_ROUTER, Events.SHRINK_ROUTER_IF],
|
||||
Status.UPDATING: [Events.DELETE_ROUTER, Events.SHRINK_ROUTER_IF,
|
||||
Events.RESET_NAT_RULE],
|
||||
Status.CREATING: [Events.DELETE_ROUTER, Events.CREATE_ROUTER],
|
||||
Status.DELETING: [Events.DELETE_ROUTER]}
|
||||
|
||||
_DVA_PENDING_ERROR_MSG = _("Dva is pending for the following reason: %s")
|
||||
_DVA_NOT_FOUNT_ERROR_MSG = _("Dva can't be found to execute the operation, "
|
||||
"probably was cancelled through the heleos UI")
|
||||
_DVA_BROKEN_ERROR_MSG = _("Dva seems to be broken for reason %s")
|
||||
_DVA_BROKEN_INTERFACE_ERROR_MSG = _("Dva interface seems to be broken "
|
||||
"for reason %s")
|
||||
_DVA_CREATION_FAILED_ERROR_MSG = _("Dva creation failed reason %s")
|
||||
_DVA_CREATION_PENDING_ERROR_MSG = _("Dva creation is in pending state "
|
||||
"for reason %s")
|
||||
_CFG_FAILED_ERROR_MSG = _("Dva configuration failed for reason %s")
|
||||
_DVA_DEL_FAILED_ERROR_MSG = _("Failed to delete the backend "
|
||||
"router for reason %s. Please remove "
|
||||
"it manually through the heleos UI")
|
||||
|
||||
error_map = {h_exc.PendingDva: _DVA_PENDING_ERROR_MSG,
|
||||
h_exc.DvaNotFound: _DVA_NOT_FOUNT_ERROR_MSG,
|
||||
h_exc.BrokenDva: _DVA_BROKEN_ERROR_MSG,
|
||||
h_exc.BrokenInterface: _DVA_BROKEN_INTERFACE_ERROR_MSG,
|
||||
h_exc.DvaCreationFailed: _DVA_CREATION_FAILED_ERROR_MSG,
|
||||
h_exc.DvaCreationPending: _DVA_CREATION_PENDING_ERROR_MSG,
|
||||
h_exc.ConfigurationFailed: _CFG_FAILED_ERROR_MSG,
|
||||
h_exc.DvaDeleteFailed: _DVA_DEL_FAILED_ERROR_MSG}
|
40
neutron/plugins/embrane/common/contexts.py
Normal file
40
neutron/plugins/embrane/common/contexts.py
Normal file
@ -0,0 +1,40 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
|
||||
class DispatcherContext(object):
|
||||
|
||||
def __init__(self, event, item, neutron_context, chain=None):
|
||||
self.event = event
|
||||
self.item = item
|
||||
self.q_context = neutron_context
|
||||
self.chain = chain
|
||||
|
||||
|
||||
class OperationContext(DispatcherContext):
|
||||
"""Operational context.
|
||||
|
||||
contains all the parameters needed to execute a status aware operation
|
||||
|
||||
"""
|
||||
def __init__(self, event, context, item, chain, function, args, kwargs):
|
||||
super(OperationContext, self).__init__(event, item, context, chain)
|
||||
self.function = function
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
35
neutron/plugins/embrane/common/exceptions.py
Normal file
35
neutron/plugins/embrane/common/exceptions.py
Normal file
@ -0,0 +1,35 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from neutron.common import exceptions as neutron_exec
|
||||
|
||||
|
||||
class EmbranePluginException(neutron_exec.NeutronException):
|
||||
message = _("An unexpected error occurred:%(err_msg)s")
|
||||
|
||||
|
||||
# Not permitted operation
|
||||
class NonPermitted(neutron_exec.BadRequest):
|
||||
pass
|
||||
|
||||
|
||||
class StateConstraintException(NonPermitted):
|
||||
message = _("Operation not permitted due to state constraint violation:"
|
||||
"%(operation)s not allowed for DVA %(dva_id)s in state "
|
||||
" %(state)s")
|
51
neutron/plugins/embrane/common/operation.py
Normal file
51
neutron/plugins/embrane/common/operation.py
Normal file
@ -0,0 +1,51 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
|
||||
class Operation(object):
|
||||
"""Defines a series of operations which shall be executed in order.
|
||||
|
||||
the operations expected are procedures, return values are discarded
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, procedure, args=(), kwargs={}, nextop=None):
|
||||
self._procedure = procedure
|
||||
self.args = args[:]
|
||||
self.kwargs = dict(kwargs)
|
||||
self.nextop = nextop
|
||||
|
||||
def execute(self):
|
||||
args = self.args
|
||||
self._procedure(*args, **self.kwargs)
|
||||
return self.nextop
|
||||
|
||||
def execute_all(self):
|
||||
nextop = self.execute()
|
||||
while nextop:
|
||||
nextop = self.execute_all()
|
||||
|
||||
def has_next(self):
|
||||
return self.nextop is not None
|
||||
|
||||
def add_bottom_operation(self, operation):
|
||||
op = self
|
||||
while op.has_next():
|
||||
op = op.nextop
|
||||
op.nextop = operation
|
65
neutron/plugins/embrane/common/utils.py
Normal file
65
neutron/plugins/embrane/common/utils.py
Normal file
@ -0,0 +1,65 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from heleosapi import info as h_info
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def set_db_item_state(context, neutron_item, new_state):
|
||||
with context.session.begin(subtransactions=True):
|
||||
if neutron_item["status"] != new_state:
|
||||
neutron_item["status"] = new_state
|
||||
context.session.merge(neutron_item)
|
||||
|
||||
|
||||
def retrieve_ip_allocation_info(l2_plugin, context, neutron_port):
|
||||
"""Retrieves ip allocation info for a specific port if any."""
|
||||
|
||||
try:
|
||||
subnet_id = neutron_port["fixed_ips"][0]["subnet_id"]
|
||||
except (KeyError, IndexError):
|
||||
LOG.info(_("No ip allocation set"))
|
||||
return
|
||||
subnet = l2_plugin._get_subnet(context, subnet_id)
|
||||
allocated_ip = neutron_port["fixed_ips"][0]["ip_address"]
|
||||
is_gw_port = neutron_port["device_owner"] == "network:router_gateway"
|
||||
gateway_ip = subnet["gateway_ip"]
|
||||
|
||||
ip_allocation_info = h_info.IpAllocationInfo(
|
||||
is_gw=is_gw_port,
|
||||
ip_version=subnet["ip_version"],
|
||||
prefix=subnet["cidr"].split("/")[1],
|
||||
ip_address=allocated_ip,
|
||||
port_id=neutron_port["id"],
|
||||
gateway_ip=gateway_ip)
|
||||
|
||||
return ip_allocation_info
|
||||
|
||||
|
||||
def retrieve_nat_info(context, fip, fixed_prefix, floating_prefix, router):
|
||||
nat_info = h_info.NatInfo(source_address=fip["floating_ip_address"],
|
||||
source_prefix=floating_prefix,
|
||||
destination_address=fip["fixed_ip_address"],
|
||||
destination_prefix=fixed_prefix,
|
||||
floating_ip_id=fip["id"],
|
||||
fixed_port_id=fip["port_id"])
|
||||
return nat_info
|
18
neutron/plugins/embrane/l2base/__init__.py
Normal file
18
neutron/plugins/embrane/l2base/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
18
neutron/plugins/embrane/l2base/fake/__init__.py
Normal file
18
neutron/plugins/embrane/l2base/fake/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
24
neutron/plugins/embrane/l2base/fake/fake_l2_plugin.py
Normal file
24
neutron/plugins/embrane/l2base/fake/fake_l2_plugin.py
Normal file
@ -0,0 +1,24 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from neutron.db import db_base_plugin_v2
|
||||
|
||||
|
||||
class FakeL2Plugin(db_base_plugin_v2.NeutronDbPluginV2):
|
||||
supported_extension_aliases = []
|
43
neutron/plugins/embrane/l2base/fake/fakeplugin_support.py
Normal file
43
neutron/plugins/embrane/l2base/fake/fakeplugin_support.py
Normal file
@ -0,0 +1,43 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from heleosapi import info as h_info
|
||||
|
||||
from neutron import manager
|
||||
from neutron.plugins.embrane.l2base import support_base as base
|
||||
|
||||
|
||||
class FakePluginSupport(base.SupportBase):
|
||||
|
||||
def __init__(self):
|
||||
super(FakePluginSupport, self).__init__()
|
||||
|
||||
def retrieve_utif_info(self, context, neutron_port):
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
network_id = neutron_port["network_id"]
|
||||
network = plugin._get_network(context, network_id)
|
||||
is_gw = neutron_port["device_owner"] == "network:router_gateway"
|
||||
result = h_info.UtifInfo(vlan=0,
|
||||
network_name=network["name"],
|
||||
network_id=network["id"],
|
||||
is_gw=is_gw,
|
||||
owner_tenant=network["tenant_id"],
|
||||
port_id=neutron_port["id"],
|
||||
mac_address=neutron_port["mac_address"])
|
||||
return result
|
18
neutron/plugins/embrane/l2base/openvswitch/__init__.py
Normal file
18
neutron/plugins/embrane/l2base/openvswitch/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
@ -0,0 +1,56 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from heleosapi import info as h_info
|
||||
|
||||
from neutron import manager
|
||||
from neutron.plugins.embrane.l2base import support_base as base
|
||||
from neutron.plugins.embrane.l2base import support_exceptions as exc
|
||||
from neutron.plugins.openvswitch import ovs_db_v2
|
||||
|
||||
|
||||
class OpenvswitchSupport(base.SupportBase):
|
||||
"""OpenVSwitch plugin support.
|
||||
|
||||
Obtains the informations needed to build the user security zones
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(OpenvswitchSupport, self).__init__()
|
||||
|
||||
def retrieve_utif_info(self, context, neutron_port):
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
session = context.session
|
||||
network_id = neutron_port["network_id"]
|
||||
network_binding = ovs_db_v2.get_network_binding(session, network_id)
|
||||
if not network_binding["segmentation_id"]:
|
||||
raise exc.UtifInfoError(
|
||||
err_msg=_("No segmentation_id found for the network, "
|
||||
"please be sure that tenant_network_type is vlan"))
|
||||
network = plugin._get_network(context, network_id)
|
||||
is_gw = neutron_port["device_owner"] == "network:router_gateway"
|
||||
result = h_info.UtifInfo(vlan=network_binding["segmentation_id"],
|
||||
network_name=network["name"],
|
||||
network_id=network["id"],
|
||||
is_gw=is_gw,
|
||||
owner_tenant=network["tenant_id"],
|
||||
port_id=neutron_port["id"],
|
||||
mac_address=neutron_port["mac_address"])
|
||||
return result
|
48
neutron/plugins/embrane/l2base/support_base.py
Normal file
48
neutron/plugins/embrane/l2base/support_base.py
Normal file
@ -0,0 +1,48 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class SupportBase(object):
|
||||
"""abstract support class.
|
||||
|
||||
Defines the methods a plugin support should implement to be used as
|
||||
the L2 base for Embrane plugin.
|
||||
|
||||
"""
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def retrieve_utif_info(self, context, neutron_port=None, network=None):
|
||||
"""Retrieve specific network info.
|
||||
|
||||
each plugin support, querying its own DB, can collect all the
|
||||
information needed by the ESM in order to create the
|
||||
user traffic security zone.
|
||||
|
||||
:param interface_info: the foo parameter
|
||||
:param context: neutron request context
|
||||
:returns: heleosapi.info.UtifInfo -- specific network info
|
||||
:raises: UtifInfoError
|
||||
"""
|
25
neutron/plugins/embrane/l2base/support_exceptions.py
Normal file
25
neutron/plugins/embrane/l2base/support_exceptions.py
Normal file
@ -0,0 +1,25 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from neutron.plugins.embrane.common import exceptions as embrane_exc
|
||||
|
||||
|
||||
class UtifInfoError(embrane_exc.EmbranePluginException):
|
||||
message = _("cannot retrieve utif info for the following reason: "
|
||||
"%(err_msg)s")
|
18
neutron/plugins/embrane/plugins/__init__.py
Normal file
18
neutron/plugins/embrane/plugins/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
34
neutron/plugins/embrane/plugins/embrane_fake_plugin.py
Normal file
34
neutron/plugins/embrane/plugins/embrane_fake_plugin.py
Normal file
@ -0,0 +1,34 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from neutron.db import extraroute_db
|
||||
from neutron.plugins.embrane import base_plugin as base
|
||||
from neutron.plugins.embrane.l2base.fake import fake_l2_plugin as l2
|
||||
from neutron.plugins.embrane.l2base.fake import fakeplugin_support as sup
|
||||
|
||||
|
||||
class EmbraneFakePlugin(base.EmbranePlugin, extraroute_db.ExtraRoute_db_mixin,
|
||||
l2.FakeL2Plugin):
|
||||
_plugin_support = sup.FakePluginSupport
|
||||
|
||||
def __init__(self):
|
||||
'''First run plugin specific initialization, then Embrane's.'''
|
||||
self.supported_extension_aliases += ["extraroute", "router"]
|
||||
l2.FakeL2Plugin.__init__(self)
|
||||
self._run_embrane_config()
|
37
neutron/plugins/embrane/plugins/embrane_ovs_plugin.py
Normal file
37
neutron/plugins/embrane/plugins/embrane_ovs_plugin.py
Normal file
@ -0,0 +1,37 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
from neutron.plugins.embrane import base_plugin as base
|
||||
from neutron.plugins.embrane.l2base.openvswitch import openvswitch_support
|
||||
from neutron.plugins.openvswitch import ovs_neutron_plugin as l2
|
||||
|
||||
|
||||
class EmbraneOvsPlugin(base.EmbranePlugin, l2.OVSNeutronPluginV2):
|
||||
'''EmbraneOvsPlugin.
|
||||
|
||||
This plugin uses OpenVSwitch specific L2 plugin for providing L2 networks
|
||||
and the base EmbranePlugin for L3.
|
||||
|
||||
'''
|
||||
_plugin_support = openvswitch_support.OpenvswitchSupport
|
||||
|
||||
def __init__(self):
|
||||
'''First run plugin specific initialization, then Embrane's.'''
|
||||
l2.OVSNeutronPluginV2.__init__(self)
|
||||
self._run_embrane_config()
|
18
neutron/tests/unit/embrane/__init__.py
Normal file
18
neutron/tests/unit/embrane/__init__.py
Normal file
@ -0,0 +1,18 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
37
neutron/tests/unit/embrane/test_embrane_defaults.py
Normal file
37
neutron/tests/unit/embrane/test_embrane_defaults.py
Normal file
@ -0,0 +1,37 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
import sys
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.plugins.embrane.common import config # noqa
|
||||
from neutron.tests import base
|
||||
|
||||
# Need to mock heleosapi.
|
||||
sys.modules["heleosapi"] = mock.Mock()
|
||||
|
||||
|
||||
class ConfigurationTest(base.BaseTestCase):
|
||||
|
||||
def test_defaults(self):
|
||||
self.assertEqual('admin', cfg.CONF.heleos.admin_username)
|
||||
self.assertEqual('default', cfg.CONF.heleos.resource_pool_id)
|
||||
self.assertTrue(cfg.CONF.heleos.async_requests)
|
46
neutron/tests/unit/embrane/test_embrane_l3_plugin.py
Normal file
46
neutron/tests/unit/embrane/test_embrane_l3_plugin.py
Normal file
@ -0,0 +1,46 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
import sys
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.db import api as db
|
||||
from neutron.plugins.embrane.common import config # noqa
|
||||
from neutron.tests.unit import test_extension_extraroute as extraroute_test
|
||||
from neutron.tests.unit import test_l3_plugin as router_test
|
||||
|
||||
PLUGIN_NAME = ('neutron.plugins.embrane.plugins.embrane_fake_plugin.'
|
||||
'EmbraneFakePlugin')
|
||||
sys.modules["heleosapi"] = mock.Mock()
|
||||
|
||||
|
||||
class TestEmbraneL3NatDBTestCase(router_test.L3NatDBTestCase):
|
||||
_plugin_name = PLUGIN_NAME
|
||||
|
||||
def setUp(self):
|
||||
cfg.CONF.set_override('admin_password', "admin123", 'heleos')
|
||||
self.addCleanup(cfg.CONF.reset)
|
||||
self.addCleanup(db.clear_db)
|
||||
super(TestEmbraneL3NatDBTestCase, self).setUp()
|
||||
|
||||
|
||||
class ExtraRouteDBTestCase(extraroute_test.ExtraRouteDBTestCase):
|
||||
_plugin_name = PLUGIN_NAME
|
81
neutron/tests/unit/embrane/test_embrane_neutron_plugin.py
Normal file
81
neutron/tests/unit/embrane/test_embrane_neutron_plugin.py
Normal file
@ -0,0 +1,81 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 Embrane, 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: Ivar Lazzaro, Embrane, Inc.
|
||||
|
||||
import sys
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
||||
from neutron.db import api as db
|
||||
from neutron.plugins.embrane.common import config # noqa
|
||||
from neutron.tests.unit import test_db_plugin as test_plugin
|
||||
|
||||
PLUGIN_NAME = ('neutron.plugins.embrane.plugins.embrane_fake_plugin.'
|
||||
'EmbraneFakePlugin')
|
||||
sys.modules["heleosapi"] = mock.Mock()
|
||||
|
||||
|
||||
class EmbranePluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
_plugin_name = PLUGIN_NAME
|
||||
|
||||
def setUp(self):
|
||||
cfg.CONF.set_override('admin_password', "admin123", 'heleos')
|
||||
self.addCleanup(cfg.CONF.reset)
|
||||
self.addCleanup(db.clear_db)
|
||||
super(EmbranePluginV2TestCase, self).setUp(self._plugin_name)
|
||||
|
||||
|
||||
class TestEmbraneBasicGet(test_plugin.TestBasicGet, EmbranePluginV2TestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestEmbraneV2HTTPResponse(test_plugin.TestV2HTTPResponse,
|
||||
EmbranePluginV2TestCase):
|
||||
pass
|
||||
|
||||
|
||||
class TestEmbranePortsV2(test_plugin.TestPortsV2, EmbranePluginV2TestCase):
|
||||
|
||||
def test_create_ports_bulk_emulated_plugin_failure(self):
|
||||
self.skip("Temporary skipping due to incompatibility with the"
|
||||
" plugin dynamic class type")
|
||||
|
||||
def test_recycle_expired_previously_run_within_context(self):
|
||||
self.skip("Temporary skipping due to incompatibility with the"
|
||||
" plugin dynamic class type")
|
||||
|
||||
def test_recycle_held_ip_address(self):
|
||||
self.skip("Temporary skipping due to incompatibility with the"
|
||||
" plugin dynamic class type")
|
||||
|
||||
|
||||
class TestEmbraneNetworksV2(test_plugin.TestNetworksV2,
|
||||
EmbranePluginV2TestCase):
|
||||
|
||||
def test_create_networks_bulk_emulated_plugin_failure(self):
|
||||
self.skip("Temporary skipping due to incompatibility with the"
|
||||
" plugin dynamic class type")
|
||||
|
||||
|
||||
class TestEmbraneSubnetsV2(test_plugin.TestSubnetsV2,
|
||||
EmbranePluginV2TestCase):
|
||||
|
||||
def test_create_subnets_bulk_emulated_plugin_failure(self):
|
||||
self.skip("Temporary skipping due to incompatibility with the"
|
||||
" plugin dynamic class type")
|
Loading…
Reference in New Issue
Block a user