diff options
-rw-r--r-- | os_net_config/__init__.py | 4 | ||||
-rw-r--r-- | os_net_config/impl_ifcfg.py | 66 | ||||
-rw-r--r-- | os_net_config/objects.py | 29 | ||||
-rw-r--r-- | os_net_config/tests/test_impl_ifcfg.py | 97 |
4 files changed, 162 insertions, 34 deletions
diff --git a/os_net_config/__init__.py b/os_net_config/__init__.py index 27dc95e..066ebb5 100644 --- a/os_net_config/__init__.py +++ b/os_net_config/__init__.py @@ -29,8 +29,8 @@ class NetConfig(object): def addInterface(self, interface): raise NotImplemented("addInterface is not implemented.") - def addRoutes(self, interface_name, routes=[]): - raise NotImplemented("addRoutes is not implemented.") + def addBridge(self, bridge): + raise NotImplemented("addBridge is not implemented.") def apply(self): raise NotImplemented("apply is not implemented.") diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py index c4ea5dd..b4da7bc 100644 --- a/os_net_config/impl_ifcfg.py +++ b/os_net_config/impl_ifcfg.py @@ -23,6 +23,11 @@ def ifcfg_config_path(name): return "/etc/sysconfig/network-scripts/ifcfg-%s" % name +#NOTE(dprince): added here for testability +def bridge_config_path(name): + return ifcfg_config_path(name) + + def route_config_path(name): return "/etc/sysconfig/network-scripts/route-%s" % name @@ -33,21 +38,32 @@ class IfcfgNetConfig(os_net_config.NetConfig): def __init__(self): self.interfaces = {} self.routes = {} + self.bridges = {} - def addInterface(self, interface): + def _addCommon(self, interface): data = "DEVICE=%s\n" % interface.name data += "ONBOOT=yes\n" data += "HOTPLUG=no\n" - if interface.type == 'ovs': + if interface.type == 'ovs_port': data += "DEVICETYPE=ovs\n" - if interface.bridge: + if interface.bridge_name: data += "TYPE=OVSPort\n" - data += "OVS_BRIDGE=%s\n" % interface.bridge + data += "OVS_BRIDGE=%s\n" % interface.bridge_name + if interface.type == 'ovs_bridge': + data += "DEVICETYPE=ovs\n" + data += "TYPE=OVSBridge\n" + if interface.use_dhcp: + data += "OVSBOOTPROTO=dhcp\n" + if interface.members: + members = [member.name for member in interface.members] + data += ("OVSDHCPINTERFACES=%s\n" % " ".join(members)) + else: + if interface.use_dhcp: + data += "BOOTPROTO=dhcp\n" + elif not interface.addresses: data += "BOOTPROTO=none\n" if interface.mtu != 1500: data += "MTU=%i\n" % interface.mtu - if interface.use_dhcp: - data += "BOOTPROTO=dhcp\n" if interface.use_dhcpv6 or interface.v6_addresses(): data += "IPV6INIT=yes\n" if interface.mtu != 1500: @@ -69,11 +85,25 @@ class IfcfgNetConfig(os_net_config.NetConfig): data += "IPV6_AUTOCONF=no\n" data += "IPV6ADDR=%s\n" % first_v6.ip + return data + + def addInterface(self, interface): + data = self._addCommon(interface) + self.interfaces[interface.name] = data if interface.routes: - self.addRoutes(interface.name, interface.routes) + self._addRoutes(interface.name, interface.routes) - def addRoutes(self, interface_name, routes=[]): + def addBridge(self, bridge): + data = self._addCommon(bridge) + + self.bridges[bridge.name] = data + if bridge.routes: + self._addRoutes(bridge.name, bridge.routes) + if bridge.routes: + self._addRoutes(bridge.name, bridge.routes) + + def _addRoutes(self, interface_name, routes=[]): data = "" first_line = "" for route in routes: @@ -88,7 +118,9 @@ class IfcfgNetConfig(os_net_config.NetConfig): def apply(self): restart_interfaces = [] + restart_bridges = [] update_files = {} + for interface_name, iface_data in self.interfaces.iteritems(): route_data = self.routes.get(interface_name) if (utils.diff(ifcfg_config_path(interface_name), iface_data) or @@ -97,11 +129,27 @@ class IfcfgNetConfig(os_net_config.NetConfig): update_files[ifcfg_config_path(interface_name)] = iface_data update_files[route_config_path(interface_name)] = route_data + for bridge_name, bridge_data in self.bridges.iteritems(): + route_data = self.routes.get(bridge_name) + if (utils.diff(ifcfg_config_path(bridge_name), bridge_data) or + utils.diff(route_config_path(bridge_name), route_data)): + restart_bridges.append(bridge_name) + update_files[bridge_config_path(bridge_name)] = bridge_data + update_files[route_config_path(bridge_name)] = route_data + for interface in restart_interfaces: - processutils.execute('/sbin/ifdown', interface) + processutils.execute('/sbin/ifdown', interface, + check_exit_code=False) + + for bridge in restart_bridges: + processutils.execute('/sbin/ifdown', bridge, + check_exit_code=False) for location, data in update_files.iteritems(): utils.write_config(location, data) + for bridge in restart_bridges: + processutils.execute('/sbin/ifup', bridge) + for interface in restart_interfaces: processutils.execute('/sbin/ifup', interface) diff --git a/os_net_config/objects.py b/os_net_config/objects.py index 4b6e09e..c4f5600 100644 --- a/os_net_config/objects.py +++ b/os_net_config/objects.py @@ -40,8 +40,8 @@ class Address(object): self.routes = routes -class Interface(object): - """Base class for network interfaces.""" +class _BaseOpts(object): + """Base abstraction for logical port options.""" def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=[], routes=[], mtu=1500): @@ -51,7 +51,7 @@ class Interface(object): self.use_dhcpv6 = use_dhcpv6 self.addresses = addresses self.routes = routes - self.bridge = None + self.bridge_name = None self.type = None def v4_addresses(self): @@ -69,3 +69,26 @@ class Interface(object): v6_addresses.append(addr) return v6_addresses + + +class Interface(_BaseOpts): + """Base class for network interfaces.""" + + def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=[], + routes=[], mtu=1500): + super(Interface, self).__init__(name, use_dhcp, use_dhcpv6, addresses, + routes, mtu) + + +class OvsBridge(_BaseOpts): + """Base class for OVS bridges.""" + + def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=[], + routes=[], members=[], mtu=1500): + super(OvsBridge, self).__init__(name, use_dhcp, use_dhcpv6, addresses, + routes, mtu) + self.type = 'ovs_bridge' + self.members = members + for member in self.members: + member.bridge_name = name + member.type = 'ovs_port' diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py index a383a56..e0df5b4 100644 --- a/os_net_config/tests/test_impl_ifcfg.py +++ b/os_net_config/tests/test_impl_ifcfg.py @@ -26,6 +26,8 @@ ONBOOT=yes HOTPLUG=no """ +_NO_IP = _BASE_IFCFG + "BOOTPROTO=none\n" + _V4_IFCFG = _BASE_IFCFG + """BOOTPROTO=static IPADDR=192.168.1.2 NETMASK=255.255.255.0 @@ -36,7 +38,7 @@ IPV6_AUTOCONF=no IPV6ADDR=2001:abc:a:: """ -_OVS_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\n" +_OVS_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\nBOOTPROTO=none\n" _OVS_BRIDGE_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\n" @@ -46,27 +48,30 @@ _ROUTES = """default via 192.168.1.1 dev em1 172.19.0.0/24 via 192.168.1.1 dev em1 """ +_OVS_INTERFACE = _BASE_IFCFG + """DEVICETYPE=ovs +TYPE=OVSPort +OVS_BRIDGE=br-ctlplane +BOOTPROTO=none +""" + +_OVS_BRIDGE_DHCP = """DEVICE=br-ctlplane +ONBOOT=yes +HOTPLUG=no +DEVICETYPE=ovs +TYPE=OVSBridge +OVSBOOTPROTO=dhcp +OVSDHCPINTERFACES=em1 +""" + class TestIfcfgNetConfig(base.TestCase): def setUp(self): super(TestIfcfgNetConfig, self).setUp() - self.temp_ifcfg_file = tempfile.NamedTemporaryFile() - self.temp_route_file = tempfile.NamedTemporaryFile() - - def test_ifcfg_path(name): - return self.temp_ifcfg_file.name - self.stubs.Set(impl_ifcfg, 'ifcfg_config_path', test_ifcfg_path) - - def test_routes_path(name): - return self.temp_route_file.name - self.stubs.Set(impl_ifcfg, 'route_config_path', test_routes_path) self.provider = impl_ifcfg.IfcfgNetConfig() def tearDown(self): - self.temp_ifcfg_file.close() - self.temp_route_file.close() super(TestIfcfgNetConfig, self).tearDown() def get_interface_config(self): @@ -78,11 +83,11 @@ class TestIfcfgNetConfig(base.TestCase): def test_add_base_interface(self): interface = objects.Interface('em1') self.provider.addInterface(interface) - self.assertEqual(_BASE_IFCFG, self.get_interface_config()) + self.assertEqual(_NO_IP, self.get_interface_config()) def test_add_ovs_interface(self): interface = objects.Interface('em1') - interface.type = 'ovs' + interface.type = 'ovs_port' self.provider.addInterface(interface) self.assertEqual(_OVS_IFCFG, self.get_interface_config()) @@ -107,7 +112,50 @@ class TestIfcfgNetConfig(base.TestCase): self.assertEqual(_V4_IFCFG, self.get_interface_config()) self.assertEqual(_ROUTES, self.get_route_config()) - def test_apply(self): + def test_network_ovs_bridge_with_dhcp(self): + interface = objects.Interface('em1') + bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, + members=[interface]) + self.provider.addInterface(interface) + self.provider.addBridge(bridge) + self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) + self.assertEqual(_OVS_BRIDGE_DHCP, + self.provider.bridges['br-ctlplane']) + + +class TestIfcfgNetConfigApply(base.TestCase): + + def setUp(self): + super(TestIfcfgNetConfigApply, self).setUp() + self.temp_ifcfg_file = tempfile.NamedTemporaryFile() + self.temp_route_file = tempfile.NamedTemporaryFile() + self.temp_bridge_file = tempfile.NamedTemporaryFile() + + def test_ifcfg_path(name): + return self.temp_ifcfg_file.name + self.stubs.Set(impl_ifcfg, 'ifcfg_config_path', test_ifcfg_path) + + def test_routes_path(name): + return self.temp_route_file.name + self.stubs.Set(impl_ifcfg, 'route_config_path', test_routes_path) + + def test_bridge_path(name): + return self.temp_bridge_file.name + self.stubs.Set(impl_ifcfg, 'bridge_config_path', test_bridge_path) + + def test_execute(*args, **kwargs): + pass + self.stubs.Set(processutils, 'execute', test_execute) + + self.provider = impl_ifcfg.IfcfgNetConfig() + + def tearDown(self): + self.temp_ifcfg_file.close() + self.temp_route_file.close() + self.temp_bridge_file.close() + super(TestIfcfgNetConfigApply, self).tearDown() + + def test_network_apply(self): route1 = objects.Route('192.168.1.1', default=True) route2 = objects.Route('192.168.1.1', '172.19.0.0/24') v4_addr = objects.Address('192.168.1.2/24') @@ -115,13 +163,22 @@ class TestIfcfgNetConfig(base.TestCase): routes=[route1, route2]) self.provider.addInterface(interface) - def test_execute(*args, **kwargs): - pass - self.stubs.Set(processutils, 'execute', test_execute) - self.provider.apply() ifcfg_data = utils.get_file_data(self.temp_ifcfg_file.name) self.assertEqual(_V4_IFCFG, ifcfg_data) route_data = utils.get_file_data(self.temp_route_file.name) self.assertEqual(_ROUTES, route_data) + + def test_dhcp_ovs_bridge_network_apply(self): + interface = objects.Interface('em1') + bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, + members=[interface]) + self.provider.addInterface(interface) + self.provider.addBridge(bridge) + self.provider.apply() + + ifcfg_data = utils.get_file_data(self.temp_ifcfg_file.name) + self.assertEqual(_OVS_INTERFACE, ifcfg_data) + bridge_data = utils.get_file_data(self.temp_bridge_file.name) + self.assertEqual(_OVS_BRIDGE_DHCP, bridge_data) |