summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloudinit/net/dhcp.py42
-rw-r--r--cloudinit/net/network_state.py2
-rw-r--r--cloudinit/net/tests/test_dhcp.py65
-rw-r--r--cloudinit/net/tests/test_network_state.py47
-rw-r--r--doc-requirements.txt3
-rw-r--r--doc/rtd/index.rst1
-rw-r--r--doc/rtd/topics/bugs.rst108
7 files changed, 259 insertions, 9 deletions
diff --git a/cloudinit/net/dhcp.py b/cloudinit/net/dhcp.py
index 17379918..c033cc8e 100644
--- a/cloudinit/net/dhcp.py
+++ b/cloudinit/net/dhcp.py
@@ -92,9 +92,12 @@ class EphemeralDHCPv4(object):
nmap = {'interface': 'interface', 'ip': 'fixed-address',
'prefix_or_mask': 'subnet-mask',
'broadcast': 'broadcast-address',
- 'static_routes': 'rfc3442-classless-static-routes',
+ 'static_routes': [
+ 'rfc3442-classless-static-routes',
+ 'classless-static-routes'
+ ],
'router': 'routers'}
- kwargs = dict([(k, self.lease.get(v)) for k, v in nmap.items()])
+ kwargs = self.extract_dhcp_options_mapping(nmap)
if not kwargs['broadcast']:
kwargs['broadcast'] = bcip(kwargs['prefix_or_mask'], kwargs['ip'])
if kwargs['static_routes']:
@@ -107,6 +110,25 @@ class EphemeralDHCPv4(object):
self._ephipv4 = ephipv4
return self.lease
+ def extract_dhcp_options_mapping(self, nmap):
+ result = {}
+ for internal_reference, lease_option_names in nmap.items():
+ if isinstance(lease_option_names, list):
+ self.get_first_option_value(
+ internal_reference,
+ lease_option_names,
+ result
+ )
+ else:
+ result[internal_reference] = self.lease.get(lease_option_names)
+ return result
+
+ def get_first_option_value(self, internal_mapping,
+ lease_option_names, result):
+ for different_names in lease_option_names:
+ if not result.get(internal_mapping):
+ result[internal_mapping] = self.lease.get(different_names)
+
def maybe_perform_dhcp_discovery(nic=None):
"""Perform dhcp discovery if nic valid and dhclient command exists.
@@ -281,24 +303,30 @@ def parse_static_routes(rfc3442):
""" parse rfc3442 format and return a list containing tuple of strings.
The tuple is composed of the network_address (including net length) and
- gateway for a parsed static route.
+ gateway for a parsed static route. It can parse two formats of rfc3442,
+ one from dhcpcd and one from dhclient (isc).
- @param rfc3442: string in rfc3442 format
+ @param rfc3442: string in rfc3442 format (isc or dhcpd)
@returns: list of tuple(str, str) for all valid parsed routes until the
first parsing error.
E.g.
- sr = parse_state_routes("32,169,254,169,254,130,56,248,255,0,130,56,240,1")
- sr = [
+ sr=parse_static_routes("32,169,254,169,254,130,56,248,255,0,130,56,240,1")
+ sr=[
("169.254.169.254/32", "130.56.248.255"), ("0.0.0.0/0", "130.56.240.1")
]
+ sr2 = parse_static_routes("24.191.168.128 192.168.128.1,0 192.168.128.1")
+ sr2 = [
+ ("191.168.128.0/24", "192.168.128.1"), ("0.0.0.0/0", "192.168.128.1")
+ ]
+
Python version of isc-dhclient's hooks:
/etc/dhcp/dhclient-exit-hooks.d/rfc3442-classless-routes
"""
# raw strings from dhcp lease may end in semi-colon
rfc3442 = rfc3442.rstrip(";")
- tokens = rfc3442.split(',')
+ tokens = [tok for tok in re.split(r"[, .]", rfc3442) if tok]
static_routes = []
def _trunc_error(cidr, required, remain):
diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py
index 7d206a1a..f3e8e250 100644
--- a/cloudinit/net/network_state.py
+++ b/cloudinit/net/network_state.py
@@ -73,7 +73,7 @@ def parse_net_config_data(net_config, skip_broken=True):
# pass the whole net-config as-is
config = net_config
- if version and config:
+ if version and config is not None:
nsi = NetworkStateInterpreter(version=version, config=config)
nsi.parse_config(skip_broken=skip_broken)
state = nsi.get_network_state()
diff --git a/cloudinit/net/tests/test_dhcp.py b/cloudinit/net/tests/test_dhcp.py
index 91f503c9..c3fa1e04 100644
--- a/cloudinit/net/tests/test_dhcp.py
+++ b/cloudinit/net/tests/test_dhcp.py
@@ -90,6 +90,32 @@ class TestDHCPRFC3442(CiTestCase):
write_file(lease_file, content)
self.assertItemsEqual(expected, parse_dhcp_lease_file(lease_file))
+ def test_parse_lease_finds_classless_static_routes(self):
+ """
+ parse_dhcp_lease_file returns classless-static-routes
+ for Centos lease format.
+ """
+ lease_file = self.tmp_path('leases')
+ content = dedent("""
+ lease {
+ interface "wlp3s0";
+ fixed-address 192.168.2.74;
+ option subnet-mask 255.255.255.0;
+ option routers 192.168.2.1;
+ option classless-static-routes 0 130.56.240.1;
+ renew 4 2017/07/27 18:02:30;
+ expire 5 2017/07/28 07:08:15;
+ }
+ """)
+ expected = [
+ {'interface': 'wlp3s0', 'fixed-address': '192.168.2.74',
+ 'subnet-mask': '255.255.255.0', 'routers': '192.168.2.1',
+ 'classless-static-routes': '0 130.56.240.1',
+ 'renew': '4 2017/07/27 18:02:30',
+ 'expire': '5 2017/07/28 07:08:15'}]
+ write_file(lease_file, content)
+ self.assertItemsEqual(expected, parse_dhcp_lease_file(lease_file))
+
@mock.patch('cloudinit.net.dhcp.EphemeralIPv4Network')
@mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery')
def test_obtain_lease_parses_static_routes(self, m_maybe, m_ipv4):
@@ -112,6 +138,31 @@ class TestDHCPRFC3442(CiTestCase):
'router': '192.168.2.1'}
m_ipv4.assert_called_with(**expected_kwargs)
+ @mock.patch('cloudinit.net.dhcp.EphemeralIPv4Network')
+ @mock.patch('cloudinit.net.dhcp.maybe_perform_dhcp_discovery')
+ def test_obtain_centos_lease_parses_static_routes(self, m_maybe, m_ipv4):
+ """
+ EphemeralDHPCv4 parses rfc3442 routes for EphemeralIPv4Network
+ for Centos Lease format
+ """
+ lease = [
+ {'interface': 'wlp3s0', 'fixed-address': '192.168.2.74',
+ 'subnet-mask': '255.255.255.0', 'routers': '192.168.2.1',
+ 'classless-static-routes': '0 130.56.240.1',
+ 'renew': '4 2017/07/27 18:02:30',
+ 'expire': '5 2017/07/28 07:08:15'}]
+ m_maybe.return_value = lease
+ eph = net.dhcp.EphemeralDHCPv4()
+ eph.obtain_lease()
+ expected_kwargs = {
+ 'interface': 'wlp3s0',
+ 'ip': '192.168.2.74',
+ 'prefix_or_mask': '255.255.255.0',
+ 'broadcast': '192.168.2.255',
+ 'static_routes': [('0.0.0.0/0', '130.56.240.1')],
+ 'router': '192.168.2.1'}
+ m_ipv4.assert_called_with(**expected_kwargs)
+
class TestDHCPParseStaticRoutes(CiTestCase):
@@ -181,6 +232,20 @@ class TestDHCPParseStaticRoutes(CiTestCase):
logs = self.logs.getvalue()
self.assertIn(rfc3442, logs.splitlines()[0])
+ def test_redhat_format(self):
+ redhat_format = "24.191.168.128 192.168.128.1,0 192.168.128.1"
+ self.assertEqual(sorted([
+ ("191.168.128.0/24", "192.168.128.1"),
+ ("0.0.0.0/0", "192.168.128.1")
+ ]), sorted(parse_static_routes(redhat_format)))
+
+ def test_redhat_format_with_a_space_too_much_after_comma(self):
+ redhat_format = "24.191.168.128 192.168.128.1, 0 192.168.128.1"
+ self.assertEqual(sorted([
+ ("191.168.128.0/24", "192.168.128.1"),
+ ("0.0.0.0/0", "192.168.128.1")
+ ]), sorted(parse_static_routes(redhat_format)))
+
class TestDHCPDiscoveryClean(CiTestCase):
with_logs = True
diff --git a/cloudinit/net/tests/test_network_state.py b/cloudinit/net/tests/test_network_state.py
new file mode 100644
index 00000000..fcb4a995
--- /dev/null
+++ b/cloudinit/net/tests/test_network_state.py
@@ -0,0 +1,47 @@
+# This file is part of cloud-init. See LICENSE file for license information.
+
+import mock
+from cloudinit.net import network_state
+from cloudinit.tests.helpers import CiTestCase
+
+netstate_path = 'cloudinit.net.network_state'
+
+
+class TestNetworkStateParseConfig(CiTestCase):
+
+ def setUp(self):
+ super(TestNetworkStateParseConfig, self).setUp()
+ nsi_path = netstate_path + '.NetworkStateInterpreter'
+ self.add_patch(nsi_path, 'm_nsi')
+
+ def test_missing_version_returns_none(self):
+ ncfg = {}
+ self.assertEqual(None, network_state.parse_net_config_data(ncfg))
+
+ def test_unknown_versions_returns_none(self):
+ ncfg = {'version': 13.2}
+ self.assertEqual(None, network_state.parse_net_config_data(ncfg))
+
+ def test_version_2_passes_self_as_config(self):
+ ncfg = {'version': 2, 'otherconfig': {}, 'somemore': [1, 2, 3]}
+ network_state.parse_net_config_data(ncfg)
+ self.assertEqual([mock.call(version=2, config=ncfg)],
+ self.m_nsi.call_args_list)
+
+ def test_valid_config_gets_network_state(self):
+ ncfg = {'version': 2, 'otherconfig': {}, 'somemore': [1, 2, 3]}
+ result = network_state.parse_net_config_data(ncfg)
+ self.assertNotEqual(None, result)
+
+ def test_empty_v1_config_gets_network_state(self):
+ ncfg = {'version': 1, 'config': []}
+ result = network_state.parse_net_config_data(ncfg)
+ self.assertNotEqual(None, result)
+
+ def test_empty_v2_config_gets_network_state(self):
+ ncfg = {'version': 2}
+ result = network_state.parse_net_config_data(ncfg)
+ self.assertNotEqual(None, result)
+
+
+# vi: ts=4 expandtab
diff --git a/doc-requirements.txt b/doc-requirements.txt
index 2d4ca7be..e8977de9 100644
--- a/doc-requirements.txt
+++ b/doc-requirements.txt
@@ -1,4 +1,5 @@
doc8
m2r
sphinx
-sphinx_rtd_theme \ No newline at end of file
+sphinx_rtd_theme
+pyyaml
diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst
index d2662edf..5d90c131 100644
--- a/doc/rtd/index.rst
+++ b/doc/rtd/index.rst
@@ -40,6 +40,7 @@ Having trouble? We would like to help!
topics/boot.rst
topics/cli.rst
topics/faq.rst
+ topics/bugs.rst
.. toctree::
:hidden:
diff --git a/doc/rtd/topics/bugs.rst b/doc/rtd/topics/bugs.rst
new file mode 100644
index 00000000..4b60776b
--- /dev/null
+++ b/doc/rtd/topics/bugs.rst
@@ -0,0 +1,108 @@
+.. _reporting_bugs:
+
+Reporting Bugs
+**************
+
+The following documents:
+
+1) How to collect information for reporting bugs
+2) How to file bugs to the upstream cloud-init project or for distro specific
+ packages
+
+Collect Logs
+============
+
+To aid in debugging, please collect the necessary logs. To do so, run the
+`collect-logs` subcommand to produce a tarfile that you can easily upload:
+
+.. code-block:: shell-session
+
+ $ cloud-init collect-logs
+ Wrote /home/ubuntu/cloud-init.tar.gz
+
+If your version of cloud-init does not have the `collect-logs` subcommand,
+then please manually collect the base log files by doing the following:
+
+.. code-block:: shell-session
+
+ $ dmesg > dmesg.txt
+ $ sudo journalctl -o short-precise > journal.txt
+ $ sudo tar -cvf cloud-init.tar dmesg.txt journal.txt /run/cloud-init \
+ /var/log/cloud-init.log /var/log/cloud-init-output.log
+
+Report Upstream Bug
+===================
+
+Bugs for upstream cloud-init are tracked using Launchpad. To file a bug:
+
+1. Collect the necessary debug logs as described above
+2. `Create a Launchpad account`_ or login to your existing account
+3. `Report an upstream cloud-init bug`_
+
+If debug logs are not provided, you will be asked for them before any
+further time is spent debugging. If you are unable to obtain the required
+logs please explain why in the bug.
+
+If your bug is for a specific distro using cloud-init, please first consider
+reporting it with the upstream distro or confirm that it still occurs
+with the latest upstream cloud-init code. See below for details on specific
+distro reporting.
+
+Distro Specific Issues
+======================
+
+For issues specific to your distro please use one of the following distro
+specific reporting mechanisms:
+
+Ubuntu
+------
+
+To report a bug on Ubuntu use the `ubuntu-bug` command on the affected
+system to automatically collect the necessary logs and file a bug on
+Launchpad:
+
+.. code-block:: shell-session
+
+ $ ubuntu-bug cloud-init
+
+If that does not work or is not an option, please collect the logs using the
+commands in the above Collect Logs section and then report the bug on the
+`Ubuntu bug tracker`_. Make sure to attach your collected logs!
+
+Debian
+------
+
+To file a bug against the Debian package fo cloud-init please use the
+`Debian bug tracker`_ to file against 'Package: cloud-init'. See the
+`Debian bug reporting wiki`_ wiki page for more details.
+
+Red Hat, CentOS, & Fedora
+-------------------------
+
+To file a bug against the Red Hat or Fedora packages of cloud-init please use
+the `Red Hat bugzilla`_.
+
+SUSE & openSUSE
+---------------
+
+To file a bug against the SuSE packages of cloud-init please use the
+`SUSE bugzilla`_.
+
+Arch
+----
+
+To file a bug against the Arch package of cloud-init please use the
+`Arch Linux Bugtracker`_. See the `Arch bug reporting wiki`_ for more
+details.
+
+.. _Create a Launchpad account: https://help.launchpad.net/YourAccount/NewAccount
+.. _Report an upstream cloud-init bug: https://bugs.launchpad.net/cloud-init/+filebug
+.. _Ubuntu bug tracker: https://bugs.launchpad.net/ubuntu/+source/cloud-init/+filebug
+.. _Debian bug tracker: https://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=cloud-init;dist=unstable
+.. _Debian bug reporting wiki: https://www.debian.org/Bugs/Reporting
+.. _Red Hat bugzilla: https://bugzilla.redhat.com/
+.. _SUSE bugzilla: https://bugzilla.suse.com/index.cgi
+.. _Arch Linux Bugtracker: https://bugs.archlinux.org/
+.. _Arch bug reporting wiki: https://wiki.archlinux.org/index.php/Bug_reporting_guidelines
+
+.. vi: textwidth=79