Replace chassis and remote_vtep with port binding
Remote VTEP and port bound to a chassis are mutually exclusive, plus, chassis ID was used for storing VTEP IP. This change proposes wrapping both fields into a single key on lport. Partial-Bug: #1690775 Change-Id: Iefd1fdc5a0a7ac62f812a8ca0e67c2acc3842350
This commit is contained in:
parent
bb09d75ff7
commit
dc80063919
|
@ -130,7 +130,7 @@ class ChassisSNATApp(df_base_app.DFlowApp, snat_mixin.SNATApp_mixin):
|
|||
if self.external_host_mac is not None:
|
||||
# install flows only when compute port is added
|
||||
if self.is_data_port(lport):
|
||||
self.chassis = lport.chassis
|
||||
self.chassis = lport.binding.chassis
|
||||
|
||||
self.install_lport_based_flows(lport)
|
||||
else:
|
||||
|
|
|
@ -72,7 +72,8 @@ class MigrationApp(df_base_app.DFlowApp):
|
|||
if not remote_chassis:
|
||||
# chassis has not been online yet.
|
||||
return
|
||||
lport.peer_vtep_address = remote_chassis.ip
|
||||
old_chassis = lport.binding.chassis
|
||||
lport.binding.chassis = dest_chassis
|
||||
|
||||
LOG.info("src process migration event port = %(port)s"
|
||||
"original_port = %(original_port)s"
|
||||
|
@ -82,7 +83,7 @@ class MigrationApp(df_base_app.DFlowApp):
|
|||
'chassis': dest_chassis})
|
||||
|
||||
# source node and other related nodes
|
||||
if original_lport and lport.chassis.id != chassis_name:
|
||||
if original_lport and old_chassis.id != chassis_name:
|
||||
original_lport.emit_remote_deleted()
|
||||
|
||||
lport.emit_remote_created()
|
||||
|
|
|
@ -148,7 +148,7 @@ class TunnelingApp(df_base_app.DFlowApp):
|
|||
self.ofproto.OFPFC_MODIFY)
|
||||
|
||||
def _add_egress_dispatch_flow(self, lport, segmentation_id):
|
||||
remote_ip = lport.peer_vtep_address
|
||||
remote_ip = lport.binding.ip
|
||||
ofport = self._get_lport_tunnel_ofport(lport)
|
||||
LOG.debug("set egress dispatch flow %(seg)s peer %(remote_ip)s",
|
||||
{'seg': segmentation_id,
|
||||
|
@ -227,7 +227,7 @@ class TunnelingApp(df_base_app.DFlowApp):
|
|||
lport = self.db_store.get_one(l2.LogicalPort(id=port_id))
|
||||
if not lport:
|
||||
continue
|
||||
peer_ip = lport.peer_vtep_address
|
||||
peer_ip = lport.binding.ip
|
||||
if peer_ip in peer_ip_list:
|
||||
continue
|
||||
peer_ip_list.add(peer_ip)
|
||||
|
|
|
@ -142,6 +142,17 @@ class DfLocalController(object):
|
|||
self.nb_api.subscriber.unregister_topic(topic)
|
||||
self._sync.remove_topic(topic)
|
||||
|
||||
def _get_ports_by_chassis(self, chassis):
|
||||
return self.db_store.get_all(
|
||||
l2.LogicalPort(
|
||||
binding=l2.PortBinding(
|
||||
type=l2.BINDING_CHASSIS,
|
||||
chassis=chassis.id,
|
||||
),
|
||||
),
|
||||
index=l2.LogicalPort.get_index('chassis_id'),
|
||||
)
|
||||
|
||||
def update_chassis(self, chassis):
|
||||
self.db_store.update(chassis)
|
||||
remote_chassis_name = chassis.id
|
||||
|
@ -149,20 +160,14 @@ class DfLocalController(object):
|
|||
return
|
||||
|
||||
# Notify about remote port update
|
||||
index = l2.LogicalPort.get_index('chassis_id')
|
||||
remote_ports = self.db_store.get_all(l2.LogicalPort(chassis=chassis),
|
||||
index=index)
|
||||
for port in remote_ports:
|
||||
for port in self._get_ports_by_chassis(chassis):
|
||||
self._logical_port_process(port)
|
||||
|
||||
def delete_chassis(self, chassis):
|
||||
LOG.info("Deleting remote ports in remote chassis %s", chassis.id)
|
||||
# Chassis is deleted, there is no reason to keep the remote port
|
||||
# in it.
|
||||
index = l2.LogicalPort.get_index('chassis_id')
|
||||
remote_ports = self.db_store.get_all(l2.LogicalPort(chassis=chassis),
|
||||
index=index)
|
||||
for port in remote_ports:
|
||||
for port in self._get_ports_by_chassis(chassis):
|
||||
self._delete_lport_instance(port)
|
||||
self.db_store.delete(chassis)
|
||||
|
||||
|
@ -182,8 +187,7 @@ class DfLocalController(object):
|
|||
lport.id)
|
||||
return
|
||||
|
||||
chassis = lport.chassis
|
||||
is_local = (chassis.id == self.chassis_name)
|
||||
is_local = lport.binding.is_local
|
||||
lport.is_local = is_local
|
||||
if is_local:
|
||||
if not lport.ofport:
|
||||
|
@ -191,9 +195,6 @@ class DfLocalController(object):
|
|||
if not lport.ofport:
|
||||
# Not attached to the switch. Maybe it's a subport?
|
||||
lport.ofport = self._get_trunk_subport_ofport(lport)
|
||||
else:
|
||||
lport.peer_vtep_address = (chassis.id if lport.remote_vtep else
|
||||
chassis.ip)
|
||||
|
||||
if not lport.ofport and lport.is_local:
|
||||
# The tunnel port online event will update the remote logical
|
||||
|
@ -224,9 +225,11 @@ class DfLocalController(object):
|
|||
pass
|
||||
|
||||
def update_lport(self, lport):
|
||||
chassis = lport.chassis
|
||||
if (not lport.remote_vtep and
|
||||
not self._is_physical_chassis(chassis)):
|
||||
if (
|
||||
lport.binding is None or
|
||||
(lport.binding.type == l2.BINDING_CHASSIS and
|
||||
not self._is_physical_chassis(lport.binding.chassis))
|
||||
):
|
||||
LOG.debug(("Port %s has not been bound or it is a vPort"),
|
||||
lport.id)
|
||||
return
|
||||
|
|
|
@ -200,7 +200,7 @@ class Topology(object):
|
|||
self.ovs_to_lport_mapping[ovs_port.id] = OvsLportMapping(
|
||||
lport_id=lport_id, topic=topic)
|
||||
|
||||
chassis = lport.chassis
|
||||
chassis = lport.binding.chassis
|
||||
# check if migration occurs
|
||||
if chassis.id != self.chassis_name:
|
||||
device_owner = lport.device_owner
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import copy
|
||||
|
||||
from jsonmodels import fields
|
||||
from jsonmodels import models
|
||||
from neutron_lib.api.definitions import portbindings
|
||||
from neutron_lib import constants as n_const
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
|
||||
import dragonflow.db.field_types as df_fields
|
||||
|
@ -83,6 +85,38 @@ class DhcpParams(models.Base):
|
|||
siaddr = df_fields.IpAddressField()
|
||||
|
||||
|
||||
BINDING_CHASSIS = 'chassis'
|
||||
BINDING_VTEP = 'vtep'
|
||||
|
||||
|
||||
class PortBinding(models.Base):
|
||||
type = df_fields.EnumField((BINDING_CHASSIS, BINDING_VTEP), required=True)
|
||||
chassis = df_fields.ReferenceField(core.Chassis)
|
||||
vtep_address = df_fields.IpAddressField()
|
||||
|
||||
@property
|
||||
def ip(self):
|
||||
if self.type == BINDING_CHASSIS:
|
||||
return self.chassis.ip
|
||||
elif self.type == BINDING_VTEP:
|
||||
return self.vtep_address
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def is_local(self):
|
||||
if self.type == BINDING_CHASSIS:
|
||||
return self.chassis.id == cfg.CONF.host
|
||||
return False
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return PortBinding(
|
||||
type=self.type,
|
||||
chassis=copy.deepcopy(self.chassis, memo),
|
||||
vtep_address=self.vtep_address,
|
||||
)
|
||||
|
||||
|
||||
# LogicalPort events
|
||||
EVENT_LOCAL_CREATED = 'local_created'
|
||||
EVENT_REMOTE_CREATED = 'remote_created'
|
||||
|
@ -98,7 +132,7 @@ EVENT_REMOTE_DELETED = 'remote_deleted'
|
|||
EVENT_LOCAL_UPDATED, EVENT_REMOTE_UPDATED,
|
||||
EVENT_LOCAL_DELETED, EVENT_REMOTE_DELETED,
|
||||
}, indexes={
|
||||
'chassis_id': 'chassis.id',
|
||||
'chassis_id': 'binding.chassis.id',
|
||||
'lswitch_id': 'lswitch.id',
|
||||
'ip,lswitch': ('ips', 'lswitch.id'),
|
||||
})
|
||||
|
@ -109,7 +143,7 @@ class LogicalPort(mf.ModelBase, mixins.Name, mixins.Version, mixins.Topic,
|
|||
subnets = df_fields.ReferenceListField(Subnet)
|
||||
macs = df_fields.ListOfField(df_fields.MacAddressField())
|
||||
enabled = fields.BoolField()
|
||||
chassis = df_fields.ReferenceField(core.Chassis)
|
||||
binding = fields.EmbeddedField(PortBinding)
|
||||
lswitch = df_fields.ReferenceField(LogicalSwitch)
|
||||
security_groups = df_fields.ReferenceListField(secgroups.SecurityGroup)
|
||||
allowed_address_pairs = fields.ListField(AddressPair)
|
||||
|
@ -117,16 +151,13 @@ class LogicalPort(mf.ModelBase, mixins.Name, mixins.Version, mixins.Topic,
|
|||
device_owner = fields.StringField()
|
||||
device_id = fields.StringField()
|
||||
qos_policy = df_fields.ReferenceField(qos.QosPolicy)
|
||||
remote_vtep = fields.BoolField()
|
||||
dhcp_params = fields.EmbeddedField(DhcpParams)
|
||||
binding_vnic_type = df_fields.EnumField(portbindings.VNIC_TYPES)
|
||||
|
||||
def __init__(self, ofport=None, is_local=None,
|
||||
peer_vtep_address=None, **kwargs):
|
||||
def __init__(self, ofport=None, is_local=None, **kwargs):
|
||||
super(LogicalPort, self).__init__(**kwargs)
|
||||
self.ofport = ofport
|
||||
self.is_local = is_local
|
||||
self.peer_vtep_address = peer_vtep_address
|
||||
|
||||
@property
|
||||
def ip(self):
|
||||
|
|
|
@ -88,23 +88,40 @@ def _build_dhcp_params(port):
|
|||
return ret
|
||||
|
||||
|
||||
def _build_port_binding(port):
|
||||
profile = port.get(portbindings.PROFILE)
|
||||
if profile:
|
||||
port_key = profile.get(df_const.DF_BINDING_PROFILE_PORT_KEY)
|
||||
if port_key == df_const.DF_REMOTE_PORT_TYPE:
|
||||
return l2.PortBinding(
|
||||
type=l2.BINDING_VTEP,
|
||||
vtep_address=profile.get(df_const.DF_BINDING_PROFILE_HOST_IP)
|
||||
)
|
||||
|
||||
chassis = port.get(portbindings.HOST_ID)
|
||||
if chassis:
|
||||
return l2.PortBinding(type=l2.BINDING_CHASSIS, chassis=chassis)
|
||||
|
||||
|
||||
def logical_port_from_neutron_port(port):
|
||||
return l2.LogicalPort(
|
||||
id=port['id'],
|
||||
lswitch=port['network_id'],
|
||||
topic=port['tenant_id'],
|
||||
macs=[port['mac_address']],
|
||||
ips=[ip['ip_address'] for ip in port.get('fixed_ips', [])],
|
||||
subnets=[ip['subnet_id'] for ip in port.get('fixed_ips', [])],
|
||||
name=port.get('name', df_const.DF_PORT_DEFAULT_NAME),
|
||||
enabled=port.get('admin_state_up', False),
|
||||
version=port['revision_number'],
|
||||
device_owner=port.get('device_owner'),
|
||||
device_id=port.get('device_id'),
|
||||
security_groups=port.get('security_groups', []),
|
||||
port_security_enabled=port.get(psec.PORTSECURITY, False),
|
||||
allowed_address_pairs=_validate_ip_prefix_allowed_address_pairs(
|
||||
port.get(addr_pair.ADDRESS_PAIRS, [])),
|
||||
binding_vnic_type=port.get(portbindings.VNIC_TYPE),
|
||||
qos_policy=port.get('qos_policy_id'),
|
||||
dhcp_params=_build_dhcp_params(port))
|
||||
id=port['id'],
|
||||
lswitch=port['network_id'],
|
||||
topic=port['tenant_id'],
|
||||
macs=[port['mac_address']],
|
||||
ips=[ip['ip_address'] for ip in port.get('fixed_ips', [])],
|
||||
subnets=[ip['subnet_id'] for ip in port.get('fixed_ips', [])],
|
||||
name=port.get('name', df_const.DF_PORT_DEFAULT_NAME),
|
||||
enabled=port.get('admin_state_up', False),
|
||||
version=port['revision_number'],
|
||||
device_owner=port.get('device_owner'),
|
||||
device_id=port.get('device_id'),
|
||||
security_groups=port.get('security_groups', []),
|
||||
port_security_enabled=port.get(psec.PORTSECURITY, False),
|
||||
allowed_address_pairs=_validate_ip_prefix_allowed_address_pairs(
|
||||
port.get(addr_pair.ADDRESS_PAIRS, [])),
|
||||
binding_vnic_type=port.get(portbindings.VNIC_TYPE),
|
||||
qos_policy=port.get('qos_policy_id'),
|
||||
dhcp_params=_build_dhcp_params(port),
|
||||
binding=_build_port_binding(port),
|
||||
)
|
||||
|
|
|
@ -450,32 +450,11 @@ class DFMechDriver(api.MechanismDriver):
|
|||
|
||||
LOG.info("DFMechDriver: delete subnet %s", subnet_id)
|
||||
|
||||
def _get_chassis_and_remote_vtep(self, port):
|
||||
# Router GW ports are not needed by dragonflow controller and
|
||||
# they currently cause error as they couldn't be mapped to
|
||||
# a valid ofport (or location)
|
||||
if port.get('device_owner') == n_const.DEVICE_OWNER_ROUTER_GW:
|
||||
chassis = None
|
||||
else:
|
||||
chassis = port.get('binding:host_id') or None
|
||||
|
||||
binding_profile = port.get('binding:profile')
|
||||
remote_vtep = False
|
||||
if binding_profile and binding_profile.get(
|
||||
df_const.DF_BINDING_PROFILE_PORT_KEY) ==\
|
||||
df_const.DF_REMOTE_PORT_TYPE:
|
||||
chassis = binding_profile.get(df_const.DF_BINDING_PROFILE_HOST_IP)
|
||||
remote_vtep = True
|
||||
return chassis, remote_vtep
|
||||
|
||||
@lock_db.wrap_db_lock(lock_db.RESOURCE_ML2_NETWORK_OR_PORT)
|
||||
def create_port_postcommit(self, context):
|
||||
port = context.current
|
||||
chassis, remote_vtep = self._get_chassis_and_remote_vtep(port)
|
||||
|
||||
lport = neutron_l2.logical_port_from_neutron_port(port)
|
||||
lport.chassis = chassis
|
||||
lport.remote_vtep = remote_vtep
|
||||
self.nb_api.create(lport)
|
||||
|
||||
LOG.info("DFMechDriver: create port %s", port['id'])
|
||||
|
@ -528,11 +507,7 @@ class DFMechDriver(api.MechanismDriver):
|
|||
updated_port)
|
||||
return None
|
||||
|
||||
chassis, remote_vtep = self._get_chassis_and_remote_vtep(updated_port)
|
||||
|
||||
lport = neutron_l2.logical_port_from_neutron_port(updated_port)
|
||||
lport.chassis = chassis
|
||||
lport.remote_vtep = remote_vtep
|
||||
self.nb_api.update(lport)
|
||||
|
||||
LOG.info("DFMechDriver: update port %s", updated_port['id'])
|
||||
|
|
|
@ -120,13 +120,16 @@ class DFBgpPlugin(service_base.ServicePluginBase,
|
|||
"""Get the accessible external ip of chassis where lport resides in"""
|
||||
|
||||
lport = self.nb_api.get(l2.LogicalPort(id=lport_id, topic=topic))
|
||||
binding_host = lport.chassis
|
||||
if not binding_host:
|
||||
binding = lport.binding
|
||||
if not binding:
|
||||
LOG.warning(
|
||||
'Logical port %s has not been bound to any host yet', lport_id)
|
||||
return
|
||||
|
||||
return self._get_external_ip_by_host(binding_host.id)
|
||||
if binding.type == l2.BINDING_VTEP:
|
||||
return binding.vtep_address
|
||||
elif binding.type == l2.BINDING_CHASSIS:
|
||||
return self._get_external_ip_by_host(binding.chassis.id)
|
||||
|
||||
def _get_external_ip_by_host(self, host):
|
||||
chassis = self.nb_api.get(core.Chassis(id=host))
|
||||
|
|
|
@ -104,7 +104,7 @@ class DragonflowDriver(base.DriverBase, mixins.LazyNbApiMixin):
|
|||
)
|
||||
self.nb_api.create(model)
|
||||
self.nb_api.update(l2.LogicalPort(id=subport.port_id,
|
||||
chassis=df_parent.chassis))
|
||||
binding=df_parent.binding))
|
||||
|
||||
def _delete_subports_handler(self, *args, **kwargs):
|
||||
"""Handle the event that subports were deleted"""
|
||||
|
@ -134,4 +134,4 @@ class DragonflowDriver(base.DriverBase, mixins.LazyNbApiMixin):
|
|||
)
|
||||
self.nb_api.delete(model)
|
||||
self.nb_api.update(l2.LogicalPort(id=subport.port_id,
|
||||
chassis=None))
|
||||
binding=None))
|
||||
|
|
|
@ -245,11 +245,19 @@ def with_nb_objects(*objs):
|
|||
res = [o for o in res if o.topic == topic]
|
||||
return res
|
||||
|
||||
def _get(obj):
|
||||
objs = _get_all(type(obj))
|
||||
for o in objs:
|
||||
if obj.id == o.id:
|
||||
return o
|
||||
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(obj, *args, **kwargs):
|
||||
with mock.patch.object(
|
||||
obj.nb_api, 'get_all', side_effect=_get_all
|
||||
), mock.patch.object(
|
||||
obj.nb_api, 'get', side_effect=_get,
|
||||
):
|
||||
return func(obj, *args, **kwargs)
|
||||
return wrapper
|
||||
|
|
|
@ -33,11 +33,15 @@ from dragonflow.db.models import secgroups
|
|||
from dragonflow.tests import base as tests_base
|
||||
|
||||
|
||||
_DEFAULT = object()
|
||||
|
||||
|
||||
class DFAppTestBase(tests_base.BaseTestCase):
|
||||
apps_list = []
|
||||
|
||||
def setUp(self, enable_selective_topo_dist=False):
|
||||
cfg.CONF.set_override('apps_list', self.apps_list, group='df')
|
||||
cfg.CONF.set_override('host', fake_chassis1.id)
|
||||
super(DFAppTestBase, self).setUp()
|
||||
mock.patch('ryu.base.app_manager.AppManager.get_instance').start()
|
||||
mock.patch('dragonflow.db.api_nb.NbApi.get_instance').start()
|
||||
|
@ -52,8 +56,8 @@ class DFAppTestBase(tests_base.BaseTestCase):
|
|||
db_store._instance = None
|
||||
|
||||
self.nb_api = api_nb.NbApi.get_instance(False)
|
||||
self.controller = df_local_controller.DfLocalController('fake_host',
|
||||
self.nb_api)
|
||||
self.controller = df_local_controller.DfLocalController(
|
||||
fake_chassis1.id, self.nb_api)
|
||||
self.vswitch_api = self.controller.vswitch_api = mock.MagicMock()
|
||||
kwargs = dict(
|
||||
nb_api=self.controller.nb_api,
|
||||
|
@ -141,6 +145,27 @@ fake_external_switch1 = l2.LogicalSwitch(
|
|||
id='fake_external_switch1')
|
||||
|
||||
|
||||
fake_chassis1 = core.Chassis(
|
||||
id='fakehost',
|
||||
ip='172.24.4.50',
|
||||
tunnel_types=('vxlan',),
|
||||
)
|
||||
|
||||
|
||||
fake_chassis2 = core.Chassis(
|
||||
id='fake_host2',
|
||||
ip='172.24.4.51',
|
||||
tunnel_types=('vxlan',),
|
||||
)
|
||||
|
||||
|
||||
def chassis_binding(chassis):
|
||||
return l2.PortBinding(
|
||||
type=l2.BINDING_CHASSIS,
|
||||
chassis=chassis,
|
||||
)
|
||||
|
||||
|
||||
def make_fake_port(id=None,
|
||||
subnets=None,
|
||||
is_local=None,
|
||||
|
@ -151,16 +176,20 @@ def make_fake_port(id=None,
|
|||
enabled=True,
|
||||
topic='fake_tenant1',
|
||||
device_owner='compute:None',
|
||||
chassis='fake_host',
|
||||
binding=_DEFAULT,
|
||||
version=2,
|
||||
unique_key=2,
|
||||
port_security_enabled=True,
|
||||
allowed_address_pairs=None,
|
||||
binding_vnic_type='normal',
|
||||
security_groups=['fake_security_group_id1'],
|
||||
device_id='fake_device_id',
|
||||
ofport=1,
|
||||
dhcp_params=None):
|
||||
|
||||
if binding == _DEFAULT:
|
||||
binding = chassis_binding(fake_chassis1.id)
|
||||
|
||||
fake_port = l2.LogicalPort(
|
||||
id="%s_%s" % (name, ofport) if not id else id,
|
||||
topic=topic,
|
||||
|
@ -170,10 +199,10 @@ def make_fake_port(id=None,
|
|||
ips=ips,
|
||||
subnets=subnets,
|
||||
macs=macs,
|
||||
chassis=chassis,
|
||||
binding=binding,
|
||||
lswitch=lswitch,
|
||||
security_groups=security_groups,
|
||||
allowed_address_pairs=[],
|
||||
allowed_address_pairs=allowed_address_pairs or [],
|
||||
port_security_enabled=port_security_enabled,
|
||||
device_owner=device_owner,
|
||||
device_id=device_id,
|
||||
|
@ -250,26 +279,12 @@ fake_remote_port1 = make_fake_remote_port(
|
|||
macs=['fa:16:3e:8c:2e:af'],
|
||||
name='fake_remote_port',
|
||||
ips=['10.0.0.8'],
|
||||
chassis='fake_host2',
|
||||
binding=chassis_binding('fake_host2'),
|
||||
unique_key=5,
|
||||
ofport=1,
|
||||
subnets=['fake_subnet1'])
|
||||
|
||||
|
||||
fake_chassis1 = core.Chassis(
|
||||
id='fake_host',
|
||||
ip='172.24.4.50',
|
||||
tunnel_types=('vxlan',),
|
||||
)
|
||||
|
||||
|
||||
fake_chassis2 = core.Chassis(
|
||||
id='fake_host2',
|
||||
ip='172.24.4.51',
|
||||
tunnel_types=('vxlan',),
|
||||
)
|
||||
|
||||
|
||||
fake_floatingip1 = l3.FloatingIp(
|
||||
id='fake_floatingip_id1',
|
||||
topic='fake_tenant1',
|
||||
|
|
|
@ -20,6 +20,7 @@ from dragonflow.db import model_framework
|
|||
from dragonflow.db import model_proxy
|
||||
from dragonflow.db.models import core
|
||||
from dragonflow.db.models import mixins
|
||||
from dragonflow.tests.common import utils
|
||||
from dragonflow.tests.unit import test_app_base
|
||||
|
||||
|
||||
|
@ -63,6 +64,7 @@ class DfLocalControllerTestCase(test_app_base.DFAppTestBase):
|
|||
mock_delete_lport.assert_called_once_with(lport)
|
||||
mock_db_store_delete.assert_called_once_with(chassis)
|
||||
|
||||
@utils.with_nb_objects(test_app_base.fake_chassis1)
|
||||
def test_register_chassis(self):
|
||||
cfg.CONF.set_override('external_host_ip',
|
||||
'172.24.4.100',
|
||||
|
|
|
@ -398,9 +398,9 @@ class TestDFMechDriver(DFMechanismDriverTestCase):
|
|||
self.nb_api.create.assert_called_once()
|
||||
lport = self.nb_api.create.call_args_list[0][0][0]
|
||||
self.assertIsInstance(lport, l2.LogicalPort)
|
||||
self.assertTrue(lport.remote_vtep)
|
||||
self.assertEqual(l2.BINDING_VTEP, lport.binding.type)
|
||||
# lport.chassis is a proxy, and we don't have a real database
|
||||
self.assertEqual("20.0.0.2", lport.chassis.id)
|
||||
self.assertEqual("20.0.0.2", str(lport.binding.ip))
|
||||
|
||||
self.nb_api.update.reset_mock()
|
||||
profile['host_ip'] = "20.0.0.20"
|
||||
|
@ -410,8 +410,8 @@ class TestDFMechDriver(DFMechanismDriverTestCase):
|
|||
self.nb_api.update.assert_called_once()
|
||||
lport = self.nb_api.update.call_args_list[0][0][0]
|
||||
self.assertIsInstance(lport, l2.LogicalPort)
|
||||
self.assertTrue(lport.remote_vtep)
|
||||
self.assertEqual("20.0.0.20", lport.chassis.id)
|
||||
self.assertEqual(l2.BINDING_VTEP, lport.binding.type)
|
||||
self.assertEqual("20.0.0.20", str(lport.binding.ip))
|
||||
|
||||
def test_delete_port(self):
|
||||
with self.port() as p:
|
||||
|
|
|
@ -54,7 +54,7 @@ class TestSGApp(test_app_base.DFAppTestBase):
|
|||
return n_const.IPv4
|
||||
|
||||
def _get_another_local_lport(self):
|
||||
fake_local_port = l2.LogicalPort(
|
||||
fake_local_port = test_app_base.make_fake_local_port(
|
||||
id='fake_port2',
|
||||
topic='fake_tenant1',
|
||||
name='',
|
||||
|
@ -64,7 +64,6 @@ class TestSGApp(test_app_base.DFAppTestBase):
|
|||
netaddr.IPAddress('2222:2222::2')],
|
||||
subnets=['fake_subnet1'],
|
||||
macs=[netaddr.EUI('fa:16:3e:8c:2e:12')],
|
||||
chassis='fake_host',
|
||||
lswitch='fake_switch1',
|
||||
security_groups=['fake_security_group_id1'],
|
||||
allowed_address_pairs=[],
|
||||
|
@ -76,8 +75,6 @@ class TestSGApp(test_app_base.DFAppTestBase):
|
|||
# 'binding_profile': {},
|
||||
# 'binding_vnic_type': 'normal',
|
||||
)
|
||||
fake_local_port.is_local = True
|
||||
fake_local_port.ofport = 20
|
||||
return fake_local_port
|
||||
|
||||
def _get_another_security_group(self, is_ipv6=False):
|
||||
|
|
|
@ -19,6 +19,7 @@ import mock
|
|||
from oslo_config import cfg
|
||||
|
||||
from dragonflow.controller import topology
|
||||
from dragonflow.tests.common import utils
|
||||
from dragonflow.tests.unit import test_app_base
|
||||
|
||||
|
||||
|
@ -64,15 +65,12 @@ class TestTopology(test_app_base.DFAppTestBase):
|
|||
test_app_base.fake_ovs_port1)
|
||||
self.controller._register_models()
|
||||
|
||||
@utils.with_nb_objects(
|
||||
test_app_base.fake_chassis1,
|
||||
test_app_base.fake_local_port1,
|
||||
test_app_base.fake_logic_switch1,
|
||||
)
|
||||
def test_vm_port_online_offline(self):
|
||||
self.nb_api.get_all.side_effect = nb_api_get_all_func(
|
||||
test_app_base.fake_logic_switch1,
|
||||
test_app_base.fake_local_port1,
|
||||
test_app_base.fake_chassis1,
|
||||
)
|
||||
self.nb_api.get.return_value = (
|
||||
test_app_base.fake_local_port1)
|
||||
|
||||
original_update = self.controller.update
|
||||
self.controller.update = mock.Mock()
|
||||
self.controller.update.side_effect = original_update
|
||||
|
@ -116,25 +114,22 @@ class TestTopology(test_app_base.DFAppTestBase):
|
|||
def test_vm_online_after_topology_pulled(self):
|
||||
self.nb_api.get_all.side_effect = nb_api_get_all_func(
|
||||
test_app_base.fake_logic_switch1,
|
||||
test_app_base.fake_local_port1)
|
||||
|
||||
def _get_logical_port(lport):
|
||||
lport_id = lport.id
|
||||
if lport_id == test_app_base.fake_local_port1.id:
|
||||
return test_app_base.fake_local_port1
|
||||
if lport_id == test_app_base.fake_local_port2.id:
|
||||
return test_app_base.fake_local_port2
|
||||
|
||||
self.nb_api.get.side_effect = _get_logical_port
|
||||
|
||||
test_app_base.fake_local_port1,
|
||||
test_app_base.fake_chassis1,
|
||||
)
|
||||
self.nb_api.get.return_value = test_app_base.fake_local_port1
|
||||
# Pull topology by first ovs port online
|
||||
self.topology.ovs_port_updated(test_app_base.fake_ovs_port1)
|
||||
|
||||
# Another port online
|
||||
self.nb_api.get_all.side_effect = nb_api_get_all_func(
|
||||
test_app_base.fake_logic_switch1,
|
||||
test_app_base.fake_local_port1,
|
||||
test_app_base.fake_local_port2)
|
||||
test_app_base.fake_local_port2,
|
||||
test_app_base.fake_chassis1,
|
||||
)
|
||||
self.controller.update = mock.Mock()
|
||||
self.nb_api.get.return_value = test_app_base.fake_local_port2
|
||||
self.topology.ovs_port_updated(test_app_base.fake_ovs_port2)
|
||||
self.controller.update.assert_called_once_with(
|
||||
test_app_base.fake_local_port2)
|
||||
|
@ -171,7 +166,6 @@ class TestTopology(test_app_base.DFAppTestBase):
|
|||
mock.call(test_app_base.fake_local_port2)]
|
||||
self.controller.update.assert_has_calls(
|
||||
calls, any_order=True)
|
||||
print(self.controller.update.call_args_list)
|
||||
self.assertEqual(4, self.controller.update.call_count)
|
||||
self.nb_api.subscriber.register_topic.assert_called_once()
|
||||
|
||||
|
|
|
@ -71,9 +71,9 @@ class TestTunnelingApp(test_app_base.DFAppTestBase):
|
|||
def test_multicast_flow_for_remote_port(self):
|
||||
fake_remote_gre_port1 = make_fake_remote_port(
|
||||
lswitch='fake_gre_switch1',
|
||||
chassis='fake_host2',
|
||||
binding=test_app_base.chassis_binding('fake_host2'),
|
||||
name='fake_remote_gre_port1')
|
||||
remote_ip = fake_remote_gre_port1.peer_vtep_address
|
||||
remote_ip = fake_remote_gre_port1.binding.ip
|
||||
ofport = fake_remote_gre_port1.ofport
|
||||
match = self.app._make_bum_match(metadata=21)
|
||||
actions = [
|
||||
|
@ -98,7 +98,7 @@ class TestTunnelingApp(test_app_base.DFAppTestBase):
|
|||
|
||||
fake_remote_gre_port2 = make_fake_remote_port(
|
||||
lswitch='fake_gre_switch1',
|
||||
chassis='fake_host2',
|
||||
binding=test_app_base.chassis_binding('fake_host2'),
|
||||
name='fake_remote_gre_port2')
|
||||
self.controller.update(fake_remote_gre_port2)
|
||||
self.app.parser.OFPInstructionActions.assert_called_with(
|
||||
|
|
Loading…
Reference in New Issue