summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorScott Moser <smoser@brickies.net>2017-03-03 02:26:38 -0500
committerScott Moser <smoser@brickies.net>2017-03-03 02:26:38 -0500
commitd7004bcf269fe60e456de336ecda9a9d2fe50bfd (patch)
treecf49b1fbc06388d46fa435814d24d97c83476047 /tests
parent1de8720effd029727bb5ef7972e7e4d859a1b53a (diff)
parentc81ea53bbdc4ada9d2b52430e106aeb3c38b4e0a (diff)
downloadvyos-cloud-init-d7004bcf269fe60e456de336ecda9a9d2fe50bfd.tar.gz
vyos-cloud-init-d7004bcf269fe60e456de336ecda9a9d2fe50bfd.zip
merge from master at 0.7.9-47-gc81ea53
Diffstat (limited to 'tests')
-rw-r--r--tests/unittests/helpers.py74
-rw-r--r--tests/unittests/test__init__.py92
-rw-r--r--tests/unittests/test_atomic_helper.py4
-rw-r--r--tests/unittests/test_data.py53
-rw-r--r--tests/unittests/test_datasource/test_gce.py4
-rw-r--r--tests/unittests/test_datasource/test_openstack.py11
-rw-r--r--[-rwxr-xr-x]tests/unittests/test_distros/test_user_data_normalize.py0
-rw-r--r--tests/unittests/test_ec2_util.py49
-rw-r--r--[-rwxr-xr-x]tests/unittests/test_net.py184
-rw-r--r--tests/unittests/test_sshutil.py24
10 files changed, 341 insertions, 154 deletions
diff --git a/tests/unittests/helpers.py b/tests/unittests/helpers.py
index cf3b46d2..90e2431f 100644
--- a/tests/unittests/helpers.py
+++ b/tests/unittests/helpers.py
@@ -29,7 +29,6 @@ PY2 = False
PY26 = False
PY27 = False
PY3 = False
-FIX_HTTPRETTY = False
_PY_VER = sys.version_info
_PY_MAJOR, _PY_MINOR, _PY_MICRO = _PY_VER[0:3]
@@ -44,8 +43,6 @@ else:
PY2 = True
if (_PY_MAJOR, _PY_MINOR) >= (3, 0):
PY3 = True
- if _PY_MINOR == 4 and _PY_MICRO < 3:
- FIX_HTTPRETTY = True
# Makes the old path start
@@ -86,6 +83,28 @@ class TestCase(unittest2.TestCase):
pass
+class CiTestCase(TestCase):
+ """This is the preferred test case base class unless user
+ needs other test case classes below."""
+ def tmp_dir(self, dir=None, cleanup=True):
+ # return a full path to a temporary directory that will be cleaned up.
+ if dir is None:
+ tmpd = tempfile.mkdtemp(
+ prefix="ci-%s." % self.__class__.__name__)
+ else:
+ tmpd = tempfile.mkdtemp(dir=dir)
+ self.addCleanup(functools.partial(shutil.rmtree, tmpd))
+ return tmpd
+
+ def tmp_path(self, path, dir=None):
+ # return an absolute path to 'path' under dir.
+ # if dir is None, one will be created with tmp_dir()
+ # the file is not created or modified.
+ if dir is None:
+ dir = self.tmp_dir()
+ return os.path.normpath(os.path.abspath(os.path.join(dir, path)))
+
+
class ResourceUsingTestCase(TestCase):
def setUp(self):
super(ResourceUsingTestCase, self).setUp()
@@ -216,37 +235,6 @@ class FilesystemMockingTestCase(ResourceUsingTestCase):
return root
-def import_httpretty():
- """Import HTTPretty and monkey patch Python 3.4 issue.
- See https://github.com/gabrielfalcao/HTTPretty/pull/193 and
- as well as https://github.com/gabrielfalcao/HTTPretty/issues/221.
-
- Lifted from
- https://github.com/inveniosoftware/datacite/blob/master/tests/helpers.py
- """
- if not FIX_HTTPRETTY:
- import httpretty
- else:
- import socket
- old_SocketType = socket.SocketType
-
- import httpretty
- from httpretty import core
-
- def sockettype_patch(f):
- @functools.wraps(f)
- def inner(*args, **kwargs):
- f(*args, **kwargs)
- socket.SocketType = old_SocketType
- socket.__dict__['SocketType'] = old_SocketType
- return inner
-
- core.httpretty.disable = sockettype_patch(
- httpretty.httpretty.disable
- )
- return httpretty
-
-
class HttprettyTestCase(TestCase):
# necessary as http_proxy gets in the way of httpretty
# https://github.com/gabrielfalcao/HTTPretty/issues/122
@@ -262,23 +250,10 @@ class HttprettyTestCase(TestCase):
super(HttprettyTestCase, self).tearDown()
-class TempDirTestCase(TestCase):
- # provide a tempdir per class, not per test.
- def setUp(self):
- super(TempDirTestCase, self).setUp()
- self.tmp = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, self.tmp)
-
- def tmp_path(self, path):
- if path.startswith(os.path.sep):
- path = "." + path
-
- return os.path.normpath(os.path.join(self.tmp, path))
-
-
def populate_dir(path, files):
if not os.path.exists(path):
os.makedirs(path)
+ ret = []
for (name, content) in files.items():
p = os.path.join(path, name)
util.ensure_dir(os.path.dirname(p))
@@ -288,6 +263,9 @@ def populate_dir(path, files):
else:
fp.write(content.encode('utf-8'))
fp.close()
+ ret.append(p)
+
+ return ret
def dir2dict(startdir, prefix=None):
diff --git a/tests/unittests/test__init__.py b/tests/unittests/test__init__.py
index 7b6f8c4e..781f6d54 100644
--- a/tests/unittests/test__init__.py
+++ b/tests/unittests/test__init__.py
@@ -1,16 +1,18 @@
# This file is part of cloud-init. See LICENSE file for license information.
+import logging
import os
import shutil
import tempfile
+from cloudinit.cmd import main
from cloudinit import handlers
from cloudinit import helpers
from cloudinit import settings
from cloudinit import url_helper
from cloudinit import util
-from .helpers import TestCase, ExitStack, mock
+from .helpers import TestCase, CiTestCase, ExitStack, mock
class FakeModule(handlers.Handler):
@@ -170,44 +172,68 @@ class TestHandlerHandlePart(TestCase):
self.data, self.ctype, self.filename, self.payload)
-class TestCmdlineUrl(TestCase):
- def test_invalid_content(self):
- url = "http://example.com/foo"
- key = "mykey"
- payload = b"0"
- cmdline = "ro %s=%s bar=1" % (key, url)
+class TestCmdlineUrl(CiTestCase):
+ def test_parse_cmdline_url_nokey_raises_keyerror(self):
+ self.assertRaises(
+ KeyError, main.parse_cmdline_url, 'root=foo bar single')
- with mock.patch('cloudinit.url_helper.readurl',
- return_value=url_helper.StringResponse(payload)):
- self.assertEqual(
- util.get_cmdline_url(names=[key], starts="xxxxxx",
- cmdline=cmdline),
- (key, url, None))
+ def test_parse_cmdline_url_found(self):
+ cmdline = 'root=foo bar single url=http://example.com arg1 -v'
+ self.assertEqual(
+ ('url', 'http://example.com'), main.parse_cmdline_url(cmdline))
- def test_valid_content(self):
- url = "http://example.com/foo"
- key = "mykey"
- payload = b"xcloud-config\nmydata: foo\nbar: wark\n"
+ @mock.patch('cloudinit.cmd.main.util.read_file_or_url')
+ def test_invalid_content(self, m_read):
+ key = "cloud-config-url"
+ url = 'http://example.com/foo'
cmdline = "ro %s=%s bar=1" % (key, url)
+ m_read.return_value = url_helper.StringResponse(b"unexpected blob")
- with mock.patch('cloudinit.url_helper.readurl',
- return_value=url_helper.StringResponse(payload)):
- self.assertEqual(
- util.get_cmdline_url(names=[key], starts=b"xcloud-config",
- cmdline=cmdline),
- (key, url, payload))
+ fpath = self.tmp_path("ccfile")
+ lvl, msg = main.attempt_cmdline_url(
+ fpath, network=True, cmdline=cmdline)
+ self.assertEqual(logging.WARN, lvl)
+ self.assertIn(url, msg)
+ self.assertFalse(os.path.exists(fpath))
- def test_no_key_found(self):
+ @mock.patch('cloudinit.cmd.main.util.read_file_or_url')
+ def test_valid_content(self, m_read):
url = "http://example.com/foo"
- key = "mykey"
- cmdline = "ro %s=%s bar=1" % (key, url)
-
- with mock.patch('cloudinit.url_helper.readurl',
- return_value=url_helper.StringResponse(b'')):
- self.assertEqual(
- util.get_cmdline_url(names=["does-not-appear"],
- starts="#cloud-config", cmdline=cmdline),
- (None, None, None))
+ payload = b"#cloud-config\nmydata: foo\nbar: wark\n"
+ cmdline = "ro %s=%s bar=1" % ('cloud-config-url', url)
+
+ m_read.return_value = url_helper.StringResponse(payload)
+ fpath = self.tmp_path("ccfile")
+ lvl, msg = main.attempt_cmdline_url(
+ fpath, network=True, cmdline=cmdline)
+ self.assertEqual(util.load_file(fpath, decode=False), payload)
+ self.assertEqual(logging.INFO, lvl)
+ self.assertIn(url, msg)
+
+ @mock.patch('cloudinit.cmd.main.util.read_file_or_url')
+ def test_no_key_found(self, m_read):
+ cmdline = "ro mykey=http://example.com/foo root=foo"
+ fpath = self.tmp_path("ccpath")
+ lvl, msg = main.attempt_cmdline_url(
+ fpath, network=True, cmdline=cmdline)
+
+ m_read.assert_not_called()
+ self.assertFalse(os.path.exists(fpath))
+ self.assertEqual(logging.DEBUG, lvl)
+
+ @mock.patch('cloudinit.cmd.main.util.read_file_or_url')
+ def test_exception_warns(self, m_read):
+ url = "http://example.com/foo"
+ cmdline = "ro cloud-config-url=%s root=LABEL=bar" % url
+ fpath = self.tmp_path("ccfile")
+ m_read.side_effect = url_helper.UrlError(
+ cause="Unexpected Error", url="http://example.com/foo")
+
+ lvl, msg = main.attempt_cmdline_url(
+ fpath, network=True, cmdline=cmdline)
+ self.assertEqual(logging.WARN, lvl)
+ self.assertIn(url, msg)
+ self.assertFalse(os.path.exists(fpath))
# vi: ts=4 expandtab
diff --git a/tests/unittests/test_atomic_helper.py b/tests/unittests/test_atomic_helper.py
index e170c7c3..515919d8 100644
--- a/tests/unittests/test_atomic_helper.py
+++ b/tests/unittests/test_atomic_helper.py
@@ -6,10 +6,10 @@ import stat
from cloudinit import atomic_helper
-from . import helpers
+from .helpers import CiTestCase
-class TestAtomicHelper(helpers.TempDirTestCase):
+class TestAtomicHelper(CiTestCase):
def test_basic_usage(self):
"""write_file takes bytes if no omode."""
path = self.tmp_path("test_basic_usage")
diff --git a/tests/unittests/test_data.py b/tests/unittests/test_data.py
index 4092d9ca..4ad86bb6 100644
--- a/tests/unittests/test_data.py
+++ b/tests/unittests/test_data.py
@@ -564,12 +564,12 @@ class TestConvertString(helpers.TestCase):
class TestFetchBaseConfig(helpers.TestCase):
-
- def test_only_builtin_gets_builtin2(self):
+ def test_only_builtin_gets_builtin(self):
ret = helpers.wrap_and_call(
- 'cloudinit.stages.util',
- {'read_conf_with_confd': None,
- 'read_conf_from_cmdline': None},
+ 'cloudinit.stages',
+ {'util.read_conf_with_confd': None,
+ 'util.read_conf_from_cmdline': None,
+ 'read_runtime_config': {'return_value': {}}},
stages.fetch_base_config)
self.assertEqual(util.get_builtin_cfg(), ret)
@@ -578,9 +578,11 @@ class TestFetchBaseConfig(helpers.TestCase):
test_key = sorted(builtin)[0]
test_value = 'test'
ret = helpers.wrap_and_call(
- 'cloudinit.stages.util',
- {'read_conf_with_confd': {'return_value': {test_key: test_value}},
- 'read_conf_from_cmdline': None},
+ 'cloudinit.stages',
+ {'util.read_conf_with_confd':
+ {'return_value': {test_key: test_value}},
+ 'util.read_conf_from_cmdline': None,
+ 'read_runtime_config': {'return_value': {}}},
stages.fetch_base_config)
self.assertEqual(ret.get(test_key), test_value)
builtin[test_key] = test_value
@@ -592,25 +594,44 @@ class TestFetchBaseConfig(helpers.TestCase):
test_value = 'test'
cmdline = {test_key: test_value}
ret = helpers.wrap_and_call(
- 'cloudinit.stages.util',
- {'read_conf_from_cmdline': {'return_value': cmdline},
- 'read_conf_with_confd': None},
+ 'cloudinit.stages',
+ {'util.read_conf_from_cmdline': {'return_value': cmdline},
+ 'util.read_conf_with_confd': None,
+ 'read_runtime_config': None},
stages.fetch_base_config)
self.assertEqual(ret.get(test_key), test_value)
builtin[test_key] = test_value
self.assertEqual(ret, builtin)
- def test_cmdline_overrides_conf_d_and_defaults(self):
+ def test_cmdline_overrides_confd_runtime_and_defaults(self):
builtin = {'key1': 'value0', 'key3': 'other2'}
conf_d = {'key1': 'value1', 'key2': 'other1'}
cmdline = {'key3': 'other3', 'key2': 'other2'}
+ runtime = {'key3': 'runtime3'}
ret = helpers.wrap_and_call(
- 'cloudinit.stages.util',
- {'read_conf_with_confd': {'return_value': conf_d},
- 'get_builtin_cfg': {'return_value': builtin},
- 'read_conf_from_cmdline': {'return_value': cmdline}},
+ 'cloudinit.stages',
+ {'util.read_conf_with_confd': {'return_value': conf_d},
+ 'util.get_builtin_cfg': {'return_value': builtin},
+ 'read_runtime_config': {'return_value': runtime},
+ 'util.read_conf_from_cmdline': {'return_value': cmdline}},
stages.fetch_base_config)
self.assertEqual(ret, {'key1': 'value1', 'key2': 'other2',
'key3': 'other3'})
+ def test_order_precedence_is_builtin_system_runtime_cmdline(self):
+ builtin = {'key1': 'builtin0', 'key3': 'builtin3'}
+ conf_d = {'key1': 'confd1', 'key2': 'confd2', 'keyconfd1': 'kconfd1'}
+ runtime = {'key1': 'runtime1', 'key2': 'runtime2'}
+ cmdline = {'key1': 'cmdline1'}
+ ret = helpers.wrap_and_call(
+ 'cloudinit.stages',
+ {'util.read_conf_with_confd': {'return_value': conf_d},
+ 'util.get_builtin_cfg': {'return_value': builtin},
+ 'util.read_conf_from_cmdline': {'return_value': cmdline},
+ 'read_runtime_config': {'return_value': runtime},
+ },
+ stages.fetch_base_config)
+ self.assertEqual(ret, {'key1': 'cmdline1', 'key2': 'runtime2',
+ 'key3': 'builtin3', 'keyconfd1': 'kconfd1'})
+
# vi: ts=4 expandtab
diff --git a/tests/unittests/test_datasource/test_gce.py b/tests/unittests/test_datasource/test_gce.py
index 4f667678..4f83454e 100644
--- a/tests/unittests/test_datasource/test_gce.py
+++ b/tests/unittests/test_datasource/test_gce.py
@@ -4,6 +4,7 @@
#
# This file is part of cloud-init. See LICENSE file for license information.
+import httpretty
import re
from base64 import b64encode, b64decode
@@ -15,7 +16,6 @@ from cloudinit.sources import DataSourceGCE
from .. import helpers as test_helpers
-httpretty = test_helpers.import_httpretty()
GCE_META = {
'instance/id': '123',
@@ -59,6 +59,8 @@ def _set_mock_metadata(gce_meta=None):
else:
return (404, headers, '')
+ # reset is needed. https://github.com/gabrielfalcao/HTTPretty/issues/316
+ httpretty.reset()
httpretty.register_uri(httpretty.GET, MD_URL_RE, body=_request_callback)
diff --git a/tests/unittests/test_datasource/test_openstack.py b/tests/unittests/test_datasource/test_openstack.py
index e5b6fcc6..7bf55084 100644
--- a/tests/unittests/test_datasource/test_openstack.py
+++ b/tests/unittests/test_datasource/test_openstack.py
@@ -5,6 +5,7 @@
# This file is part of cloud-init. See LICENSE file for license information.
import copy
+import httpretty as hp
import json
import re
@@ -20,8 +21,6 @@ from cloudinit.sources import DataSourceOpenStack as ds
from cloudinit.sources.helpers import openstack
from cloudinit import util
-hp = test_helpers.import_httpretty()
-
BASE_URL = "http://169.254.169.254"
PUBKEY = u'ssh-rsa AAAAB3NzaC1....sIkJhq8wdX+4I3A4cYbYP ubuntu@server-460\n'
EC2_META = {
@@ -232,7 +231,7 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
None,
helpers.Paths({}))
self.assertIsNone(ds_os.version)
- found = ds_os.get_data(timeout=0.1, retries=0)
+ found = ds_os.get_data()
self.assertTrue(found)
self.assertEqual(2, ds_os.version)
md = dict(ds_os.metadata)
@@ -256,7 +255,7 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
None,
helpers.Paths({}))
self.assertIsNone(ds_os.version)
- found = ds_os.get_data(timeout=0.1, retries=0)
+ found = ds_os.get_data()
self.assertFalse(found)
self.assertIsNone(ds_os.version)
@@ -275,7 +274,7 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
'timeout': 0,
}
self.assertIsNone(ds_os.version)
- found = ds_os.get_data(timeout=0.1, retries=0)
+ found = ds_os.get_data()
self.assertFalse(found)
self.assertIsNone(ds_os.version)
@@ -298,7 +297,7 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
'timeout': 0,
}
self.assertIsNone(ds_os.version)
- found = ds_os.get_data(timeout=0.1, retries=0)
+ found = ds_os.get_data()
self.assertFalse(found)
self.assertIsNone(ds_os.version)
diff --git a/tests/unittests/test_distros/test_user_data_normalize.py b/tests/unittests/test_distros/test_user_data_normalize.py
index 88746e0a..88746e0a 100755..100644
--- a/tests/unittests/test_distros/test_user_data_normalize.py
+++ b/tests/unittests/test_distros/test_user_data_normalize.py
diff --git a/tests/unittests/test_ec2_util.py b/tests/unittests/test_ec2_util.py
index 4a33d747..65fdb519 100644
--- a/tests/unittests/test_ec2_util.py
+++ b/tests/unittests/test_ec2_util.py
@@ -1,12 +1,12 @@
# This file is part of cloud-init. See LICENSE file for license information.
+import httpretty as hp
+
from . import helpers
from cloudinit import ec2_utils as eu
from cloudinit import url_helper as uh
-hp = helpers.import_httpretty()
-
class TestEc2Util(helpers.HttprettyTestCase):
VERSION = 'latest'
@@ -140,4 +140,49 @@ class TestEc2Util(helpers.HttprettyTestCase):
self.assertEqual(bdm['ami'], 'sdb')
self.assertEqual(bdm['ephemeral0'], 'sdc')
+ @hp.activate
+ def test_metadata_no_security_credentials(self):
+ base_url = 'http://169.254.169.254/%s/meta-data/' % (self.VERSION)
+ hp.register_uri(hp.GET, base_url, status=200,
+ body="\n".join(['instance-id',
+ 'iam/']))
+ hp.register_uri(hp.GET, uh.combine_url(base_url, 'instance-id'),
+ status=200, body='i-0123451689abcdef0')
+ hp.register_uri(hp.GET,
+ uh.combine_url(base_url, 'iam/'),
+ status=200,
+ body="\n".join(['info/', 'security-credentials/']))
+ hp.register_uri(hp.GET,
+ uh.combine_url(base_url, 'iam/info/'),
+ status=200,
+ body='LastUpdated')
+ hp.register_uri(hp.GET,
+ uh.combine_url(base_url, 'iam/info/LastUpdated'),
+ status=200, body='2016-10-27T17:29:39Z')
+ hp.register_uri(hp.GET,
+ uh.combine_url(base_url, 'iam/security-credentials/'),
+ status=200,
+ body='ReadOnly/')
+ hp.register_uri(hp.GET,
+ uh.combine_url(base_url,
+ 'iam/security-credentials/ReadOnly/'),
+ status=200,
+ body="\n".join(['LastUpdated', 'Expiration']))
+ hp.register_uri(hp.GET,
+ uh.combine_url(
+ base_url,
+ 'iam/security-credentials/ReadOnly/LastUpdated'),
+ status=200, body='2016-10-27T17:28:17Z')
+ hp.register_uri(hp.GET,
+ uh.combine_url(
+ base_url,
+ 'iam/security-credentials/ReadOnly/Expiration'),
+ status=200, body='2016-10-28T00:00:34Z')
+ md = eu.get_instance_metadata(self.VERSION, retries=0, timeout=0.1)
+ self.assertEqual(md['instance-id'], 'i-0123451689abcdef0')
+ iam = md['iam']
+ self.assertEqual(1, len(iam))
+ self.assertEqual(iam['info']['LastUpdated'], '2016-10-27T17:29:39Z')
+ self.assertNotIn('security-credentials', iam)
+
# vi: ts=4 expandtab
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 1090282a..4b03ff72 100755..100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -8,11 +8,10 @@ from cloudinit.net import sysconfig
from cloudinit.sources.helpers import openstack
from cloudinit import util
+from .helpers import CiTestCase
from .helpers import dir2dict
from .helpers import mock
from .helpers import populate_dir
-from .helpers import TempDirTestCase
-from .helpers import TestCase
import base64
import copy
@@ -20,8 +19,6 @@ import gzip
import io
import json
import os
-import shutil
-import tempfile
import textwrap
import yaml
@@ -166,6 +163,91 @@ nameserver 172.19.0.12
('etc/udev/rules.d/70-persistent-net.rules',
"".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))]
+ },
+ {
+ 'in_data': {
+ "services": [{"type": "dns", "address": "172.19.0.12"}],
+ "networks": [{
+ "network_id": "public-ipv4",
+ "type": "ipv4", "netmask": "255.255.252.0",
+ "link": "tap1a81968a-79",
+ "routes": [{
+ "netmask": "0.0.0.0",
+ "network": "0.0.0.0",
+ "gateway": "172.19.3.254",
+ }],
+ "ip_address": "172.19.1.34", "id": "network0"
+ }, {
+ "network_id": "private-ipv4",
+ "type": "ipv4", "netmask": "255.255.255.0",
+ "link": "tap1a81968a-79",
+ "routes": [],
+ "ip_address": "10.0.0.10", "id": "network1"
+ }],
+ "links": [
+ {
+ "ethernet_mac_address": "fa:16:3e:ed:9a:59",
+ "mtu": None, "type": "bridge", "id":
+ "tap1a81968a-79",
+ "vif_id": "1a81968a-797a-400f-8a80-567f997eb93f"
+ },
+ ],
+ },
+ 'in_macs': {
+ 'fa:16:3e:ed:9a:59': 'eth0',
+ },
+ 'out_sysconfig': [
+ ('etc/sysconfig/network-scripts/ifcfg-eth0',
+ """
+# Created by cloud-init on instance boot automatically, do not edit.
+#
+BOOTPROTO=none
+DEVICE=eth0
+HWADDR=fa:16:3e:ed:9a:59
+NM_CONTROLLED=no
+ONBOOT=yes
+TYPE=Ethernet
+USERCTL=no
+""".lstrip()),
+ ('etc/sysconfig/network-scripts/ifcfg-eth0:0',
+ """
+# Created by cloud-init on instance boot automatically, do not edit.
+#
+BOOTPROTO=static
+DEFROUTE=yes
+DEVICE=eth0:0
+GATEWAY=172.19.3.254
+HWADDR=fa:16:3e:ed:9a:59
+IPADDR=172.19.1.34
+NETMASK=255.255.252.0
+NM_CONTROLLED=no
+ONBOOT=yes
+TYPE=Ethernet
+USERCTL=no
+""".lstrip()),
+ ('etc/sysconfig/network-scripts/ifcfg-eth0:1',
+ """
+# Created by cloud-init on instance boot automatically, do not edit.
+#
+BOOTPROTO=static
+DEVICE=eth0:1
+HWADDR=fa:16:3e:ed:9a:59
+IPADDR=10.0.0.10
+NETMASK=255.255.255.0
+NM_CONTROLLED=no
+ONBOOT=yes
+TYPE=Ethernet
+USERCTL=no
+""".lstrip()),
+ ('etc/resolv.conf',
+ """
+; Created by cloud-init on instance boot automatically, do not edit.
+;
+nameserver 172.19.0.12
+""".lstrip()),
+ ('etc/udev/rules.d/70-persistent-net.rules',
+ "".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
+ 'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))]
}
]
@@ -222,11 +304,9 @@ NETWORK_CONFIGS = {
auto eth99
iface eth99 inet dhcp
- post-up ifup eth99:1
-
- auto eth99:1
- iface eth99:1 inet static
+ # control-alias eth99
+ iface eth99 inet static
address 192.168.21.3/24
dns-nameservers 8.8.8.8 8.8.4.4
dns-search barley.maas sach.maas
@@ -264,6 +344,27 @@ NETWORK_CONFIGS = {
- wark.maas
"""),
},
+ 'v4_and_v6': {
+ 'expected_eni': textwrap.dedent("""\
+ auto lo
+ iface lo inet loopback
+
+ auto iface0
+ iface iface0 inet dhcp
+
+ # control-alias iface0
+ iface iface0 inet6 dhcp
+ """).rstrip(' '),
+ 'yaml': textwrap.dedent("""\
+ version: 1
+ config:
+ - type: 'physical'
+ name: 'iface0'
+ subnets:
+ - {'type': 'dhcp4'}
+ - {'type': 'dhcp6'}
+ """).rstrip(' '),
+ },
'all': {
'expected_eni': ("""\
auto lo
@@ -301,11 +402,9 @@ iface br0 inet static
address 192.168.14.2/24
bridge_ports eth3 eth4
bridge_stp off
- post-up ifup br0:1
-
-auto br0:1
-iface br0:1 inet6 static
+# control-alias br0
+iface br0 inet6 static
address 2001:1::1/64
auto bond0.200
@@ -322,11 +421,9 @@ iface eth0.101 inet static
mtu 1500
vlan-raw-device eth0
vlan_id 101
- post-up ifup eth0.101:1
-
-auto eth0.101:1
-iface eth0.101:1 inet static
+# control-alias eth0.101
+iface eth0.101 inet static
address 192.168.2.10/24
post-up route add -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true
@@ -478,7 +575,7 @@ def _setup_test(tmp_dir, mock_get_devicelist, mock_read_sys_net,
mock_sys_dev_path.side_effect = sys_dev_path
-class TestSysConfigRendering(TestCase):
+class TestSysConfigRendering(CiTestCase):
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@@ -486,8 +583,7 @@ class TestSysConfigRendering(TestCase):
def test_default_generation(self, mock_get_devicelist,
mock_read_sys_net,
mock_sys_dev_path):
- tmp_dir = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, tmp_dir)
+ tmp_dir = self.tmp_dir()
_setup_test(tmp_dir, mock_get_devicelist,
mock_read_sys_net, mock_sys_dev_path)
@@ -518,10 +614,8 @@ USERCTL=no
self.assertEqual(expected_content, content)
def test_openstack_rendering_samples(self):
- tmp_dir = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, tmp_dir)
- render_dir = os.path.join(tmp_dir, "render")
for os_sample in OS_SAMPLES:
+ render_dir = self.tmp_dir()
ex_input = os_sample['in_data']
ex_mac_addrs = os_sample['in_macs']
network_cfg = openstack.convert_net_json(
@@ -535,7 +629,7 @@ USERCTL=no
self.assertEqual(expected_content, fh.read())
-class TestEniNetRendering(TestCase):
+class TestEniNetRendering(CiTestCase):
@mock.patch("cloudinit.net.sys_dev_path")
@mock.patch("cloudinit.net.read_sys_net")
@@ -543,8 +637,7 @@ class TestEniNetRendering(TestCase):
def test_default_generation(self, mock_get_devicelist,
mock_read_sys_net,
mock_sys_dev_path):
- tmp_dir = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, tmp_dir)
+ tmp_dir = self.tmp_dir()
_setup_test(tmp_dir, mock_get_devicelist,
mock_read_sys_net, mock_sys_dev_path)
@@ -576,7 +669,7 @@ iface eth1000 inet dhcp
self.assertEqual(expected.lstrip(), contents.lstrip())
-class TestEniNetworkStateToEni(TestCase):
+class TestEniNetworkStateToEni(CiTestCase):
mycfg = {
'config': [{"type": "physical", "name": "eth0",
"mac_address": "c0:d6:9f:2c:e8:80",
@@ -607,7 +700,7 @@ class TestEniNetworkStateToEni(TestCase):
self.assertNotIn("hwaddress", rendered)
-class TestCmdlineConfigParsing(TestCase):
+class TestCmdlineConfigParsing(CiTestCase):
simple_cfg = {
'config': [{"type": "physical", "name": "eth0",
"mac_address": "c0:d6:9f:2c:e8:80",
@@ -665,7 +758,7 @@ class TestCmdlineConfigParsing(TestCase):
self.assertEqual(found, self.simple_cfg)
-class TestCmdlineReadKernelConfig(TempDirTestCase):
+class TestCmdlineReadKernelConfig(CiTestCase):
macs = {
'eth0': '14:02:ec:42:48:00',
'eno1': '14:02:ec:42:48:01',
@@ -673,8 +766,7 @@ class TestCmdlineReadKernelConfig(TempDirTestCase):
def test_ip_cmdline_read_kernel_cmdline_ip(self):
content = {'net-eth0.conf': DHCP_CONTENT_1}
- populate_dir(self.tmp, content)
- files = [os.path.join(self.tmp, k) for k in content.keys()]
+ files = sorted(populate_dir(self.tmp_dir(), content))
found = cmdline.read_kernel_cmdline_config(
files=files, cmdline='foo ip=dhcp', mac_addrs=self.macs)
exp1 = copy.deepcopy(DHCP_EXPECTED_1)
@@ -684,8 +776,7 @@ class TestCmdlineReadKernelConfig(TempDirTestCase):
def test_ip_cmdline_read_kernel_cmdline_ip6(self):
content = {'net6-eno1.conf': DHCP6_CONTENT_1}
- populate_dir(self.tmp, content)
- files = [os.path.join(self.tmp, k) for k in content.keys()]
+ files = sorted(populate_dir(self.tmp_dir(), content))
found = cmdline.read_kernel_cmdline_config(
files=files, cmdline='foo ip6=dhcp root=/dev/sda',
mac_addrs=self.macs)
@@ -701,8 +792,7 @@ class TestCmdlineReadKernelConfig(TempDirTestCase):
def test_ip_cmdline_read_kernel_cmdline_none(self):
# if there is no ip= or ip6= on cmdline, return value should be None
content = {'net6-eno1.conf': DHCP6_CONTENT_1}
- populate_dir(self.tmp, content)
- files = [os.path.join(self.tmp, k) for k in content.keys()]
+ files = sorted(populate_dir(self.tmp_dir(), content))
found = cmdline.read_kernel_cmdline_config(
files=files, cmdline='foo root=/dev/sda', mac_addrs=self.macs)
self.assertEqual(found, None)
@@ -710,8 +800,7 @@ class TestCmdlineReadKernelConfig(TempDirTestCase):
def test_ip_cmdline_both_ip_ip6(self):
content = {'net-eth0.conf': DHCP_CONTENT_1,
'net6-eth0.conf': DHCP6_CONTENT_1.replace('eno1', 'eth0')}
- populate_dir(self.tmp, content)
- files = [os.path.join(self.tmp, k) for k in sorted(content.keys())]
+ files = sorted(populate_dir(self.tmp_dir(), content))
found = cmdline.read_kernel_cmdline_config(
files=files, cmdline='foo ip=dhcp ip6=dhcp', mac_addrs=self.macs)
@@ -725,14 +814,12 @@ class TestCmdlineReadKernelConfig(TempDirTestCase):
self.assertEqual(found['config'], expected)
-class TestEniRoundTrip(TestCase):
- def setUp(self):
- super(TestCase, self).setUp()
- self.tmp_dir = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, self.tmp_dir)
-
+class TestEniRoundTrip(CiTestCase):
def _render_and_read(self, network_config=None, state=None, eni_path=None,
- links_prefix=None, netrules_path=None):
+ links_prefix=None, netrules_path=None, dir=None):
+ if dir is None:
+ dir = self.tmp_dir()
+
if network_config:
ns = network_state.parse_net_config_data(network_config)
elif state:
@@ -747,8 +834,8 @@ class TestEniRoundTrip(TestCase):
config={'eni_path': eni_path, 'links_path_prefix': links_prefix,
'netrules_path': netrules_path})
- renderer.render_network_state(self.tmp_dir, ns)
- return dir2dict(self.tmp_dir)
+ renderer.render_network_state(dir, ns)
+ return dir2dict(dir)
def testsimple_convert_and_render(self):
network_config = eni.convert_eni_data(EXAMPLE_ENI)
@@ -771,6 +858,13 @@ class TestEniRoundTrip(TestCase):
entry['expected_eni'].splitlines(),
files['/etc/network/interfaces'].splitlines())
+ def testsimple_render_v4_and_v6(self):
+ entry = NETWORK_CONFIGS['v4_and_v6']
+ files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+ self.assertEqual(
+ entry['expected_eni'].splitlines(),
+ files['/etc/network/interfaces'].splitlines())
+
def test_routes_rendered(self):
# as reported in bug 1649652
conf = [
diff --git a/tests/unittests/test_sshutil.py b/tests/unittests/test_sshutil.py
index 55971b5e..991f45a6 100644
--- a/tests/unittests/test_sshutil.py
+++ b/tests/unittests/test_sshutil.py
@@ -32,6 +32,22 @@ VALID_CONTENT = {
"YWpMfYdPUnE7u536WqzFmsaqJctz3gBxH9Ex7dFtrxR4qiqEr9Qtlu3xGn7Bw07"
"/+i1D+ey3ONkZLN+LQ714cgj8fRS4Hj29SCmXp5Kt5/82cD/VN3NtHw=="
),
+ 'ecdsa-sha2-nistp256': (
+ "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMy/WuXq5MF"
+ "r5hVQ9EEKKUTF7vUaOkgxUh6bNsCs9SFMVslIm1zM/WJYwUv52LdEePjtDYiV4A"
+ "l2XthJ9/bs7Pc="
+ ),
+ 'ecdsa-sha2-nistp521': (
+ "AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBABOdNTkh9F"
+ "McK4hZRLs5LTXBEXwNr0+Yg9uvJYRFcz2ZlnjYX9tM4Z3QQFjqogU4pU+zpKLqZ"
+ "5VE4Jcnb1T608UywBIdXkSFZT8trGJqBv9nFWGgmTX3KP8kiBbihpuv1cGwglPl"
+ "Hxs50A42iP0JiT7auGtEAGsu/uMql323GTGb4171Q=="
+ ),
+ 'ecdsa-sha2-nistp384': (
+ "AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBAnoqFU9Gnl"
+ "LcsEuCJnobs/c6whzvjCgouaOO61kgXNtIxyF4Wkutg6xaGYgBBt/phb7a2TurI"
+ "bcIBuzJ/mP22UyUAbNnBfStAEBmYbrTf1EfiMCYUAr1XnL0UdYmZ8HFg=="
+ ),
}
TEST_OPTIONS = (
@@ -44,7 +60,13 @@ class TestAuthKeyLineParser(test_helpers.TestCase):
def test_simple_parse(self):
# test key line with common 3 fields (keytype, base64, comment)
parser = ssh_util.AuthKeyLineParser()
- for ktype in ['rsa', 'ecdsa', 'dsa']:
+ ecdsa_types = [
+ 'ecdsa-sha2-nistp256',
+ 'ecdsa-sha2-nistp384',
+ 'ecdsa-sha2-nistp521',
+ ]
+
+ for ktype in ['rsa', 'ecdsa', 'dsa'] + ecdsa_types:
content = VALID_CONTENT[ktype]
comment = 'user-%s@host' % ktype
line = ' '.join((ktype, content, comment,))