diff --git a/README.md b/README.md index 9d66088..2e940fb 100644 --- a/README.md +++ b/README.md @@ -352,7 +352,8 @@ network_connections: autoconnect: no type: vlan parent: eth1-profile - vlan_id: 6 + vlan: + id: 6 ip: address: - 192.0.2.5/24 diff --git a/library/network_connections.py b/library/network_connections.py index 480178d..d6012e4 100755 --- a/library/network_connections.py +++ b/library/network_connections.py @@ -818,6 +818,22 @@ class ArgValidator_DictBond(ArgValidatorDict): 'miimon': None, } +class ArgValidator_DictVlan(ArgValidatorDict): + + def __init__(self): + ArgValidatorDict.__init__(self, + name = 'vlan', + nested = [ + ArgValidatorNum ('id', val_min = 0, val_max = 4094, required = True), + ], + default_value = ArgValidator.MISSING, + ) + + def get_default_vlan(self): + return { + 'id': None, + } + class ArgValidator_DictConnection(ArgValidatorDict): @@ -843,13 +859,16 @@ class ArgValidator_DictConnection(ArgValidatorDict): ArgValidatorStr ('zone'), ArgValidatorBool('check_iface_exists', default_value = True), ArgValidatorStr ('parent'), - ArgValidatorNum ('vlan_id', val_min = 0, val_max = 4094, default_value = None), ArgValidatorBool('ignore_errors', default_value = None), ArgValidatorStr ('infiniband_transport_mode', enum_values = ['datagram', 'connected']), ArgValidatorNum ('infiniband_p_key', val_min = -1, val_max = 0xFFFF, default_value = None), ArgValidator_DictIP(), ArgValidator_DictEthernet(), ArgValidator_DictBond(), + ArgValidator_DictVlan(), + + # deprecated options: + ArgValidatorNum ('vlan_id', val_min = 0, val_max = 4094, default_value = ArgValidator.MISSING), ], default_value = dict, all_missing_during_validate = True, @@ -957,11 +976,20 @@ class ArgValidator_DictConnection(ArgValidatorDict): result['interface_name'] = result['name'] if result['type'] == 'vlan': - if 'vlan_id' not in result: - raise ValidationError(name + '.vlan_id', 'missing "vlan_id" for "type" "vlan"') + if 'vlan' not in result: + if 'vlan_id' not in result: + raise ValidationError(name + '.vlan', 'missing "vlan" settings for "type" "vlan"') + result['vlan'] = self.nested['vlan'].get_default_vlan() + result['vlan']['id'] = result['vlan_id'] + del result['vlan_id'] + else: + if 'vlan_id' in result: + raise ValidationError(name + '.vlan_id', 'don\'t use the deprecated "vlan_id" together with the "vlan" settings"') if 'parent' not in result: raise ValidationError(name + '.parent', 'missing "parent" for "type" "vlan"') else: + if 'vlan' in result: + raise ValidationError(name + '.vlan', '"vlan" is only allowed for "type" "vlan"') if 'vlan_id' in result: raise ValidationError(name + '.vlan_id', '"vlan_id" is only allowed for "type" "vlan"') @@ -1218,7 +1246,7 @@ class IfcfgUtil: ifcfg['VLAN'] = 'yes' ifcfg['TYPE'] = 'Vlan' ifcfg['PHYSDEV'] = ArgUtil.connection_find_master(connection['parent'], connections, idx) - ifcfg['VID'] = str(connection['vlan_id']) + ifcfg['VID'] = str(connection['vlan']['id']) else: raise MyError('unsupported type %s' % (connection['type'])) @@ -1604,7 +1632,7 @@ class NMUtil: s_con.set_property(NM.SETTING_CONNECTION_TYPE, 'team') elif connection['type'] == 'vlan': s_vlan = self.connection_ensure_setting(con, NM.SettingVlan) - s_vlan.set_property(NM.SETTING_VLAN_ID, connection['vlan_id']) + s_vlan.set_property(NM.SETTING_VLAN_ID, connection['vlan']['id']) s_vlan.set_property(NM.SETTING_VLAN_PARENT, ArgUtil.connection_find_master_uuid(connection['parent'], connections, idx)) else: raise MyError('unsupported type %s' % (connection['type'])) diff --git a/library/test_network_connections.py b/library/test_network_connections.py index a1260d8..8078bb0 100755 --- a/library/test_network_connections.py +++ b/library/test_network_connections.py @@ -260,7 +260,6 @@ class TestValidator(unittest.TestCase): 'mtu': None, 'zone': None, 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': None, 'check_iface_exists': True, @@ -315,7 +314,6 @@ class TestValidator(unittest.TestCase): 'mtu': None, 'zone': None, 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': None, 'check_iface_exists': True, @@ -391,7 +389,6 @@ class TestValidator(unittest.TestCase): 'mac': '52:54:00:44:9f:ba', 'zone': None, 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': None, 'type': 'ethernet', @@ -460,7 +457,6 @@ class TestValidator(unittest.TestCase): 'mac': '52:54:00:44:9f:ba', 'zone': None, 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': None, 'type': 'ethernet', @@ -523,7 +519,9 @@ class TestValidator(unittest.TestCase): 'ignore_errors': None, 'interface_name': 'prod.100', 'type': 'vlan', - 'vlan_id': 100, + 'vlan': { + 'id' : 100, + }, 'wait': None, 'infiniband_p_key': None, 'infiniband_transport_mode': None, @@ -546,7 +544,161 @@ class TestValidator(unittest.TestCase): 'state': 'up', 'type': 'vlan', 'parent': 'prod1', - 'vlan_id': '100', + 'vlan': { + 'id': '100', + }, + 'ip': { + 'address': [ + '192.168.174.5/24', + { + 'address': 'a:b:c::6', + 'prefix': 65, + }, + ], + 'route_append_only': False, + 'rule_append_only': False, + 'route': [ + { + 'network': '192.168.5.0', + }, + ], + } + } + ], + ) + + self.do_connections_validate( + [ + { + 'autoconnect': True, + 'name': 'prod1', + 'parent': None, + 'ip': { + 'dhcp4': False, + 'auto6': True, + 'address': [ + { + 'prefix': 24, + 'family': socket.AF_INET, + 'address': '192.168.176.5' + }, + { + 'prefix': 24, + 'family': socket.AF_INET, + 'address': '192.168.177.5' + } + ], + 'route_append_only': False, + 'rule_append_only': False, + 'route': [], + 'route_metric6': None, + 'route_metric4': None, + 'dns_search': [], + 'dhcp4_send_hostname': None, + 'gateway6': None, + 'gateway4': None, + 'dns': [] + }, + 'ethernet': { + 'autoneg': None, + 'duplex': None, + 'speed': 0, + }, + 'state': 'up', + 'mtu': 1450, + 'check_iface_exists': True, + 'force_state_change': None, + 'mac': '52:54:00:44:9f:ba', + 'zone': None, + 'master': None, + 'ignore_errors': None, + 'interface_name': None, + 'type': 'ethernet', + 'slave_type': None, + 'wait': None, + 'infiniband_p_key': None, + 'infiniband_transport_mode': None, + }, + { + 'autoconnect': True, + 'name': 'prod.100', + 'parent': 'prod1', + 'ip': { + 'dhcp4': False, + 'route_metric6': None, + 'route_metric4': None, + 'dns_search': [], + 'dhcp4_send_hostname': None, + 'gateway6': None, + 'gateway4': None, + 'auto6': False, + 'dns': [], + 'address': [ + { + 'prefix': 24, + 'family': socket.AF_INET, + 'address': '192.168.174.5' + }, + { + 'prefix': 65, + 'family': socket.AF_INET6, + 'address': 'a:b:c::6', + }, + ], + 'route_append_only': False, + 'rule_append_only': False, + 'route': [ + { + 'family': socket.AF_INET, + 'network': '192.168.5.0', + 'prefix': 24, + 'gateway': None, + 'metric': -1, + }, + ], + }, + 'ethernet': { + 'autoneg': None, + 'duplex': None, + 'speed': 0, + }, + 'mac': None, + 'mtu': None, + 'zone': None, + 'check_iface_exists': True, + 'force_state_change': None, + 'state': 'up', + 'master': None, + 'slave_type': None, + 'ignore_errors': None, + 'interface_name': 'prod.100', + 'type': 'vlan', + 'vlan': { + 'id' : 101, + }, + 'wait': None, + 'infiniband_p_key': None, + 'infiniband_transport_mode': None, + } + ], + [ + { + 'name': 'prod1', + 'state': 'up', + 'type': 'ethernet', + 'autoconnect': 'yes', + 'mac': '52:54:00:44:9f:ba', + 'mtu': 1450, + 'ip': { + 'address': '192.168.176.5/24 192.168.177.5/24', + } + }, + { + 'name': 'prod.100', + 'state': 'up', + 'type': 'vlan', + 'parent': 'prod1', + 'vlan_id': 101, 'ip': { 'address': [ '192.168.174.5/24', @@ -600,7 +752,6 @@ class TestValidator(unittest.TestCase): 'force_state_change': None, 'state': 'up', 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': 'bridge2', 'type': 'bridge', @@ -640,7 +791,6 @@ class TestValidator(unittest.TestCase): 'force_state_change': None, 'state': 'up', 'master': 'prod2', - 'vlan_id': None, 'ignore_errors': None, 'interface_name': 'eth1', 'type': 'ethernet', @@ -704,7 +854,6 @@ class TestValidator(unittest.TestCase): 'force_state_change': None, 'state': 'up', 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': 'bond1', 'type': 'bond', @@ -760,7 +909,6 @@ class TestValidator(unittest.TestCase): 'force_state_change': None, 'state': 'up', 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': 'bond1', 'type': 'bond', @@ -825,7 +973,6 @@ class TestValidator(unittest.TestCase): 'slave_type': None, 'state': 'present', 'type': 'ethernet', - 'vlan_id': None, 'infiniband_p_key': None, 'infiniband_transport_mode': None, }, @@ -871,7 +1018,6 @@ class TestValidator(unittest.TestCase): 'mtu': None, 'zone': None, 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': None, 'check_iface_exists': True, @@ -922,7 +1068,6 @@ class TestValidator(unittest.TestCase): 'mtu': None, 'zone': None, 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': None, 'check_iface_exists': True, @@ -1004,7 +1149,6 @@ class TestValidator(unittest.TestCase): 'slave_type': None, 'state': 'up', 'type': 'bridge', - 'vlan_id': None, 'wait': None, 'zone': None, }, @@ -1044,7 +1188,6 @@ class TestValidator(unittest.TestCase): 'slave_type': 'bridge', 'state': 'up', 'type': 'ethernet', - 'vlan_id': None, 'wait': None, 'zone': None, } @@ -1095,7 +1238,6 @@ class TestValidator(unittest.TestCase): 'slave_type': None, 'state': 'up', 'type': 'infiniband', - 'vlan_id': None, 'wait': None, 'zone': None, }, @@ -1160,7 +1302,6 @@ class TestValidator(unittest.TestCase): 'slave_type': None, 'state': 'up', 'type': 'infiniband', - 'vlan_id': None, 'wait': None, 'zone': None, }, @@ -1245,7 +1386,6 @@ class TestValidator(unittest.TestCase): 'mtu': None, 'zone': None, 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': None, 'check_iface_exists': True, @@ -1349,7 +1489,6 @@ class TestValidator(unittest.TestCase): 'mtu': None, 'zone': 'external', 'master': None, - 'vlan_id': None, 'ignore_errors': None, 'interface_name': None, 'check_iface_exists': True,