From 3304fa066d1dae93df0f597c1709c955e3857a5d Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Mon, 26 Jan 2015 18:44:21 +0000 Subject: Add a --no-activate option to disable device up/down actions Allows you to only install the config, but not take interfaces down/up. Useful if you wish to defer activation of a new config until a later time (e.g reboot). Change-Id: I42f3195e1d3d5d3b9d1c9dbb1f7cf1364503cbd3 --- os_net_config/cli.py | 10 +++++++++- os_net_config/impl_eni.py | 25 ++++++++++++++++--------- os_net_config/impl_ifcfg.py | 24 +++++++++++++++--------- os_net_config/tests/test_impl_eni.py | 19 +++++++++++++++++++ os_net_config/tests/test_impl_ifcfg.py | 13 +++++++++++-- 5 files changed, 70 insertions(+), 21 deletions(-) diff --git a/os_net_config/cli.py b/os_net_config/cli.py index 955bb6f..c3a6358 100644 --- a/os_net_config/cli.py +++ b/os_net_config/cli.py @@ -67,6 +67,13 @@ def parse_opts(argv): help="Return the configuration commands, without applying them.", required=False) + parser.add_argument( + '--no-activate', + dest="no_activate", + action='store_true', + help="Install the configuration but don't start/stop interfaces.", + required=False) + parser.add_argument( '--cleanup', dest="cleanup", @@ -161,7 +168,8 @@ def main(argv=sys.argv): iface_json.update({'persist_mapping': persist_mapping}) obj = objects.object_from_json(iface_json) provider.add_object(obj) - files_changed = provider.apply(cleanup=opts.cleanup) + files_changed = provider.apply(cleanup=opts.cleanup, + activate=not opts.no_activate) if opts.noop: for location, data in files_changed.iteritems(): print "File: %s\n" % location diff --git a/os_net_config/impl_eni.py b/os_net_config/impl_eni.py index 5f46f33..3115e04 100644 --- a/os_net_config/impl_eni.py +++ b/os_net_config/impl_eni.py @@ -187,9 +187,14 @@ class ENINetConfig(os_net_config.NetConfig): self.routes[interface_name] = data logger.debug('route data: %s' % self.routes[interface_name]) - def apply(self, cleanup=False): + def apply(self, cleanup=False, activate=True): """Apply the network configuration. + :param cleanup: A boolean which indicates whether any undefined + (existing but not present in the object model) interface + should be disabled and deleted. + :param activate: A boolean which indicates if the config should + be activated by stopping/starting interfaces :returns: a dict of the format: filename/data which contains info for each file that was changed (or would be changed if in --noop mode). @@ -210,19 +215,21 @@ class ENINetConfig(os_net_config.NetConfig): new_config += iface_data if (utils.diff(_network_config_path(), new_config)): - for interface in self.interfaces.keys(): - self.ifdown(interface) + if activate: + for interface in self.interfaces.keys(): + self.ifdown(interface) - for bridge in self.bridges.keys(): - self.ifdown(bridge, iftype='bridge') + for bridge in self.bridges.keys(): + self.ifdown(bridge, iftype='bridge') self.write_config(_network_config_path(), new_config) - for bridge in self.bridges.keys(): - self.ifup(bridge, iftype='bridge') + if activate: + for bridge in self.bridges.keys(): + self.ifup(bridge, iftype='bridge') - for interface in self.interfaces.keys(): - self.ifup(interface) + for interface in self.interfaces.keys(): + self.ifup(interface) else: logger.info('No interface changes are required.') diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py index 100edeb..78433d8 100644 --- a/os_net_config/impl_ifcfg.py +++ b/os_net_config/impl_ifcfg.py @@ -208,12 +208,16 @@ class IfcfgNetConfig(os_net_config.NetConfig): if bond.routes: self._add_routes(bond.name, bond.routes) - def apply(self, cleanup=False): + def apply(self, cleanup=False, activate=True): """Apply the network configuration. :param cleanup: A boolean which indicates whether any undefined (existing but not present in the object model) interface should be disabled and deleted. + :param activate: A boolean which indicates if the config should + be activated by stopping/starting interfaces + NOTE: if cleanup is specified we will deactivate interfaces even + if activate is false :returns: a dict of the format: filename/data which contains info for each file that was changed (or would be changed if in --noop mode). @@ -264,19 +268,21 @@ class IfcfgNetConfig(os_net_config.NetConfig): self.ifdown(interface_name) self.remove_config(ifcfg_file) - for interface in restart_interfaces: - self.ifdown(interface) + if activate: + for interface in restart_interfaces: + self.ifdown(interface) - for bridge in restart_bridges: - self.ifdown(bridge, iftype='bridge') + for bridge in restart_bridges: + self.ifdown(bridge, iftype='bridge') for location, data in update_files.iteritems(): self.write_config(location, data) - for bridge in restart_bridges: - self.ifup(bridge, iftype='bridge') + if activate: + for bridge in restart_bridges: + self.ifup(bridge, iftype='bridge') - for interface in restart_interfaces: - self.ifup(interface) + for interface in restart_interfaces: + self.ifup(interface) return update_files diff --git a/os_net_config/tests/test_impl_eni.py b/os_net_config/tests/test_impl_eni.py index 9322017..e5a712e 100644 --- a/os_net_config/tests/test_impl_eni.py +++ b/os_net_config/tests/test_impl_eni.py @@ -207,13 +207,17 @@ class TestENINetConfigApply(base.TestCase): def setUp(self): super(TestENINetConfigApply, self).setUp() self.temp_config_file = tempfile.NamedTemporaryFile() + self.ifup_interface_names = [] def test_config_path(): return self.temp_config_file.name self.stubs.Set(impl_eni, '_network_config_path', test_config_path) def test_execute(*args, **kwargs): + if args[0] == '/sbin/ifup': + self.ifup_interface_names.append(args[1]) pass + self.stubs.Set(processutils, 'execute', test_execute) self.provider = impl_eni.ENINetConfig() @@ -232,6 +236,19 @@ class TestENINetConfigApply(base.TestCase): self.provider.apply() iface_data = utils.get_file_data(self.temp_config_file.name) self.assertEqual((_V4_IFACE_STATIC_IP + _RTS), iface_data) + self.assertIn('eth0', self.ifup_interface_names) + + def test_apply_noactivate(self): + route = objects.Route('192.168.1.1', '172.19.0.0/24') + v4_addr = objects.Address('192.168.1.2/24') + interface = objects.Interface('eth0', addresses=[v4_addr], + routes=[route]) + self.provider.add_interface(interface) + + self.provider.apply(activate=False) + iface_data = utils.get_file_data(self.temp_config_file.name) + self.assertEqual((_V4_IFACE_STATIC_IP + _RTS), iface_data) + self.assertEqual([], self.ifup_interface_names) def test_dhcp_ovs_bridge_network_apply(self): interface = objects.Interface('eth0') @@ -242,3 +259,5 @@ class TestENINetConfigApply(base.TestCase): self.provider.apply() iface_data = utils.get_file_data(self.temp_config_file.name) self.assertEqual((_OVS_BRIDGE_DHCP + _OVS_PORT_IFACE), iface_data) + self.assertIn('eth0', self.ifup_interface_names) + self.assertIn('br0', self.ifup_interface_names) diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py index 02a5cb4..3930709 100644 --- a/os_net_config/tests/test_impl_ifcfg.py +++ b/os_net_config/tests/test_impl_ifcfg.py @@ -328,6 +328,15 @@ class TestIfcfgNetConfigApply(base.TestCase): route_data = utils.get_file_data(self.temp_route_file.name) self.assertEqual("", route_data) + def test_apply_noactivate(self): + interface = objects.Interface('em1') + bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, + members=[interface]) + self.provider.add_interface(interface) + self.provider.add_bridge(bridge) + self.provider.apply(activate=False) + self.assertEqual([], self.ifup_interface_names) + def test_restart_children_on_change(self): # setup and apply a bridge interface = objects.Interface('em1') @@ -336,6 +345,8 @@ class TestIfcfgNetConfigApply(base.TestCase): self.provider.add_interface(interface) self.provider.add_bridge(bridge) self.provider.apply() + self.assertIn('em1', self.ifup_interface_names) + self.assertIn('br-ctlplane', self.ifup_interface_names) # changing the bridge should restart the interface too self.ifup_interface_names = [] @@ -344,8 +355,6 @@ class TestIfcfgNetConfigApply(base.TestCase): self.provider.add_interface(interface) self.provider.add_bridge(bridge) self.provider.apply() - self.assertIn('em1', self.ifup_interface_names) - self.assertIn('br-ctlplane', self.ifup_interface_names) # setup and apply a bond on a bridge self.ifup_interface_names = [] -- cgit 1.2.3-korg