aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Prince <dprince@redhat.com>2014-06-10 14:01:06 -0400
committerDan Prince <dprince@redhat.com>2014-06-10 14:01:06 -0400
commit86230e11d10a9a605f1eaaf9ab3619875224eb3d (patch)
treecac4dce869f1049b86b576dfb4e034f41e40e784
parent3e1474324568a277bd3d8e493d26021ec3f3767c (diff)
Implement apply for ifcfg implementation
Adds an apply function to the ifcfg implementation which: 1) Shuts down existing interfaces w/ ifdown 2) writes new interfaces config files (routes too) 3) Starts up new interfaces w/ ifup
-rw-r--r--os_net_config/__init__.py5
-rw-r--r--os_net_config/impl_ifcfg.py56
-rw-r--r--os_net_config/objects.py1
-rw-r--r--os_net_config/tests/test_impl_ifcfg.py81
-rw-r--r--os_net_config/utils.py30
-rw-r--r--requirements.txt5
6 files changed, 138 insertions, 40 deletions
diff --git a/os_net_config/__init__.py b/os_net_config/__init__.py
index bdbc69f..27dc95e 100644
--- a/os_net_config/__init__.py
+++ b/os_net_config/__init__.py
@@ -23,7 +23,7 @@ class NotImplemented(Exception):
pass
-class NetworkConfig(object):
+class NetConfig(object):
"""Configure network interfaces using the ifcfg format."""
def addInterface(self, interface):
@@ -31,3 +31,6 @@ class NetworkConfig(object):
def addRoutes(self, interface_name, routes=[]):
raise NotImplemented("addRoutes 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 c4fbde4..c4ea5dd 100644
--- a/os_net_config/impl_ifcfg.py
+++ b/os_net_config/impl_ifcfg.py
@@ -12,6 +12,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os_net_config
+from os_net_config import utils
+
+
+from os_net_config.openstack.common import processutils
+
def ifcfg_config_path(name):
return "/etc/sysconfig/network-scripts/ifcfg-%s" % name
@@ -21,21 +27,7 @@ def route_config_path(name):
return "/etc/sysconfig/network-scripts/route-%s" % name
-def writeConfig(filename, data):
- with open(filename, "w") as f:
- f.write(str(data))
-
-
-def get_config(filename):
- with open(filename, "r") as f:
- return f.read()
-
-
-def diff(filename, data):
- return get_config(filename) == data
-
-
-class IfcfgNetwork(object):
+class IfcfgNetConfig(os_net_config.NetConfig):
"""Configure network interfaces using the ifcfg format."""
def __init__(self):
@@ -78,16 +70,38 @@ class IfcfgNetwork(object):
data += "IPV6ADDR=%s\n" % first_v6.ip
self.interfaces[interface.name] = data
+ if interface.routes:
+ self.addRoutes(interface.name, interface.routes)
def addRoutes(self, interface_name, routes=[]):
data = ""
first_line = ""
for route in routes:
if route.default:
- first_line = "default %s dev %s\n" % (route.next_hop,
- interface_name)
+ first_line = "default via %s dev %s\n" % (route.next_hop,
+ interface_name)
else:
- data += "%s via %s dev %s" % (route.ip_netmask,
- route.next_hop,
- interface_name)
- self.routes[interface_name] == first_line + data
+ data += "%s via %s dev %s\n" % (route.ip_netmask,
+ route.next_hop,
+ interface_name)
+ self.routes[interface_name] = first_line + data
+
+ def apply(self):
+ restart_interfaces = []
+ 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
+ utils.diff(route_config_path(interface_name), 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
+
+ for interface in restart_interfaces:
+ processutils.execute('/sbin/ifdown', interface)
+
+ for location, data in update_files.iteritems():
+ utils.write_config(location, data)
+
+ 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 455e55f..4b6e09e 100644
--- a/os_net_config/objects.py
+++ b/os_net_config/objects.py
@@ -50,6 +50,7 @@ class Interface(object):
self.use_dhcp = use_dhcp
self.use_dhcpv6 = use_dhcpv6
self.addresses = addresses
+ self.routes = routes
self.bridge = None
self.type = None
diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py
index 7a2deec..a383a56 100644
--- a/os_net_config/tests/test_impl_ifcfg.py
+++ b/os_net_config/tests/test_impl_ifcfg.py
@@ -16,16 +16,18 @@ import tempfile
from os_net_config import impl_ifcfg
from os_net_config import objects
+from os_net_config.openstack.common import processutils
from os_net_config.tests import base
+from os_net_config import utils
-_BASE_IFCFG = """DEVICE=foo
+_BASE_IFCFG = """DEVICE=em1
ONBOOT=yes
HOTPLUG=no
"""
_V4_IFCFG = _BASE_IFCFG + """BOOTPROTO=static
-IPADDR=192.168.1.1
+IPADDR=192.168.1.2
NETMASK=255.255.255.0
"""
@@ -40,43 +42,86 @@ _OVS_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\n"
_OVS_BRIDGE_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\n"
-class TestIfcfgNetwork(base.TestCase):
+_ROUTES = """default via 192.168.1.1 dev em1
+172.19.0.0/24 via 192.168.1.1 dev em1
+"""
+
+
+class TestIfcfgNetConfig(base.TestCase):
def setUp(self):
- super(TestIfcfgNetwork, self).setUp()
- self.temp_config_file = tempfile.NamedTemporaryFile()
+ 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_config_path(name):
- return self.temp_config_file.name
- self.stubs.Set(impl_ifcfg, 'ifcfg_config_path', test_config_path)
- self.provider = impl_ifcfg.IfcfgNetwork()
+ 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_config_file.close()
- super(TestIfcfgNetwork, self).tearDown()
+ self.temp_ifcfg_file.close()
+ self.temp_route_file.close()
+ super(TestIfcfgNetConfig, self).tearDown()
def get_interface_config(self):
- return self.provider.interfaces['foo']
+ return self.provider.interfaces['em1']
+
+ def get_route_config(self):
+ return self.provider.routes['em1']
def test_add_base_interface(self):
- interface = objects.Interface('foo')
+ interface = objects.Interface('em1')
self.provider.addInterface(interface)
self.assertEqual(_BASE_IFCFG, self.get_interface_config())
def test_add_ovs_interface(self):
- interface = objects.Interface('foo')
+ interface = objects.Interface('em1')
interface.type = 'ovs'
self.provider.addInterface(interface)
self.assertEqual(_OVS_IFCFG, self.get_interface_config())
def test_add_interface_with_v4(self):
- v4_addr = objects.Address('192.168.1.1/24')
- interface = objects.Interface('foo', addresses=[v4_addr])
+ v4_addr = objects.Address('192.168.1.2/24')
+ interface = objects.Interface('em1', addresses=[v4_addr])
self.provider.addInterface(interface)
self.assertEqual(_V4_IFCFG, self.get_interface_config())
def test_add_interface_with_v6(self):
v6_addr = objects.Address('2001:abc:a::/64')
- interface = objects.Interface('foo', addresses=[v6_addr])
+ interface = objects.Interface('em1', addresses=[v6_addr])
self.provider.addInterface(interface)
- self.assertEqual(_V6_IFCFG, self.get_interface_config())
+
+ def test_network_with_routes(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')
+ interface = objects.Interface('em1', addresses=[v4_addr],
+ routes=[route1, route2])
+ self.provider.addInterface(interface)
+ self.assertEqual(_V4_IFCFG, self.get_interface_config())
+ self.assertEqual(_ROUTES, self.get_route_config())
+
+ def test_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')
+ interface = objects.Interface('em1', addresses=[v4_addr],
+ 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)
diff --git a/os_net_config/utils.py b/os_net_config/utils.py
new file mode 100644
index 0000000..41bc55e
--- /dev/null
+++ b/os_net_config/utils.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+def write_config(filename, data):
+ with open(filename, "w") as f:
+ f.write(str(data))
+
+
+def get_file_data(filename):
+ try:
+ with open(filename, "r") as f:
+ return f.read()
+ except IOError:
+ return ""
+
+
+def diff(filename, data):
+ return not get_file_data(filename) == data
diff --git a/requirements.txt b/requirements.txt
index 8883e46..9719046 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,8 @@
pbr>=0.5.21,<1.0
+anyjson>=0.3.3
Babel>=0.9.6
+six>=1.6.0
+eventlet>=0.13.0
+iso8601>=0.1.9
netaddr>=0.7.6
+oslo.config>=1.2.0