port_fault_status and switch_fault_status

port_fault_status and switch_fault_status implementation.
reflect the same status in neutron db from ovsdb.
raises appropriate error message while creating l2gateway connection
if switch_fault_status and port_fault_status is not UP.

Change-Id: Icc77392afeb62bd2b0b0b816a63f8f02b442b0d8
stable/ocata
vikas 2015-03-25 03:57:26 -07:00
parent c43e6f293b
commit 91214d2bc7
12 changed files with 178 additions and 22 deletions

View File

@ -73,7 +73,8 @@ def add_physical_switch(context, record_dict):
uuid=record_dict['uuid'],
name=record_dict['name'],
tunnel_ip=record_dict['tunnel_ip'],
ovsdb_identifier=record_dict['ovsdb_identifier'])
ovsdb_identifier=record_dict['ovsdb_identifier'],
switch_fault_status=record_dict['switch_fault_status'])
session.add(physical_switch)
@ -117,10 +118,29 @@ def add_physical_port(context, record_dict):
uuid=record_dict['uuid'],
name=record_dict['name'],
physical_switch_id=record_dict['physical_switch_id'],
ovsdb_identifier=record_dict['ovsdb_identifier'])
ovsdb_identifier=record_dict['ovsdb_identifier'],
port_fault_status=record_dict['port_fault_status'])
session.add(physical_port)
def update_physical_ports_status(context, record_dict):
"""Update physical port fault status."""
with context.session.begin(subtransactions=True):
(context.session.query(models.PhysicalPorts).
filter(models.PhysicalPorts.uuid == record_dict['uuid']).
update({'port_fault_status': record_dict['port_fault_status']},
synchronize_session=False))
def update_physical_switch_status(context, record_dict):
"""Update physical switch fault status."""
with context.session.begin(subtransactions=True):
(context.session.query(models.PhysicalSwitches).
filter(models.PhysicalSwitches.uuid == record_dict['uuid']).
update({'switch_fault_status': record_dict['switch_fault_status']},
synchronize_session=False))
def delete_physical_port(context, record_dict):
"""Delete physical port that matches the supplied uuid."""
session = context.session

View File

@ -35,6 +35,7 @@ class PhysicalSwitches(model_base.BASEV2):
tunnel_ip = sa.Column(sa.String(64), nullable=False)
ovsdb_identifier = sa.Column(sa.String(64), nullable=False,
primary_key=True)
switch_fault_status = sa.Column(sa.String(length=16), nullable=True)
__table_args__ = (sa.UniqueConstraint(uuid,
ovsdb_identifier),)
@ -46,6 +47,7 @@ class PhysicalPorts(model_base.BASEV2):
physical_switch_id = sa.Column(sa.String(36), nullable=False)
ovsdb_identifier = sa.Column(sa.String(64), nullable=False,
primary_key=True)
port_fault_status = sa.Column(sa.String(length=16), nullable=True)
__table_args__ = (sa.UniqueConstraint(uuid,
ovsdb_identifier),)

View File

@ -44,6 +44,8 @@ def upgrade():
nullable=True),
sa.Column('ovsdb_identifier', sa.String(length=64),
nullable=False),
sa.Column('switch_fault_status', sa.String(length=16),
nullable=True),
sa.PrimaryKeyConstraint('uuid', 'ovsdb_identifier'))
op.create_table('physical_ports',
@ -53,6 +55,8 @@ def upgrade():
nullable=True),
sa.Column('ovsdb_identifier', sa.String(length=64),
nullable=False),
sa.Column('port_fault_status', sa.String(length=16),
nullable=True),
sa.PrimaryKeyConstraint('uuid', 'ovsdb_identifier'))
op.create_table('logical_switches',

View File

@ -298,7 +298,8 @@ class OVSDBMonitor(base_connection.BaseConnection):
old_row = uuid_dict.get('old', None)
if new_row:
port = ovsdb_schema.PhysicalPort(uuid, new_row.get('name'), None,
None)
None,
new_row.get('port_fault_status'))
switch_id = port_map.get(uuid, None)
if switch_id:
port.physical_switch_id = switch_id
@ -328,7 +329,8 @@ class OVSDBMonitor(base_connection.BaseConnection):
elif old_row:
# Port is deleted permanently from OVSDB server
port = ovsdb_schema.PhysicalPort(uuid, old_row.get('name'), None,
None)
None,
old_row.get('port_fault_status'))
deleted_physical_ports = data_dict.get('deleted_physical_ports')
deleted_physical_ports.append(port)
@ -356,10 +358,9 @@ class OVSDBMonitor(base_connection.BaseConnection):
for inner_port in port:
if inner_port != 'uuid':
all_ports.append(inner_port)
phys_switch = ovsdb_schema.PhysicalSwitch(uuid,
new_row.get('name'),
new_row.get('tunnel_ips')
)
phys_switch = ovsdb_schema.PhysicalSwitch(
uuid, new_row.get('name'), new_row.get('tunnel_ips'),
new_row.get('switch_fault_status'))
# Now, store mapping of physical ports to
# physical switch so that it is useful while
# processing Physical_Switch record
@ -379,10 +380,9 @@ class OVSDBMonitor(base_connection.BaseConnection):
elif old_row:
# Physical switch is deleted permanently from OVSDB
# server
phys_switch = ovsdb_schema.PhysicalSwitch(uuid,
old_row.get('name'),
old_row.get('tunnel_ips')
)
phys_switch = ovsdb_schema.PhysicalSwitch(
uuid, old_row.get('name'), old_row.get('tunnel_ips'),
old_row.get('switch_fault_status'))
deleted_physical_switches = data_dict.get(
'deleted_physical_switches')
deleted_physical_switches.append(phys_switch)

View File

@ -40,3 +40,5 @@ L2_GATEWAYS_CONNECTION = "%ss" % EXT_ALIAS
BUFFER_SIZE = 4096
MAX_RETRIES = 500
L2_GATEWAY_SERVICE_PLUGIN = "Neutron L2 gateway Service Plugin"
PORT_FAULT_STATUS_UP = "UP"
SWITCH_FAULT_STATUS_UP = "UP"

View File

@ -21,18 +21,21 @@ class PhysicalLocator(object):
class PhysicalSwitch(object):
def __init__(self, uuid, name, tunnel_ip):
def __init__(self, uuid, name, tunnel_ip, switch_fault_status):
self.uuid = uuid
self.name = name
self.tunnel_ip = tunnel_ip
self.switch_fault_status = switch_fault_status
class PhysicalPort(object):
def __init__(self, uuid, name, phys_switch_id, vlan_binding_dicts):
def __init__(self, uuid, name, phys_switch_id, vlan_binding_dicts,
port_fault_status):
self.uuid = uuid
self.name = name
self.physical_switch_id = phys_switch_id
self.vlan_bindings = []
self.port_fault_status = port_fault_status
if vlan_binding_dicts:
for vlan_binding in vlan_binding_dicts:
v_binding = VlanBinding(vlan_binding['vlan'],

View File

@ -60,6 +60,16 @@ class L2GatewayInterfaceNotFound(exceptions.NeutronException):
message = _("L2 Gateway interface not found on '%(interface_id)s'")
class L2GatewayPhysicalPortFaultStatus(exceptions.NeutronException):
message = _("Physical Port '%(int_name)s' in Physical switch "
"'%(device_name)s' port_fault_status is '%(fault_status)s'")
class L2GatewayPhysicalSwitchFaultStatus(exceptions.NeutronException):
message = _("Physical Switch '%(device_name)s' switch_fault_status is "
"'%(fault_status)s'")
class L2GatewayConnectionNotFound(exceptions.NotFound):
message = _("The connection %(id)s not found on the l2 gateway")

View File

@ -89,6 +89,8 @@ class OVSDBData(object):
self._process_deleted_local_macs,
'deleted_remote_macs':
self._process_deleted_remote_macs,
'modified_physical_switches':
self._process_modified_physical_switches,
}
return
@ -193,6 +195,7 @@ class OVSDBData(object):
pp_dict[n_const.OVSDB_IDENTIFIER] = self.ovsdb_identifier
modified_port = db.get_physical_port(context, pp_dict)
if modified_port:
db.update_physical_ports_status(context, pp_dict)
port_vlan_bindings = physical_port.get('vlan_bindings')
vlan_bindings = db.get_all_vlan_bindings_by_physical_port(
context, pp_dict)
@ -206,6 +209,11 @@ class OVSDBData(object):
else:
db.add_physical_port(context, pp_dict)
def _process_modified_physical_switches(self, context,
modified_physical_switches):
for physical_switch in modified_physical_switches:
db.update_physical_switch_status(context, physical_switch)
def _process_deleted_logical_switches(self,
context,
deleted_logical_switches):

View File

@ -258,9 +258,37 @@ class L2GatewayPlugin(l2gateway_db.L2GatewayMixin):
logical_switch_uuid,
mac_list)
def _check_port_fault_status_and_switch_fault_status(self, context,
l2_gateway_id):
l2gw = self.get_l2_gateway(context, l2_gateway_id)
devices = l2gw['devices']
rec_dict = {}
for device in devices:
device_name = device['device_name']
dev_db = db.get_physical_switch_by_name(context, device_name)
rec_dict['physical_switch_id'] = dev_db['uuid']
rec_dict['ovsdb_identifier'] = dev_db['ovsdb_identifier']
status = dev_db.get('switch_fault_status')
if status != constants.SWITCH_FAULT_STATUS_UP:
raise l2gw_exc.L2GatewayPhysicalSwitchFaultStatus(
device_name=device_name, fault_status=status)
for interface_list in device['interfaces']:
int_name = interface_list.get('name')
rec_dict['interface_name'] = int_name
port_db = db.get_physical_port_by_name_and_ps(context,
rec_dict)
port_status = port_db['port_fault_status']
if (port_db['port_fault_status']) != (
constants.PORT_FAULT_STATUS_UP):
raise l2gw_exc.L2GatewayPhysicalPortFaultStatus(
int_name=int_name, device_name=device_name,
fault_status=port_status)
def _validate_connection(self, context, gw_connection):
seg_id = gw_connection.get('segmentation_id', None)
l2_gw_id = gw_connection.get('l2_gateway_id')
self._check_port_fault_status_and_switch_fault_status(context,
l2_gw_id)
check_vlan = self._is_vlan_configured_on_any_interface_for_l2gw(
context, l2_gw_id)
nw_map = {}
@ -358,7 +386,8 @@ class L2GatewayPlugin(l2gateway_db.L2GatewayMixin):
uuid=pp_dict.get('uuid'),
name=pp_dict.get('interface_name'),
phys_switch_id=pp_dict.get('physical_switch_id'),
vlan_binding_dicts=None))
vlan_binding_dicts=None,
port_fault_status=None))
physical_port['vlan_bindings'] = port_list
else:
vlan_id = gw_connection.get('segmentation_id')
@ -377,7 +406,8 @@ class L2GatewayPlugin(l2gateway_db.L2GatewayMixin):
uuid=pp_dict.get('uuid'),
name=pp_dict.get('interface_name'),
phys_switch_id=pp_dict.get('physical_switch_id'),
vlan_binding_dicts=None))
vlan_binding_dicts=None,
port_fault_status=None))
physical_port['vlan_bindings'] = port_list
return physical_port

View File

@ -374,6 +374,7 @@ class TestOVSDBMonitor(base.BaseTestCase):
add = {'new': {'uuid': 'fake_id',
'name': 'fake_name',
'physical_switch_id': 'fake_switch_id',
'port_fault_status': 'fake_status',
'vlan_bindings': [["some"], []]}}
delete = {'old': {'uuid': 'fake_id_old',
'name': 'fake_name_old',
@ -393,7 +394,8 @@ class TestOVSDBMonitor(base.BaseTestCase):
add,
port_map,
data_dict)
phy_port.assert_called_with(fake_id, 'fake_name', None, None)
phy_port.assert_called_with(fake_id, 'fake_name', None, None,
'fake_status')
self.assertIn(phy_port.return_value,
data_dict.get('new_physical_ports'))
@ -422,6 +424,7 @@ class TestOVSDBMonitor(base.BaseTestCase):
add = {'new': {'uuid': 'fake_id',
'name': 'fake_name',
'tunnel_ips': 'fake_tunnel_ip',
'switch_fault_status': 'fake_status',
'ports': ['set', 'set',
physical_port]}}
delete = {'old': {'uuid': 'fake_id_old',
@ -441,6 +444,8 @@ class TestOVSDBMonitor(base.BaseTestCase):
data_dict)
self.assertIn(phy_switch.return_value,
data_dict['new_physical_switches'])
phy_switch.assert_called_with('fake_id', 'fake_name',
'fake_tunnel_ip', 'fake_status')
# test modify
self.l2gw_ovsdb._process_physical_switch(fake_id,
modify,

View File

@ -364,14 +364,18 @@ class TestOVSDBData(base.BaseTestCase):
mock.patch.object(lib,
'get_all_vlan_bindings_by_physical_port'),
mock.patch.object(lib,
'add_vlan_binding')) as (
get_pp, add_pp, get_vlan, add_vlan):
'add_vlan_binding'),
mock.patch.object(lib,
'update_physical_ports_status')
) as (
get_pp, add_pp, get_vlan, add_vlan, update_pp_status):
self.ovsdb_data._process_modified_physical_ports(
self.context, fake_modified_physical_ports)
self.assertIn(n_const.OVSDB_IDENTIFIER, fake_dict2)
self.assertEqual(fake_dict2[n_const.OVSDB_IDENTIFIER],
'fake_ovsdb_id')
get_pp.assert_called_with(self.context, fake_dict2)
update_pp_status.assert_called_with(self.context, fake_dict2)
self.assertFalse(add_pp.called)
get_vlan.assert_called_with(self.context, fake_dict2)
self.assertIn(n_const.OVSDB_IDENTIFIER, fake_dict1)

View File

@ -25,6 +25,7 @@ from networking_l2gw.db.l2gateway.ovsdb import lib as db
from networking_l2gw.services.l2gateway import agent_scheduler
from networking_l2gw.services.l2gateway.common import config
from networking_l2gw.services.l2gateway.common import l2gw_validators
from networking_l2gw.services.l2gateway import exceptions as l2gw_exc
from networking_l2gw.services.l2gateway import plugin as l2gw_plugin
from oslo_utils import importutils
@ -202,9 +203,12 @@ class TestL2GatewayPlugin(base.BaseTestCase):
return_value=fake_tenant_id),
mock.patch.object(l2gateway_db.L2GatewayMixin,
'get_l2_gateway_connections',
return_value=False)) as (
is_vlan, val_ntwk, get_net_seg, get_network, get_l2gw,
ret_gw_conn, get_ten_id, get_l2_gw_conn):
return_value=False),
mock.patch.object(
self.plugin,
'_check_port_fault_status_and_switch_fault_status')
) as (is_vlan, val_ntwk, get_net_seg, get_network, get_l2gw,
ret_gw_conn, get_ten_id, get_l2_gw_conn, check_pf_sf):
self.plugin._validate_connection(self.context, fake_connection)
is_vlan.assert_called_with(self.context, 'fake_l2gw_id')
val_ntwk.assert_called_with(fake_connection, False)
@ -212,6 +216,7 @@ class TestL2GatewayPlugin(base.BaseTestCase):
'fake_network_id')
get_network.assert_called_with(self.context, 'fake_network_id')
get_l2gw.assert_called_with(self.context, 'fake_l2gw_id')
check_pf_sf.assert_called_with(self.context, 'fake_l2gw_id')
ret_gw_conn.assert_called_with(self.context,
'fake_l2gw_id',
fake_connection)
@ -632,6 +637,69 @@ class TestL2GatewayPlugin(base.BaseTestCase):
self.assertTrue(update_rpc.called)
del_conn.assert_called_with(self.db_context, fake_conn_dict)
def test_create_l2gateway_connection_with_switch_fault_status_down(self):
self.db_context = ctx.get_admin_context()
fake_l2gw_conn_dict = {'l2_gateway_connection': {
'id': 'fake_id', 'network_id': 'fake_network_id',
'l2_gateway_id': 'fake_l2gw_id'}}
fake_device = {'devices': [{'device_name': 'fake_device',
'interfaces': [{'name': 'fake_interface'}]}]}
fake_physical_port = {'uuid': 'fake_id',
'name': 'fake_name',
'physical_switch_id': 'fake_switch1',
'port_fault_status': 'UP'}
fake_physical_switch = {'uuid': 'fake_id',
'name': 'fake_name',
'tunnel_ip': 'fake_tunnel_ip',
'ovsdb_identifier': 'fake_ovsdb_id',
'switch_fault_status': 'DOWN'}
with contextlib.nested(
mock.patch.object(l2gateway_db.L2GatewayMixin,
'_admin_check',
return_value=True),
mock.patch.object(l2gateway_db.L2GatewayMixin, 'get_l2_gateway',
return_value=fake_device),
mock.patch.object(db, 'get_physical_port_by_name_and_ps',
return_value=fake_physical_port),
mock.patch.object(db, 'get_physical_switch_by_name',
return_value=fake_physical_switch)
) as (get_l2gw, admin_check, phy_port, phy_switch):
self.assertRaises(l2gw_exc.L2GatewayPhysicalSwitchFaultStatus,
self.plugin.create_l2_gateway_connection,
self.db_context,
fake_l2gw_conn_dict)
def test_create_l2gateway_connection_with_port_fault_status_down(self):
self.db_context = ctx.get_admin_context()
fake_l2gw_conn_dict = {'l2_gateway_connection': {
'id': 'fake_id', 'network_id': 'fake_network_id',
'l2_gateway_id': 'fake_l2gw_id'}}
fake_device = {'devices': [{'device_name': 'fake_device',
'interfaces': [{'name': 'fake_interface'}]}]}
fake_physical_port = {'uuid': 'fake_id',
'name': 'fake_name',
'physical_switch_id': 'fake_switch1',
'port_fault_status': 'DOWN'}
fake_physical_switch = {'uuid': 'fake_id',
'name': 'fake_name',
'tunnel_ip': 'fake_tunnel_ip',
'ovsdb_identifier': 'fake_ovsdb_id',
'switch_fault_status': 'UP'}
with contextlib.nested(
mock.patch.object(l2gateway_db.L2GatewayMixin,
'_admin_check',
return_value=True),
mock.patch.object(l2gateway_db.L2GatewayMixin, 'get_l2_gateway',
return_value=fake_device),
mock.patch.object(db, 'get_physical_port_by_name_and_ps',
return_value=fake_physical_port),
mock.patch.object(db, 'get_physical_switch_by_name',
return_value=fake_physical_switch)
) as (get_l2gw, admin_check, phy_port, phy_switch):
self.assertRaises(l2gw_exc.L2GatewayPhysicalPortFaultStatus,
self.plugin.create_l2_gateway_connection,
self.db_context, fake_l2gw_conn_dict)
def test_create_l2_gateway_connection(self):
self.db_context = ctx.get_admin_context()
fake_l2gw_conn_dict = {'l2_gateway_connection': {