summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorChad Smith <chad.smith@canonical.com>2017-12-05 16:25:11 -0700
committerChad Smith <chad.smith@canonical.com>2017-12-05 16:25:11 -0700
commit30b4d15764a1a9644379cf95770e8b2480856882 (patch)
tree102b18e80e5ff8bf383a7fe35e56f88328cd924a /tests
parent47016791ca5e97d80e45d3f100bc4e5d0b88627d (diff)
downloadvyos-cloud-init-30b4d15764a1a9644379cf95770e8b2480856882.tar.gz
vyos-cloud-init-30b4d15764a1a9644379cf95770e8b2480856882.zip
cli: Add clean and status subcommands
The 'cloud-init clean' command allows a user or script to clear cloud-init artifacts from the system so that cloud-init sees the system as unconfigured upon reboot. Optional parameters can be provided to remove cloud-init logs and reboot after clean. The 'cloud-init status' command allows the user or script to check whether cloud-init has finished all configuration stages and whether errors occurred. An optional --wait argument will poll on a 0.25 second interval until cloud-init configuration is complete. The benefit here is scripts can block on cloud-init completion before performing post-config tasks.
Diffstat (limited to 'tests')
-rw-r--r--tests/unittests/test_cli.py30
-rw-r--r--tests/unittests/test_util.py38
2 files changed, 62 insertions, 6 deletions
diff --git a/tests/unittests/test_cli.py b/tests/unittests/test_cli.py
index fccbbd23..a8d28ae6 100644
--- a/tests/unittests/test_cli.py
+++ b/tests/unittests/test_cli.py
@@ -2,9 +2,9 @@
import six
+from cloudinit.cmd import main as cli
from cloudinit.tests import helpers as test_helpers
-from cloudinit.cmd import main as cli
mock = test_helpers.mock
@@ -45,8 +45,8 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):
"""All known subparsers are represented in the cloud-int help doc."""
self._call_main()
error = self.stderr.getvalue()
- expected_subcommands = ['analyze', 'init', 'modules', 'single',
- 'dhclient-hook', 'features', 'devel']
+ expected_subcommands = ['analyze', 'clean', 'devel', 'dhclient-hook',
+ 'features', 'init', 'modules', 'single']
for subcommand in expected_subcommands:
self.assertIn(subcommand, error)
@@ -76,9 +76,11 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):
self.patchStdoutAndStderr(stdout=stdout)
expected_errors = [
- 'usage: cloud-init analyze', 'usage: cloud-init collect-logs',
- 'usage: cloud-init devel']
- conditional_subcommands = ['analyze', 'collect-logs', 'devel']
+ 'usage: cloud-init analyze', 'usage: cloud-init clean',
+ 'usage: cloud-init collect-logs', 'usage: cloud-init devel',
+ 'usage: cloud-init status']
+ conditional_subcommands = [
+ 'analyze', 'clean', 'collect-logs', 'devel', 'status']
# The cloud-init entrypoint calls main without passing sys_argv
for subcommand in conditional_subcommands:
with mock.patch('sys.argv', ['cloud-init', subcommand, '-h']):
@@ -106,6 +108,22 @@ class TestCLI(test_helpers.FilesystemMockingTestCase):
self._call_main(['cloud-init', 'collect-logs', '-h'])
self.assertIn('usage: cloud-init collect-log', stdout.getvalue())
+ def test_clean_subcommand_parser(self):
+ """The subcommand cloud-init clean calls the subparser."""
+ # Provide -h param to clean to avoid having to mock behavior.
+ stdout = six.StringIO()
+ self.patchStdoutAndStderr(stdout=stdout)
+ self._call_main(['cloud-init', 'clean', '-h'])
+ self.assertIn('usage: cloud-init clean', stdout.getvalue())
+
+ def test_status_subcommand_parser(self):
+ """The subcommand cloud-init status calls the subparser."""
+ # Provide -h param to clean to avoid having to mock behavior.
+ stdout = six.StringIO()
+ self.patchStdoutAndStderr(stdout=stdout)
+ self._call_main(['cloud-init', 'status', '-h'])
+ self.assertIn('usage: cloud-init status', stdout.getvalue())
+
def test_devel_subcommand_parser(self):
"""The subcommand cloud-init devel calls the correct subparser."""
self._call_main(['cloud-init', 'devel'])
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 3e4154ca..71f59529 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -477,6 +477,44 @@ class TestReadDMIData(helpers.FilesystemMockingTestCase):
self.assertIsNone(util.read_dmi_data("system-product-name"))
+class TestGetConfigLogfiles(helpers.CiTestCase):
+
+ def test_empty_cfg_returns_empty_list(self):
+ """An empty config passed to get_config_logfiles returns empty list."""
+ self.assertEqual([], util.get_config_logfiles(None))
+ self.assertEqual([], util.get_config_logfiles({}))
+
+ def test_default_log_file_present(self):
+ """When default_log_file is set get_config_logfiles finds it."""
+ self.assertEqual(
+ ['/my.log'],
+ util.get_config_logfiles({'def_log_file': '/my.log'}))
+
+ def test_output_logs_parsed_when_teeing_files(self):
+ """When output configuration is parsed when teeing files."""
+ self.assertEqual(
+ ['/himom.log', '/my.log'],
+ sorted(util.get_config_logfiles({
+ 'def_log_file': '/my.log',
+ 'output': {'all': '|tee -a /himom.log'}})))
+
+ def test_output_logs_parsed_when_redirecting(self):
+ """When output configuration is parsed when redirecting to a file."""
+ self.assertEqual(
+ ['/my.log', '/test.log'],
+ sorted(util.get_config_logfiles({
+ 'def_log_file': '/my.log',
+ 'output': {'all': '>/test.log'}})))
+
+ def test_output_logs_parsed_when_appending(self):
+ """When output configuration is parsed when appending to a file."""
+ self.assertEqual(
+ ['/my.log', '/test.log'],
+ sorted(util.get_config_logfiles({
+ 'def_log_file': '/my.log',
+ 'output': {'all': '>> /test.log'}})))
+
+
class TestMultiLog(helpers.FilesystemMockingTestCase):
def _createConsole(self, root):