5 changed files with 737 additions and 0 deletions
@ -0,0 +1,52 @@
|
||||
# Defines Configuration options for FSL SDN OS Mechanism Driver |
||||
# Cloud Resource Discovery (CRD) authorization credentials |
||||
[ml2_fslsdn] |
||||
#(StrOpt) User name for authentication to CRD. |
||||
# e.g.: user12 |
||||
# |
||||
# crd_user_name = |
||||
|
||||
#(StrOpt) Password for authentication to CRD. |
||||
# e.g.: secret |
||||
# |
||||
# crd_password = |
||||
|
||||
#(StrOpt) Tenant name for CRD service. |
||||
# e.g.: service |
||||
# |
||||
# crd_tenant_name = |
||||
|
||||
#(StrOpt) CRD auth URL. |
||||
# e.g.: http://127.0.0.1:5000/v2.0/ |
||||
# |
||||
# crd_auth_url = |
||||
|
||||
#(StrOpt) URL for connecting to CRD Service. |
||||
# e.g.: http://127.0.0.1:9797 |
||||
# |
||||
# crd_url= |
||||
|
||||
#(IntOpt) Timeout value for connecting to CRD service |
||||
# in seconds, e.g.: 30 |
||||
# |
||||
# crd_url_timeout= |
||||
|
||||
#(StrOpt) Region name for connecting to CRD in |
||||
# admin context, e.g.: RegionOne |
||||
# |
||||
# crd_region_name= |
||||
|
||||
#(BoolOpt)If set, ignore any SSL validation issues (boolean value) |
||||
# e.g.: False |
||||
# |
||||
# crd_api_insecure= |
||||
|
||||
#(StrOpt)Authorization strategy for connecting to CRD in admin |
||||
# context, e.g.: keystone |
||||
# |
||||
# crd_auth_strategy= |
||||
|
||||
#(StrOpt)Location of CA certificates file to use for CRD client |
||||
# requests. |
||||
# |
||||
# crd_ca_certificates_file= |
@ -0,0 +1,102 @@
|
||||
===================================================== |
||||
Freescale SDN Mechanism Driver for Neutron ML2 plugin |
||||
===================================================== |
||||
|
||||
Introduction |
||||
============ |
||||
|
||||
Freescale SDN (FSL-SDN) Mechanism Driver is an add-on support for ML2 plugin |
||||
for Neutron. |
||||
|
||||
It supports the Cloud Resource Discovery (CRD) service by updating |
||||
Network, Subnet and Port Create/Update/Delete data into the CRD database. |
||||
|
||||
CRD service manages network nodes, virtual network appliances and openflow |
||||
controller based network applications. |
||||
|
||||
Basic work flow |
||||
--------------- |
||||
|
||||
:: |
||||
|
||||
+---------------------------------+ |
||||
| | |
||||
| Neutron Server | |
||||
| (with ML2 plugin) | |
||||
| | |
||||
| +-------------------------------+ |
||||
| | Freescale SDN | |
||||
| | Mechanism Driver | |
||||
+-+--------+----------------------+ |
||||
| |
||||
| ReST API |
||||
| |
||||
+----------+-------------+ |
||||
| CRD server | |
||||
+------------------------+ |
||||
|
||||
|
||||
|
||||
How does Freescale SDN Mechanism Driver work? |
||||
=========================================== |
||||
|
||||
- Freescale Mechanism driver handles the following postcommit operations. |
||||
- Network create/update/delete |
||||
- Subnet create/update/delete |
||||
- Port create/delete |
||||
|
||||
Sequence diagram : create_network |
||||
--------------------------------- |
||||
|
||||
:: |
||||
|
||||
create_network |
||||
{ |
||||
neutron -> ML2_plugin |
||||
ML2_plugin -> FSL-SDN-MD |
||||
FSL-SDN-MD -> crd_service |
||||
FSL-SDN-MD <-- crd_service |
||||
ML2_plugin <-- FSL-SDN-MD |
||||
neutron <-- ML2_plugin |
||||
} |
||||
|
||||
- Supported network types by FSL OF Controller include vlan and vxlan. |
||||
|
||||
- Freescale SDN mechanism driver handles VM port binding within in the |
||||
mechanism driver (like ODL MD). |
||||
|
||||
- 'bind_port' function verifies the supported network types (vlan,vxlan) |
||||
and calls context.set_binding with binding details. |
||||
|
||||
- Flow management in OVS is handled by Freescale Openflow Controller. |
||||
|
||||
|
||||
How to use Freescale SDN Mechanism Driver? |
||||
========================================== |
||||
|
||||
Configuring ML2 Plugin |
||||
---------------------- |
||||
|
||||
In [ml2] section of /etc/neutron/plugins/ml2/ml2_conf.ini, |
||||
modify 'mechanism_drivers' attributes as: |
||||
|
||||
:: |
||||
|
||||
mechanism_drivers = fslsdn |
||||
|
||||
Configuring FSLSDN Mechanism Driver |
||||
----------------------------------- |
||||
|
||||
Update /etc/neutron/plugins/ml2/ml2_conf_fslsdn.ini, as below. |
||||
|
||||
:: |
||||
|
||||
[ml2_fslsdn] |
||||
crd_auth_strategy = keystone |
||||
crd_url = http://127.0.0.1:9797 |
||||
crd_auth_url = http://127.0.0.1:5000/v2.0/ |
||||
crd_tenant_name = service |
||||
crd_password = <-service-password-> |
||||
crd_user_name = <-service-username-> |
||||
|
||||
CRD service must be running in the controller. |
@ -0,0 +1,288 @@
|
||||
# Copyright (c) 2014 Freescale Semiconductor |
||||
# |
||||
# 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: Trinath Somanchi, Freescale, Inc |
||||
|
||||
|
||||
from neutronclient.v2_0 import client |
||||
from oslo.config import cfg |
||||
|
||||
from neutron.common import constants as n_const |
||||
from neutron.common import log |
||||
from neutron.extensions import portbindings |
||||
from neutron.openstack.common import log as logging |
||||
from neutron.plugins.common import constants |
||||
from neutron.plugins.ml2 import driver_api as api |
||||
|
||||
|
||||
LOG = logging.getLogger(__name__) |
||||
|
||||
# CRD service options required for FSL SDN OS Mech Driver |
||||
ml2_fslsdn_opts = [ |
||||
cfg.StrOpt('crd_user_name', default='crd', |
||||
help=_("CRD service Username")), |
||||
cfg.StrOpt('crd_password', default='password', |
||||
secret='True', |
||||
help=_("CRD Service Password")), |
||||
cfg.StrOpt('crd_tenant_name', default='service', |
||||
help=_("CRD Tenant Name")), |
||||
cfg.StrOpt('crd_auth_url', |
||||
default='http://127.0.0.1:5000/v2.0/', |
||||
help=_("CRD Auth URL")), |
||||
cfg.StrOpt('crd_url', |
||||
default='http://127.0.0.1:9797', |
||||
help=_("URL for connecting to CRD service")), |
||||
cfg.IntOpt('crd_url_timeout', |
||||
default=30, |
||||
help=_("Timeout value for connecting to " |
||||
"CRD service in seconds")), |
||||
cfg.StrOpt('crd_region_name', |
||||
default='RegionOne', |
||||
help=_("Region name for connecting to " |
||||
"CRD Service in admin context")), |
||||
cfg.BoolOpt('crd_api_insecure', |
||||
default=False, |
||||
help=_("If set, ignore any SSL validation issues")), |
||||
cfg.StrOpt('crd_auth_strategy', |
||||
default='keystone', |
||||
help=_("Auth strategy for connecting to " |
||||
"neutron in admin context")), |
||||
cfg.StrOpt('crd_ca_certificates_file', |
||||
help=_("Location of ca certificates file to use for " |
||||
"CRD client requests.")), |
||||
] |
||||
|
||||
# Register the configuration option for crd service |
||||
# required for FSL SDN OS Mechanism driver |
||||
cfg.CONF.register_opts(ml2_fslsdn_opts, "ml2_fslsdn") |
||||
|
||||
# shortcut |
||||
FSLCONF = cfg.CONF.ml2_fslsdn |
||||
|
||||
SERVICE_TYPE = 'crd' |
||||
|
||||
|
||||
class FslsdnMechanismDriver(api.MechanismDriver): |
||||
|
||||
"""Freescale SDN OS Mechanism Driver for ML2 Plugin.""" |
||||
|
||||
@log.log |
||||
def initialize(self): |
||||
"""Initialize the Mechanism driver.""" |
||||
|
||||
self.vif_type = portbindings.VIF_TYPE_OVS |
||||
self.vif_details = {portbindings.CAP_PORT_FILTER: True} |
||||
LOG.info(_("Initializing CRD client... ")) |
||||
crd_client_params = { |
||||
'username': FSLCONF.crd_user_name, |
||||
'tenant_name': FSLCONF.crd_tenant_name, |
||||
'region_name': FSLCONF.crd_region_name, |
||||
'password': FSLCONF.crd_password, |
||||
'auth_url': FSLCONF.crd_auth_url, |
||||
'auth_strategy': FSLCONF.crd_auth_strategy, |
||||
'endpoint_url': FSLCONF.crd_url, |
||||
'timeout': FSLCONF.crd_url_timeout, |
||||
'insecure': FSLCONF.crd_api_insecure, |
||||
'service_type': SERVICE_TYPE, |
||||
'ca_cert': FSLCONF.crd_ca_certificates_file, |
||||
} |
||||
self._crdclient = client.Client(**crd_client_params) |
||||
|
||||
# Network Management |
||||
@staticmethod |
||||
@log.log |
||||
def _prepare_crd_network(network, segments): |
||||
"""Helper function to create 'network' data.""" |
||||
|
||||
return {'network': |
||||
{'network_id': network['id'], |
||||
'tenant_id': network['tenant_id'], |
||||
'name': network['name'], |
||||
'status': network['status'], |
||||
'admin_state_up': network['admin_state_up'], |
||||
'segments': segments, |
||||
}} |
||||
|
||||
def create_network_postcommit(self, context): |
||||
"""Send create_network data to CRD service.""" |
||||
|
||||
network = context.current |
||||
segments = context.network_segments |
||||
body = self._prepare_crd_network(network, segments) |
||||
self._crdclient.create_network(body=body) |
||||
LOG.debug("create_network update sent to CRD Server: %s", body) |
||||
|
||||
def update_network_postcommit(self, context): |
||||
"""Send update_network data to CRD service.""" |
||||
|
||||
network = context.current |
||||
segments = context.network_segments |
||||
body = self._prepare_crd_network(network, segments) |
||||
self._crdclient.update_network(network['id'], body=body) |
||||
LOG.debug("update_network update sent to CRD Server: %s", body) |
||||
|
||||
def delete_network_postcommit(self, context): |
||||
"""Send delete_network data to CRD service.""" |
||||
|
||||
network = context.current |
||||
self._crdclient.delete_network(network['id']) |
||||
LOG.debug( |
||||
"delete_network update sent to CRD Server: %s", |
||||
network['id']) |
||||
|
||||
# Port Management |
||||
@staticmethod |
||||
def _prepare_crd_port(port): |
||||
"""Helper function to prepare 'port' data.""" |
||||
|
||||
crd_subnet_id = '' |
||||
crd_ipaddress = '' |
||||
crd_sec_grps = '' |
||||
# Since CRD accepts one Fixed IP, |
||||
# so handle only one fixed IP per port. |
||||
if len(port['fixed_ips']) > 1: |
||||
LOG.debug("More than one fixed IP exists - using first one.") |
||||
# check empty fixed_ips list, move on if one or more exists |
||||
if len(port['fixed_ips']) != 0: |
||||
crd_subnet_id = port['fixed_ips'][0]['subnet_id'] |
||||
crd_ipaddress = port['fixed_ips'][0]['ip_address'] |
||||
LOG.debug("Handling fixed IP {subnet_id:%(subnet)s, " |
||||
"ip_address:%(ip)s}", |
||||
{'subnet': crd_subnet_id, 'ip': crd_ipaddress}) |
||||
else: |
||||
LOG.debug("No fixed IPs found.") |
||||
if 'security_groups' in port: |
||||
crd_sec_grps = ','.join(port['security_groups']) |
||||
return {'port': |
||||
{'port_id': port['id'], |
||||
'tenant_id': port['tenant_id'], |
||||
'name': port['name'], |
||||
'network_id': port['network_id'], |
||||
'subnet_id': crd_subnet_id, |
||||
'mac_address': port['mac_address'], |
||||
'device_id': port['device_id'], |
||||
'ip_address': crd_ipaddress, |
||||
'admin_state_up': port['admin_state_up'], |
||||
'status': port['status'], |
||||
'device_owner': port['device_owner'], |
||||
'security_groups': crd_sec_grps, |
||||
}} |
||||
|
||||
def create_port_postcommit(self, context): |
||||
"""Send create_port data to CRD service.""" |
||||
|
||||
port = context.current |
||||
body = self._prepare_crd_port(port) |
||||
self._crdclient.create_port(body=body) |
||||
LOG.debug("create_port update sent to CRD Server: %s", body) |
||||
|
||||
def delete_port_postcommit(self, context): |
||||
"""Send delete_port data to CRD service.""" |
||||
|
||||
port = context.current |
||||
self._crdclient.delete_port(port['id']) |
||||
LOG.debug("delete_port update sent to CRD Server: %s", port['id']) |
||||
|
||||
# Subnet Management |
||||
@staticmethod |
||||
@log.log |
||||
def _prepare_crd_subnet(subnet): |
||||
"""Helper function to prepare 'subnet' data.""" |
||||
|
||||
crd_allocation_pools = '' |
||||
crd_dns_nameservers = '' |
||||
crd_host_routes = '' |
||||
# Handling Allocation IPs |
||||
if 'allocation_pools' in subnet: |
||||
a_pools = subnet['allocation_pools'] |
||||
crd_allocation_pools = ','.join(["%s-%s" % (p['start'], |
||||
p['end']) |
||||
for p in a_pools]) |
||||
# Handling Host Routes |
||||
if 'host_routes' in subnet: |
||||
crd_host_routes = ','.join(["%s-%s" % (r['destination'], |
||||
r['nexthop']) |
||||
for r in subnet['host_routes']]) |
||||
# Handling DNS Nameservers |
||||
if 'dns_nameservers' in subnet: |
||||
crd_dns_nameservers = ','.join(subnet['dns_nameservers']) |
||||
# return Subnet Data |
||||
return {'subnet': |
||||
{'subnet_id': subnet['id'], |
||||
'tenant_id': subnet['tenant_id'], |
||||
'name': subnet['name'], |
||||
'network_id': subnet['network_id'], |
||||
'ip_version': subnet['ip_version'], |
||||
'cidr': subnet['cidr'], |
||||
'gateway_ip': subnet['gateway_ip'], |
||||
'dns_nameservers': crd_dns_nameservers, |
||||
'allocation_pools': crd_allocation_pools, |
||||
'host_routes': crd_host_routes, |
||||
}} |
||||
|
||||
def create_subnet_postcommit(self, context): |
||||
"""Send create_subnet data to CRD service.""" |
||||
|
||||
subnet = context.current |
||||
body = self._prepare_crd_subnet(subnet) |
||||
self._crdclient.create_subnet(body=body) |
||||
LOG.debug("create_subnet update sent to CRD Server: %s", body) |
||||
|
||||
def update_subnet_postcommit(self, context): |
||||
"""Send update_subnet data to CRD service.""" |
||||
|
||||
subnet = context.current |
||||
body = self._prepare_crd_subnet(subnet) |
||||
self._crdclient.update_subnet(subnet['id'], body=body) |
||||
LOG.debug("update_subnet update sent to CRD Server: %s", body) |
||||
|
||||
def delete_subnet_postcommit(self, context): |
||||
"""Send delete_subnet data to CRD service.""" |
||||
|
||||
subnet = context.current |
||||
self._crdclient.delete_subnet(subnet['id']) |
||||
LOG.debug("delete_subnet update sent to CRD Server: %s", subnet['id']) |
||||
|
||||
def bind_port(self, context): |
||||
"""Set porting binding data for use with nova.""" |
||||
|
||||
LOG.debug("Attempting to bind port %(port)s on " |
||||
"network %(network)s", |
||||
{'port': context.current['id'], |
||||
'network': context.network.current['id']}) |
||||
# Prepared porting binding data |
||||
for segment in context.network.network_segments: |
||||
if self.check_segment(segment): |
||||
context.set_binding(segment[api.ID], |
||||
self.vif_type, |
||||
self.vif_details, |
||||
status=n_const.PORT_STATUS_ACTIVE) |
||||
LOG.debug("Bound using segment: %s", segment) |
||||
return |
||||
else: |
||||
LOG.debug("Refusing to bind port for segment ID %(id)s, " |
||||
"segment %(seg)s, phys net %(physnet)s, and " |
||||
"network type %(nettype)s", |
||||
{'id': segment[api.ID], |
||||
'seg': segment[api.SEGMENTATION_ID], |
||||
'physnet': segment[api.PHYSICAL_NETWORK], |
||||
'nettype': segment[api.NETWORK_TYPE]}) |
||||
|
||||
@log.log |
||||
def check_segment(self, segment): |
||||
"""Verify a segment is valid for the FSL SDN MechanismDriver.""" |
||||
|
||||
return segment[api.NETWORK_TYPE] in [constants.TYPE_VLAN, |
||||
constants.TYPE_VXLAN] |
@ -0,0 +1,293 @@
|
||||
# Copyright (c) 2014 Freescale, Inc. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||
# implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# @author: Trinath Somanchi, Freescale, Inc. |
||||
|
||||
import mock |
||||
from oslo.config import cfg |
||||
|
||||
from neutron.extensions import portbindings |
||||
from neutron.plugins.ml2.drivers import mechanism_fslsdn |
||||
from neutron.tests import base |
||||
from neutron.tests.unit import test_db_plugin |
||||
|
||||
|
||||
"""Unit testing for Freescale SDN mechanism driver.""" |
||||
|
||||
|
||||
def setup_driver_config(): |
||||
"""Mechanism Driver specific configuration.""" |
||||
|
||||
# Configure mechanism driver as 'fslsdn' |
||||
cfg.CONF.set_override('mechanism_drivers', ['fslsdn'], 'ml2') |
||||
# Configure FSL SDN Mechanism driver specific options |
||||
cfg.CONF.set_override('crd_user_name', 'crd', 'ml2_fslsdn') |
||||
cfg.CONF.set_override('crd_password', 'CRD_PASS', 'ml2_fslsdn') |
||||
cfg.CONF.set_override('crd_tenant_name', 'service', 'ml2_fslsdn') |
||||
cfg.CONF.set_override('crd_auth_url', |
||||
'http://127.0.0.1:5000/v2.0', 'ml2_fslsdn') |
||||
cfg.CONF.set_override('crd_url', |
||||
'http://127.0.0.1:9797', 'ml2_fslsdn') |
||||
cfg.CONF.set_override('crd_auth_strategy', 'keystone', 'ml2_fslsdn') |
||||
|
||||
|
||||
class TestFslSdnMechDriverV2(test_db_plugin.NeutronDbPluginV2TestCase): |
||||
|
||||
"""Testing mechanism driver with ML2 plugin.""" |
||||
|
||||
def setUp(self): |
||||
setup_driver_config() |
||||
|
||||
def mocked_fslsdn_init(self): |
||||
# Mock CRD client, since it requires CRD service running. |
||||
self._crdclieint = mock.Mock() |
||||
|
||||
with mock.patch.object(mechanism_fslsdn.FslsdnMechanismDriver, |
||||
'initialize', new=mocked_fslsdn_init): |
||||
super(TestFslSdnMechDriverV2, self).setUp() |
||||
|
||||
|
||||
class TestFslSdnMechDriverNetworksV2(test_db_plugin.TestNetworksV2, |
||||
TestFslSdnMechDriverV2): |
||||
pass |
||||
|
||||
|
||||
class TestFslSdnMechDriverPortsV2(test_db_plugin.TestPortsV2, |
||||
TestFslSdnMechDriverV2): |
||||
VIF_TYPE = portbindings.VIF_TYPE_OVS |
||||
CAP_PORT_FILTER = True |
||||
|
||||
|
||||
class TestFslSdnMechDriverSubnetsV2(test_db_plugin.TestSubnetsV2, |
||||
TestFslSdnMechDriverV2): |
||||
pass |
||||
|
||||
|
||||
class TestFslSdnMechanismDriver(base.BaseTestCase): |
||||
|
||||
"""Testing FSL SDN Mechanism driver.""" |
||||
|
||||
def setUp(self): |
||||
super(TestFslSdnMechanismDriver, self).setUp() |
||||
setup_driver_config() |
||||
self.driver = mechanism_fslsdn.FslsdnMechanismDriver() |
||||
self.driver.initialize() |
||||
self.client = self.driver._crdclient = mock.Mock() |
||||
|
||||
def test_create_update_delete_network_postcommit(self): |
||||
"""Testing create/update/delete network postcommit operations.""" |
||||
|
||||
tenant_id = 'test' |
||||
network_id = '123' |
||||
segmentation_id = 456 |
||||
expected_seg = [{'segmentation_id': segmentation_id}] |
||||
expected_crd_network = {'network': |
||||
{'network_id': network_id, |
||||
'tenant_id': tenant_id, |
||||
'name': 'FakeNetwork', |
||||
'status': 'ACTIVE', |
||||
'admin_state_up': True, |
||||
'segments': expected_seg}} |
||||
network_context = self._get_network_context(tenant_id, network_id, |
||||
segmentation_id) |
||||
network = network_context.current |
||||
segments = network_context.network_segments |
||||
net_id = network['id'] |
||||
req = self.driver._prepare_crd_network(network, segments) |
||||
# test crd network dict |
||||
self.assertEqual(expected_crd_network, req) |
||||
# test create_network. |
||||
self.driver.create_network_postcommit(network_context) |
||||
self.client.create_network.assert_called_once_with(body=req) |
||||
# test update_network. |
||||
self.driver.update_network_postcommit(network_context) |
||||
self.client.update_network.assert_called_once_with(net_id, body=req) |
||||
# test delete_network. |
||||
self.driver.delete_network_postcommit(network_context) |
||||
self.client.delete_network.assert_called_once_with(net_id) |
||||
|
||||
def test_create_update_delete_subnet_postcommit(self): |
||||
"""Testing create/update/delete subnet postcommit operations.""" |
||||
|
||||
tenant_id = 'test' |
||||
network_id = '123' |
||||
subnet_id = '122' |
||||
cidr = '192.0.0.0/8' |
||||
gateway_ip = '192.0.0.1' |
||||
expected_crd_subnet = {'subnet': |
||||
{'subnet_id': subnet_id, 'tenant_id': tenant_id, |
||||
'name': 'FakeSubnet', 'network_id': network_id, |
||||
'ip_version': 4, 'cidr': cidr, |
||||
'gateway_ip': gateway_ip, |
||||
'dns_nameservers': '', |
||||
'allocation_pools': '', |
||||
'host_routes': ''}} |
||||
subnet_context = self._get_subnet_context(tenant_id, network_id, |
||||
subnet_id, cidr, gateway_ip) |
||||
subnet = subnet_context.current |
||||
subnet_id = subnet['id'] |
||||
req = self.driver._prepare_crd_subnet(subnet) |
||||
# test crd subnet dict |
||||
self.assertEqual(expected_crd_subnet, req) |
||||
# test create_subnet. |
||||
self.driver.create_subnet_postcommit(subnet_context) |
||||
self.client.create_subnet.assert_called_once_with(body=req) |
||||
# test update_subnet. |
||||
self.driver.update_subnet_postcommit(subnet_context) |
||||
self.client.update_subnet.assert_called_once_with(subnet_id, body=req) |
||||
# test delete_subnet. |
||||
self.driver.delete_subnet_postcommit(subnet_context) |
||||
self.client.delete_subnet.assert_called_once_with(subnet_id) |
||||
|
||||
def test_create_delete_port_postcommit(self): |
||||
"""Testing create/delete port postcommit operations.""" |
||||
|
||||
tenant_id = 'test' |
||||
network_id = '123' |
||||
port_id = '453' |
||||
expected_crd_port = {'port': |
||||
{'port_id': port_id, 'tenant_id': tenant_id, |
||||
'name': 'FakePort', 'network_id': network_id, |
||||
'subnet_id': '', 'mac_address': 'aabb', |
||||
'device_id': '1234', 'ip_address': '', |
||||
'admin_state_up': True, 'status': 'ACTIVE', |
||||
'device_owner': 'compute', |
||||
'security_groups': ''}} |
||||
# Test with empty fixed IP |
||||
port_context = self._get_port_context(tenant_id, network_id, port_id) |
||||
port = port_context.current |
||||
req = self.driver._prepare_crd_port(port) |
||||
# Test crd port dict |
||||
self.assertEqual(expected_crd_port, req) |
||||
# test create_port. |
||||
self.driver.create_port_postcommit(port_context) |
||||
self.client.create_port.assert_called_once_with(body=req) |
||||
# Test delete_port |
||||
self.driver.delete_port_postcommit(port_context) |
||||
self.client.delete_port.assert_called_once_with(port['id']) |
||||
|
||||
def test_prepare_port_with_single_fixed_ip(self): |
||||
"""Test _prepare_crd_port with single fixed_ip.""" |
||||
|
||||
tenant_id = 'test' |
||||
network_id = '123' |
||||
port_id = '453' |
||||
fips = [{"subnet_id": "sub-1", "ip_address": "10.0.0.1"}] |
||||
expected_crd_port = {'port': |
||||
{'port_id': port_id, 'tenant_id': tenant_id, |
||||
'name': 'FakePort', 'network_id': network_id, |
||||
'subnet_id': '', 'mac_address': 'aabb', |
||||
'device_id': '1234', 'ip_address': '', |
||||
'admin_state_up': True, 'status': 'ACTIVE', |
||||
'device_owner': 'compute', |
||||
'security_groups': ''}} |
||||
port_context = self._get_port_context(tenant_id, network_id, port_id, |
||||
fips) |
||||
port = port_context.current |
||||
req = self.driver._prepare_crd_port(port) |
||||
expected_crd_port['port']['subnet_id'] = 'sub-1' |
||||
expected_crd_port['port']['ip_address'] = '10.0.0.1' |
||||
self.assertEqual(expected_crd_port, req) |
||||
|
||||
def test_prepare_port_with_multiple_fixed_ips(self): |
||||
"""Test _prepare_crd_port with multiple fixed_ips.""" |
||||
|
||||
tenant_id = 'test' |
||||
network_id = '123' |
||||
port_id = '453' |
||||
multiple_fips = [{"subnet_id": "sub-1", "ip_address": "10.0.0.1"}, |
||||
{"subnet_id": "sub-1", "ip_address": "10.0.0.4"}] |
||||
expected_crd_port = {'port': |
||||
{'port_id': port_id, 'tenant_id': tenant_id, |
||||
'name': 'FakePort', 'network_id': network_id, |
||||
'subnet_id': '', 'mac_address': 'aabb', |
||||
'device_id': '1234', 'ip_address': '', |
||||
'admin_state_up': True, 'status': 'ACTIVE', |
||||
'device_owner': 'compute', |
||||
'security_groups': ''}} |
||||
port_context = self._get_port_context(tenant_id, network_id, port_id, |
||||
multiple_fips) |
||||
port = port_context.current |
||||
req = self.driver._prepare_crd_port(port) |
||||
expected_crd_port['port']['subnet_id'] = 'sub-1' |
||||
expected_crd_port['port']['ip_address'] = '10.0.0.1' |
||||
self.assertEqual(expected_crd_port, req) |
||||
|
||||
def _get_subnet_context(self, tenant_id, net_id, subnet_id, cidr, |
||||
gateway_ip): |
||||
# sample data for testing purpose only. |
||||
subnet = {'tenant_id': tenant_id, |
||||
'network_id': net_id, |
||||
'id': subnet_id, |
||||
'cidr': cidr, |
||||
'name': 'FakeSubnet', |
||||
'ip_version': 4, |
||||
'gateway_ip': gateway_ip, |
||||
} |
||||
return FakeContext(subnet) |
||||
|
||||
def _get_port_context(self, tenant_id, net_id, port_id, |
||||
fixed_ips=[]): |
||||
# sample data for testing purpose only |
||||
port = {'device_id': '1234', |
||||
'name': 'FakePort', |
||||
'mac_address': 'aabb', |
||||
'device_owner': 'compute', |
||||
'tenant_id': tenant_id, |
||||
'id': port_id, |
||||
'fixed_ips': fixed_ips, |
||||
'admin_state_up': True, |
||||
'status': 'ACTIVE', |
||||
'network_id': net_id} |
||||
return FakeContext(port) |
||||
|
||||
def _get_network_context(self, tenant_id, net_id, seg_id): |
||||
# sample data for testing purpose only. |
||||
network = {'id': net_id, |
||||
'tenant_id': tenant_id, |
||||
'admin_state_up': True, |
||||
'status': 'ACTIVE', |
||||
'name': 'FakeNetwork', } |
||||
segments = [{'segmentation_id': seg_id}] |
||||
return FakeNetworkContext(network, segments) |
||||
|
||||
|
||||
class FakeNetworkContext(object): |
||||
|
||||
"""To generate network context for testing purposes only.""" |
||||
|
||||
def __init__(self, network, segments): |
||||
self._network = network |
||||
self._segments = segments |
||||
|
||||
@property |
||||
def current(self): |
||||
return self._network |
||||
|
||||
@property |
||||
def network_segments(self): |
||||
return self._segments |
||||
|
||||
|
||||
class FakeContext(object): |
||||
|
||||
"""To generate context for testing purposes only.""" |
||||
|
||||
def __init__(self, record): |
||||
self._record = record |
||||
|
||||
@property |
||||
def current(self): |
||||
return self._record |
Loading…
Reference in new issue