summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md11
-rw-r--r--google_compute_engine/instance_setup/instance_config.py2
-rwxr-xr-xgoogle_compute_engine/network_setup/network_setup.py43
-rw-r--r--google_compute_engine/network_setup/tests/network_setup_test.py89
-rw-r--r--google_compute_engine/network_utils.py18
-rw-r--r--google_compute_engine/tests/network_utils_test.py20
6 files changed, 97 insertions, 86 deletions
diff --git a/README.md b/README.md
index 603df3d..17925a2 100644
--- a/README.md
+++ b/README.md
@@ -136,13 +136,8 @@ The library provides the following functions:
A network utilities library retrieves information about a network interface. The
library is used for IP forwarding and for setting up an Ethernet interface on
-boot.
-
-The library exposes the following functions:
-
-* **GetNetworkInterface** retrieves the network interface name associated
- with a MAC address.
-* **IsEnabled** checks whether a network interface is enabled.
+boot. The library exposes a `GetNetworkInterface` function that retrieves the
+network interface name associated with a MAC address.
## Daemons
@@ -249,7 +244,7 @@ InstanceSetup | set_multiqueue | `false` skips multiqueue driver suppo
IpForwarding | ethernet_proto_id | Protocol ID string for daemon added routes.
MetadataScripts | startup | `false` disables startup script execution.
MetadataScripts | shutdown | `false` disables shutdown script execution.
-NetworkInterfaces | dhcp_binary | DHCP binary string that enables a network interface parameter.
+NetworkInterfaces | dhcp_command | String to execute to enable network interfaces.
NetworkInterfaces | setup | `false` disables network interface setup.
Setting `network_enabled` to `false` will skip setting up host keys and the
diff --git a/google_compute_engine/instance_setup/instance_config.py b/google_compute_engine/instance_setup/instance_config.py
index 9d37875..f13351b 100644
--- a/google_compute_engine/instance_setup/instance_config.py
+++ b/google_compute_engine/instance_setup/instance_config.py
@@ -67,7 +67,7 @@ class InstanceConfig(config_manager.ConfigManager):
},
'NetworkInterfaces': {
'setup': 'true',
- 'dhcp_binary': 'dhclient',
+ 'dhcp_command': '',
},
}
diff --git a/google_compute_engine/network_setup/network_setup.py b/google_compute_engine/network_setup/network_setup.py
index 4c6e3a7..52c6399 100755
--- a/google_compute_engine/network_setup/network_setup.py
+++ b/google_compute_engine/network_setup/network_setup.py
@@ -30,14 +30,14 @@ class NetworkSetup(object):
network_interfaces = 'instance/network-interfaces'
- def __init__(self, dhcp_binary=None, debug=False):
+ def __init__(self, dhcp_command=None, debug=False):
"""Constructor.
Args:
- dhcp_binary: string, an executable to enable an Ethernet interface.
+ dhcp_command: string, a command to enable Ethernet interfaces.
debug: bool, True if debug output should write to the console.
"""
- self.dhcp_binary = dhcp_binary or 'dhclient'
+ self.dhcp_command = dhcp_command
facility = logging.handlers.SysLogHandler.LOG_DAEMON
self.logger = logger.Logger(
name='network-setup', debug=debug, facility=facility)
@@ -45,36 +45,47 @@ class NetworkSetup(object):
self.network_utils = network_utils.NetworkUtils(logger=self.logger)
self._SetupNetworkInterfaces()
- def _EnableNetworkInterface(self, interface):
- """Enable the network interface.
+ def _EnableNetworkInterfaces(self, interfaces):
+ """Enable the list of network interfaces.
Args:
- interface: string, the output device to enable.
+ interface: list of string, the output devices to enable.
"""
- if self.network_utils.IsEnabled(interface):
- return
-
- command = [self.dhcp_binary, interface]
try:
- self.logger.info('Enabling the Ethernet interface %s.', interface)
- subprocess.check_call(command)
+ self.logger.info('Enabling the Ethernet interface %s.', interfaces)
+ subprocess.check_call(['dhclient', '-r'] + interfaces)
+ subprocess.check_call(['dhclient'] + interfaces)
except subprocess.CalledProcessError:
- self.logger.warning('Could not enable the interface %s.', interface)
+ self.logger.warning('Could not enable interfaces %s.', interfaces)
def _SetupNetworkInterfaces(self):
"""Get network interfaces metadata and enable each Ethernet interface."""
result = self.watcher.GetMetadata(
metadata_key=self.network_interfaces, recursive=True)
+ interfaces = []
for network_interface in result:
mac_address = network_interface.get('mac')
interface = self.network_utils.GetNetworkInterface(mac_address)
if interface:
- self._EnableNetworkInterface(interface)
+ interfaces.append(interface)
else:
message = 'Network interface not found for MAC address: %s.'
self.logger.warning(message, mac_address)
+ # The default Ethernet interface is enabled by default. Do not attempt to
+ # enable interfaces if only one interface is specified in metadata.
+ if len(interfaces) <= 1:
+ return
+
+ if self.dhcp_command:
+ try:
+ subprocess.check_call([self.dhcp_command])
+ except subprocess.CalledProcessError:
+ self.logger.warning('Could not enable Ethernet interfaces.')
+ else:
+ self._EnableNetworkInterfaces(interfaces)
+
def main():
parser = optparse.OptionParser()
@@ -85,8 +96,8 @@ def main():
instance_config = config_manager.ConfigManager()
if instance_config.GetOptionBool('NetworkInterfaces', 'setup'):
NetworkSetup(
- dhcp_binary=instance_config.GetOptionString(
- 'NetworkInterfaces', 'dhcp_binary'),
+ dhcp_command=instance_config.GetOptionString(
+ 'NetworkInterfaces', 'dhcp_command'),
debug=bool(options.debug))
diff --git a/google_compute_engine/network_setup/tests/network_setup_test.py b/google_compute_engine/network_setup/tests/network_setup_test.py
index 12b2588..4c3f01e 100644
--- a/google_compute_engine/network_setup/tests/network_setup_test.py
+++ b/google_compute_engine/network_setup/tests/network_setup_test.py
@@ -30,14 +30,13 @@ class NetworkSetupTest(unittest.TestCase):
self.mock_ip_forwarding_utils = mock.Mock()
self.mock_network_utils = mock.Mock()
self.metadata_key = 'metadata_key'
- self.dhcp_binary = 'binary'
self.mock_setup = mock.create_autospec(network_setup.NetworkSetup)
self.mock_setup.logger = self.mock_logger
self.mock_setup.watcher = self.mock_watcher
self.mock_setup.network_utils = self.mock_network_utils
self.mock_setup.network_interfaces = self.metadata_key
- self.mock_setup.dhcp_binary = self.dhcp_binary
+ self.mock_setup.dhcp_command = ''
@mock.patch('google_compute_engine.network_setup.network_setup.network_utils')
@mock.patch('google_compute_engine.network_setup.network_setup.metadata_watcher')
@@ -51,7 +50,7 @@ class NetworkSetupTest(unittest.TestCase):
mocks.attach_mock(mock_network_utils, 'network')
with mock.patch.object(
network_setup.NetworkSetup, '_SetupNetworkInterfaces'):
- network_setup.NetworkSetup(dhcp_binary='binary', debug=True)
+ network_setup.NetworkSetup(debug=True)
expected_calls = [
mock.call.logger.Logger(name=mock.ANY, debug=True, facility=mock.ANY),
mock.call.watcher.MetadataWatcher(logger=mock_logger_instance),
@@ -60,30 +59,28 @@ class NetworkSetupTest(unittest.TestCase):
self.assertEqual(mocks.mock_calls, expected_calls)
@mock.patch('google_compute_engine.network_setup.network_setup.subprocess.check_call')
- def testEnableNetworkInterface(self, mock_call):
+ def testEnableNetworkInterfaces(self, mock_call):
mocks = mock.Mock()
mocks.attach_mock(mock_call, 'call')
mocks.attach_mock(self.mock_logger, 'logger')
mocks.attach_mock(self.mock_watcher, 'watcher')
mocks.attach_mock(self.mock_network_utils, 'network')
- mock_call.side_effect = [None, subprocess.CalledProcessError(1, 'Test')]
- self.mock_network_utils.IsEnabled.side_effect = [True, False, False]
+ mock_call.side_effect = [
+ None, None, subprocess.CalledProcessError(1, 'Test')]
- network_setup.NetworkSetup._EnableNetworkInterface(self.mock_setup, 'a')
- network_setup.NetworkSetup._EnableNetworkInterface(self.mock_setup, 'b')
- network_setup.NetworkSetup._EnableNetworkInterface(self.mock_setup, 'c')
+ network_setup.NetworkSetup._EnableNetworkInterfaces(
+ self.mock_setup, ['a', 'b', 'c'])
+ network_setup.NetworkSetup._EnableNetworkInterfaces(
+ self.mock_setup, [])
expected_calls = [
- # The network interface is already enabled.
- mock.call.network.IsEnabled('a'),
# Successfully enable the network interface.
- mock.call.network.IsEnabled('b'),
- mock.call.logger.info(mock.ANY, 'b'),
- mock.call.call([self.dhcp_binary, 'b']),
+ mock.call.logger.info(mock.ANY, ['a', 'b', 'c']),
+ mock.call.call(['dhclient', '-r', 'a', 'b', 'c']),
+ mock.call.call(['dhclient', 'a', 'b', 'c']),
# Exception while enabling the network interface.
- mock.call.network.IsEnabled('c'),
- mock.call.logger.info(mock.ANY, 'c'),
- mock.call.call([self.dhcp_binary, 'c']),
- mock.call.logger.warning(mock.ANY, 'c'),
+ mock.call.logger.info(mock.ANY, []),
+ mock.call.call(['dhclient', '-r']),
+ mock.call.logger.warning(mock.ANY, []),
]
self.assertEqual(mocks.mock_calls, expected_calls)
@@ -94,21 +91,67 @@ class NetworkSetupTest(unittest.TestCase):
mocks.attach_mock(self.mock_network_utils, 'network')
mocks.attach_mock(self.mock_setup, 'setup')
self.mock_watcher.GetMetadata.return_value = [
- {'mac': '1'}, {'mac': '2'}, {}]
+ {'mac': '1'}, {'mac': '2'}, {'mac': '3'}, {}]
self.mock_network_utils.GetNetworkInterface.side_effect = [
- 'eth0', None, None]
+ 'eth0', 'eth1', None, None]
with mock.patch.object(
- network_setup.NetworkSetup, '_EnableNetworkInterface'):
+ network_setup.NetworkSetup, '_EnableNetworkInterfaces'):
network_setup.NetworkSetup._SetupNetworkInterfaces(self.mock_setup)
expected_calls = [
mock.call.watcher.GetMetadata(
metadata_key=self.metadata_key, recursive=True),
mock.call.network.GetNetworkInterface('1'),
- mock.call.setup._EnableNetworkInterface('eth0'),
mock.call.network.GetNetworkInterface('2'),
- mock.call.logger.warning(mock.ANY, '2'),
+ mock.call.network.GetNetworkInterface('3'),
+ mock.call.logger.warning(mock.ANY, '3'),
mock.call.network.GetNetworkInterface(None),
mock.call.logger.warning(mock.ANY, None),
+ mock.call.setup._EnableNetworkInterfaces(['eth0', 'eth1']),
+ ]
+ self.assertEqual(mocks.mock_calls, expected_calls)
+
+ def testSetupNetworkInterfacesSkip(self):
+ mocks = mock.Mock()
+ mocks.attach_mock(self.mock_logger, 'logger')
+ mocks.attach_mock(self.mock_watcher, 'watcher')
+ mocks.attach_mock(self.mock_network_utils, 'network')
+ mocks.attach_mock(self.mock_setup, 'setup')
+ self.mock_watcher.GetMetadata.return_value = [{'mac': '1'}]
+
+ with mock.patch.object(
+ network_setup.NetworkSetup, '_EnableNetworkInterfaces'):
+ network_setup.NetworkSetup._SetupNetworkInterfaces(self.mock_setup)
+ expected_calls = [
+ mock.call.watcher.GetMetadata(
+ metadata_key=self.metadata_key, recursive=True),
+ mock.call.network.GetNetworkInterface('1'),
+ ]
+ self.assertEqual(mocks.mock_calls, expected_calls)
+
+ @mock.patch('google_compute_engine.network_setup.network_setup.subprocess.check_call')
+ def testSetupNetworkInterfacesCommand(self, mock_call):
+ mocks = mock.Mock()
+ mocks.attach_mock(mock_call, 'call')
+ mocks.attach_mock(self.mock_logger, 'logger')
+ mocks.attach_mock(self.mock_watcher, 'watcher')
+ mocks.attach_mock(self.mock_network_utils, 'network')
+ mocks.attach_mock(self.mock_setup, 'setup')
+ self.mock_watcher.GetMetadata.return_value = [
+ {'mac': '1'}, {'mac': '2'}]
+ self.mock_network_utils.GetNetworkInterface.side_effect = ['eth0', 'eth1']
+ mock_call.side_effect = subprocess.CalledProcessError(1, 'Test')
+
+ with mock.patch.object(
+ network_setup.NetworkSetup, '_EnableNetworkInterfaces'):
+ self.mock_setup.dhcp_command = 'command'
+ network_setup.NetworkSetup._SetupNetworkInterfaces(self.mock_setup)
+ expected_calls = [
+ mock.call.watcher.GetMetadata(
+ metadata_key=self.metadata_key, recursive=True),
+ mock.call.network.GetNetworkInterface('1'),
+ mock.call.network.GetNetworkInterface('2'),
+ mock.call.call(['command']),
+ mock.call.logger.warning(mock.ANY),
]
self.assertEqual(mocks.mock_calls, expected_calls)
diff --git a/google_compute_engine/network_utils.py b/google_compute_engine/network_utils.py
index 3c94deb..3ed36bb 100644
--- a/google_compute_engine/network_utils.py
+++ b/google_compute_engine/network_utils.py
@@ -59,21 +59,3 @@ class NetworkUtils(object):
string, the network interface associated with a MAC address or None.
"""
return self.interfaces.get(mac_address)
-
- def IsEnabled(self, interface):
- """Check whether a network interface is enabled.
-
- Args:
- interface: string, the network interface.
-
- Returns:
- bool, True if the network interface is enabled.
- """
- try:
- state = open('/sys/class/net/%s/operstate' % interface).read().strip()
- except (IOError, OSError) as e:
- message = 'Unable to determine the state for %s. %s.'
- self.logger.warning(message, interface, str(e))
- return False
- else:
- return 'up' == state
diff --git a/google_compute_engine/tests/network_utils_test.py b/google_compute_engine/tests/network_utils_test.py
index 1c0cb7c..60386b3 100644
--- a/google_compute_engine/tests/network_utils_test.py
+++ b/google_compute_engine/tests/network_utils_test.py
@@ -64,23 +64,3 @@ class NetworkUtilsTest(unittest.TestCase):
self.assertIsNone(self.mock_utils.GetNetworkInterface('invalid'))
self.assertEqual(
self.mock_utils.GetNetworkInterface('address'), 'interface')
-
- def testIsEnabled(self):
- mock_open = mock.mock_open()
-
- with mock.patch('%s.open' % builtin, mock_open, create=False):
- mock_open().read.side_effect = ['up', 'down', 'up\n', '', 'Garbage']
- self.assertEqual(self.mock_utils.IsEnabled('a'), True)
- self.assertEqual(self.mock_utils.IsEnabled('a'), False)
- self.assertEqual(self.mock_utils.IsEnabled('a'), True)
- self.assertEqual(self.mock_utils.IsEnabled('a'), False)
- self.assertEqual(self.mock_utils.IsEnabled('a'), False)
-
- def testIsEnabledError(self):
- mock_open = mock.mock_open()
-
- with mock.patch('%s.open' % builtin, mock_open, create=False):
- mock_open().read.side_effect = [OSError('OSError')]
- self.assertEqual(self.mock_utils.IsEnabled('a'), False)
- self.mock_logger.warning.assert_called_once_with(
- mock.ANY, 'a', 'OSError'),