summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--os_net_config/__init__.py5
-rw-r--r--os_net_config/cli.py9
-rw-r--r--os_net_config/impl_eni.py2
-rw-r--r--os_net_config/impl_ifcfg.py45
-rw-r--r--os_net_config/tests/test_impl_ifcfg.py12
5 files changed, 61 insertions, 12 deletions
diff --git a/os_net_config/__init__.py b/os_net_config/__init__.py
index bd28bbc..9e451f2 100644
--- a/os_net_config/__init__.py
+++ b/os_net_config/__init__.py
@@ -56,10 +56,13 @@ class NetConfig(object):
def add_bond(self, bond):
raise NotImplemented("add_bond is not implemented.")
- def apply(self, noop=False):
+ def apply(self, noop=False, cleanup=False):
"""Apply the network configuration.
:param noop: A boolean which indicates whether this is a no-op.
+ :param cleanup: A boolean which indicates whether any undefined
+ (existing but not present in the object model) interfaces
+ should be disabled and deleted.
: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).
diff --git a/os_net_config/cli.py b/os_net_config/cli.py
index 0efc399..5b6ff1d 100644
--- a/os_net_config/cli.py
+++ b/os_net_config/cli.py
@@ -64,6 +64,13 @@ def parse_opts(argv):
help="Return the configuration commands, without applying them.",
required=False)
+ parser.add_argument(
+ '--cleanup',
+ dest="cleanup",
+ action='store_true',
+ help="Cleanup unconfigured interfaces.",
+ required=False)
+
opts = parser.parse_args(argv[1:])
return opts
@@ -122,7 +129,7 @@ def main(argv=sys.argv):
for iface_json in iface_array:
obj = objects.object_from_json(iface_json)
provider.addObject(obj)
- files_changed = provider.apply(noop=opts.noop)
+ files_changed = provider.apply(noop=opts.noop, cleanup=opts.cleanup)
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 cf09ff3..2a2e4e1 100644
--- a/os_net_config/impl_eni.py
+++ b/os_net_config/impl_eni.py
@@ -164,7 +164,7 @@ class ENINetConfig(os_net_config.NetConfig):
self.routes[interface_name] = data
logger.debug('route data: %s' % self.routes[interface_name])
- def apply(self, noop=False):
+ def apply(self, noop=False, cleanup=False):
"""Apply the network configuration.
:param noop: A boolean which indicates whether this is a no-op.
diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py
index bd1cf22..4125017 100644
--- a/os_net_config/impl_ifcfg.py
+++ b/os_net_config/impl_ifcfg.py
@@ -14,7 +14,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+import glob
import logging
+import os
import os_net_config
from os_net_config import objects
@@ -40,6 +42,10 @@ def route_config_path(name):
return "/etc/sysconfig/network-scripts/route-%s" % name
+def cleanup_pattern():
+ return "/etc/sysconfig/network-scripts/ifcfg-*"
+
+
class IfcfgNetConfig(os_net_config.NetConfig):
"""Configure network interfaces using the ifcfg format."""
@@ -166,10 +172,13 @@ class IfcfgNetConfig(os_net_config.NetConfig):
if bond.routes:
self._add_routes(bond.name, bond.routes)
- def apply(self, noop=False):
+ def apply(self, noop=False, cleanup=False):
"""Apply the network configuration.
:param noop: A boolean which indicates whether this is a no-op.
+ :param cleanup: A boolean which indicates whether any undefined
+ (existing but not present in the object model) interfaces
+ should be disabled and deleted.
: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).
@@ -178,29 +187,47 @@ class IfcfgNetConfig(os_net_config.NetConfig):
restart_interfaces = []
restart_bridges = []
update_files = {}
+ all_file_names = []
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
- utils.diff(route_config_path(interface_name), route_data)):
+ interface_path = ifcfg_config_path(interface_name)
+ route_path = route_config_path(interface_name)
+ all_file_names.append(interface_path)
+ all_file_names.append(route_path)
+ if (utils.diff(interface_path, iface_data) or
+ utils.diff(route_path, route_data)):
restart_interfaces.append(interface_name)
- update_files[ifcfg_config_path(interface_name)] = iface_data
- update_files[route_config_path(interface_name)] = route_data
+ update_files[interface_path] = iface_data
+ update_files[route_path] = route_data
logger.info('No changes required for interface: %s' %
interface_name)
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)):
+ bridge_path = bridge_config_path(bridge_name)
+ bridge_route_path = route_config_path(bridge_name)
+ all_file_names.append(bridge_path)
+ all_file_names.append(bridge_route_path)
+ if (utils.diff(bridge_path, bridge_data) or
+ utils.diff(bridge_route_path, 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
+ update_files[bridge_path] = bridge_data
+ update_files[bridge_route_path] = route_data
logger.info('No changes required for bridge: %s' % bridge_name)
if noop:
return update_files
+ if cleanup:
+ for ifcfg_file in glob.iglob(cleanup_pattern()):
+ if ifcfg_file not in all_file_names:
+ interface_name = ifcfg_file[37:]
+ logger.info('cleaning up interface: %s' % interface_name)
+ processutils.execute('/sbin/ifdown', interface_name,
+ check_exit_code=False)
+ os.remove(ifcfg_file)
+
for interface in restart_interfaces:
logger.info('running ifdown on interface: %s' % interface)
processutils.execute('/sbin/ifdown', interface,
diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py
index aee34d3..a5c621c 100644
--- a/os_net_config/tests/test_impl_ifcfg.py
+++ b/os_net_config/tests/test_impl_ifcfg.py
@@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os.path
import tempfile
from os_net_config import impl_ifcfg
@@ -220,6 +221,7 @@ class TestIfcfgNetConfigApply(base.TestCase):
self.temp_ifcfg_file = tempfile.NamedTemporaryFile()
self.temp_route_file = tempfile.NamedTemporaryFile()
self.temp_bridge_file = tempfile.NamedTemporaryFile()
+ self.temp_cleanup_file = tempfile.NamedTemporaryFile()
def test_ifcfg_path(name):
return self.temp_ifcfg_file.name
@@ -233,6 +235,10 @@ class TestIfcfgNetConfigApply(base.TestCase):
return self.temp_bridge_file.name
self.stubs.Set(impl_ifcfg, 'bridge_config_path', test_bridge_path)
+ def test_cleanup_pattern():
+ return self.temp_cleanup_file.name
+ self.stubs.Set(impl_ifcfg, 'cleanup_pattern', test_cleanup_pattern)
+
def test_execute(*args, **kwargs):
pass
self.stubs.Set(processutils, 'execute', test_execute)
@@ -243,6 +249,8 @@ class TestIfcfgNetConfigApply(base.TestCase):
self.temp_ifcfg_file.close()
self.temp_route_file.close()
self.temp_bridge_file.close()
+ if os.path.exists(self.temp_cleanup_file.name):
+ self.temp_cleanup_file.close()
super(TestIfcfgNetConfigApply, self).tearDown()
def test_network_apply(self):
@@ -282,3 +290,7 @@ class TestIfcfgNetConfigApply(base.TestCase):
ifcfg_data = utils.get_file_data(self.temp_ifcfg_file.name)
self.assertEqual(_VLAN_NO_IP, ifcfg_data)
+
+ def test_cleanup(self):
+ self.provider.apply(cleanup=True)
+ self.assertTrue(not os.path.exists(self.temp_cleanup_file.name))