|
Packit |
bc9a3a |
# This file is part of cloud-init. See LICENSE file for license information.
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
from collections import namedtuple
|
|
Packit |
bc9a3a |
import os
|
|
Packit |
bc9a3a |
from six import StringIO
|
|
Packit |
bc9a3a |
from textwrap import dedent
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
from cloudinit.atomic_helper import write_json
|
|
Packit |
bc9a3a |
from cloudinit.cmd import status
|
|
Packit |
bc9a3a |
from cloudinit.util import ensure_file
|
|
Packit |
bc9a3a |
from cloudinit.tests.helpers import CiTestCase, wrap_and_call, mock
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
mypaths = namedtuple('MyPaths', 'run_dir')
|
|
Packit |
bc9a3a |
myargs = namedtuple('MyArgs', 'long wait')
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
class TestStatus(CiTestCase):
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def setUp(self):
|
|
Packit |
bc9a3a |
super(TestStatus, self).setUp()
|
|
Packit |
bc9a3a |
self.new_root = self.tmp_dir()
|
|
Packit |
bc9a3a |
self.status_file = self.tmp_path('status.json', self.new_root)
|
|
Packit |
bc9a3a |
self.disable_file = self.tmp_path('cloudinit-disable', self.new_root)
|
|
Packit |
bc9a3a |
self.paths = mypaths(run_dir=self.new_root)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
class FakeInit(object):
|
|
Packit |
bc9a3a |
paths = self.paths
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def __init__(self, ds_deps):
|
|
Packit |
bc9a3a |
pass
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def read_cfg(self):
|
|
Packit |
bc9a3a |
pass
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
self.init_class = FakeInit
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test__is_cloudinit_disabled_false_on_sysvinit(self):
|
|
Packit |
bc9a3a |
'''When not in an environment using systemd, return False.'''
|
|
Packit |
bc9a3a |
ensure_file(self.disable_file) # Create the ignored disable file
|
|
Packit |
bc9a3a |
(is_disabled, reason) = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'uses_systemd': False,
|
|
Packit |
bc9a3a |
'get_cmdline': "root=/dev/my-root not-important"},
|
|
Packit |
bc9a3a |
status._is_cloudinit_disabled, self.disable_file, self.paths)
|
|
Packit |
bc9a3a |
self.assertFalse(
|
|
Packit |
bc9a3a |
is_disabled, 'expected enabled cloud-init on sysvinit')
|
|
Packit |
bc9a3a |
self.assertEqual('Cloud-init enabled on sysvinit', reason)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test__is_cloudinit_disabled_true_on_disable_file(self):
|
|
Packit |
bc9a3a |
'''When using systemd and disable_file is present return disabled.'''
|
|
Packit |
bc9a3a |
ensure_file(self.disable_file) # Create observed disable file
|
|
Packit |
bc9a3a |
(is_disabled, reason) = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'uses_systemd': True,
|
|
Packit |
bc9a3a |
'get_cmdline': "root=/dev/my-root not-important"},
|
|
Packit |
bc9a3a |
status._is_cloudinit_disabled, self.disable_file, self.paths)
|
|
Packit |
bc9a3a |
self.assertTrue(is_disabled, 'expected disabled cloud-init')
|
|
Packit |
bc9a3a |
self.assertEqual(
|
|
Packit |
bc9a3a |
'Cloud-init disabled by {0}'.format(self.disable_file), reason)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test__is_cloudinit_disabled_false_on_kernel_cmdline_enable(self):
|
|
Packit |
bc9a3a |
'''Not disabled when using systemd and enabled via commandline.'''
|
|
Packit |
bc9a3a |
ensure_file(self.disable_file) # Create ignored disable file
|
|
Packit |
bc9a3a |
(is_disabled, reason) = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'uses_systemd': True,
|
|
Packit |
bc9a3a |
'get_cmdline': 'something cloud-init=enabled else'},
|
|
Packit |
bc9a3a |
status._is_cloudinit_disabled, self.disable_file, self.paths)
|
|
Packit |
bc9a3a |
self.assertFalse(is_disabled, 'expected enabled cloud-init')
|
|
Packit |
bc9a3a |
self.assertEqual(
|
|
Packit |
bc9a3a |
'Cloud-init enabled by kernel command line cloud-init=enabled',
|
|
Packit |
bc9a3a |
reason)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test__is_cloudinit_disabled_true_on_kernel_cmdline(self):
|
|
Packit |
bc9a3a |
'''When using systemd and disable_file is present return disabled.'''
|
|
Packit |
bc9a3a |
(is_disabled, reason) = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'uses_systemd': True,
|
|
Packit |
bc9a3a |
'get_cmdline': 'something cloud-init=disabled else'},
|
|
Packit |
bc9a3a |
status._is_cloudinit_disabled, self.disable_file, self.paths)
|
|
Packit |
bc9a3a |
self.assertTrue(is_disabled, 'expected disabled cloud-init')
|
|
Packit |
bc9a3a |
self.assertEqual(
|
|
Packit |
bc9a3a |
'Cloud-init disabled by kernel parameter cloud-init=disabled',
|
|
Packit |
bc9a3a |
reason)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test__is_cloudinit_disabled_true_when_generator_disables(self):
|
|
Packit |
bc9a3a |
'''When cloud-init-generator doesn't write enabled file return True.'''
|
|
Packit |
bc9a3a |
enabled_file = os.path.join(self.paths.run_dir, 'enabled')
|
|
Packit |
bc9a3a |
self.assertFalse(os.path.exists(enabled_file))
|
|
Packit |
bc9a3a |
(is_disabled, reason) = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'uses_systemd': True,
|
|
Packit |
bc9a3a |
'get_cmdline': 'something'},
|
|
Packit |
bc9a3a |
status._is_cloudinit_disabled, self.disable_file, self.paths)
|
|
Packit |
bc9a3a |
self.assertTrue(is_disabled, 'expected disabled cloud-init')
|
|
Packit |
bc9a3a |
self.assertEqual('Cloud-init disabled by cloud-init-generator', reason)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test__is_cloudinit_disabled_false_when_enabled_in_systemd(self):
|
|
Packit |
bc9a3a |
'''Report enabled when systemd generator creates the enabled file.'''
|
|
Packit |
bc9a3a |
enabled_file = os.path.join(self.paths.run_dir, 'enabled')
|
|
Packit |
bc9a3a |
ensure_file(enabled_file)
|
|
Packit |
bc9a3a |
(is_disabled, reason) = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'uses_systemd': True,
|
|
Packit |
bc9a3a |
'get_cmdline': 'something ignored'},
|
|
Packit |
bc9a3a |
status._is_cloudinit_disabled, self.disable_file, self.paths)
|
|
Packit |
bc9a3a |
self.assertFalse(is_disabled, 'expected enabled cloud-init')
|
|
Packit |
bc9a3a |
self.assertEqual(
|
|
Packit |
bc9a3a |
'Cloud-init enabled by systemd cloud-init-generator', reason)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_returns_not_run(self):
|
|
Packit |
bc9a3a |
'''When status.json does not exist yet, return 'not run'.'''
|
|
Packit |
bc9a3a |
self.assertFalse(
|
|
Packit |
bc9a3a |
os.path.exists(self.status_file), 'Unexpected status.json found')
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=False, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(0, retcode)
|
|
Packit |
bc9a3a |
self.assertEqual('status: not run\n', m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_returns_disabled_long_on_presence_of_disable_file(self):
|
|
Packit |
bc9a3a |
'''When cloudinit is disabled, return disabled reason.'''
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
checked_files = []
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def fakeexists(filepath):
|
|
Packit |
bc9a3a |
checked_files.append(filepath)
|
|
Packit |
bc9a3a |
status_file = os.path.join(self.paths.run_dir, 'status.json')
|
|
Packit |
bc9a3a |
return bool(not filepath == status_file)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=True, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'os.path.exists': {'side_effect': fakeexists},
|
|
Packit |
bc9a3a |
'_is_cloudinit_disabled': (True, 'disabled for some reason'),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(0, retcode)
|
|
Packit |
bc9a3a |
self.assertEqual(
|
|
Packit |
bc9a3a |
[os.path.join(self.paths.run_dir, 'status.json')],
|
|
Packit |
bc9a3a |
checked_files)
|
|
Packit |
bc9a3a |
expected = dedent('''\
|
|
Packit |
bc9a3a |
status: disabled
|
|
Packit |
bc9a3a |
detail:
|
|
Packit |
bc9a3a |
disabled for some reason
|
|
Packit |
bc9a3a |
''')
|
|
Packit |
bc9a3a |
self.assertEqual(expected, m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_returns_running_on_no_results_json(self):
|
|
Packit |
bc9a3a |
'''Report running when status.json exists but result.json does not.'''
|
|
Packit |
bc9a3a |
result_file = self.tmp_path('result.json', self.new_root)
|
|
Packit |
bc9a3a |
write_json(self.status_file, {})
|
|
Packit |
bc9a3a |
self.assertFalse(
|
|
Packit |
bc9a3a |
os.path.exists(result_file), 'Unexpected result.json found')
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=False, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(0, retcode)
|
|
Packit |
bc9a3a |
self.assertEqual('status: running\n', m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_returns_running(self):
|
|
Packit |
bc9a3a |
'''Report running when status exists with an unfinished stage.'''
|
|
Packit |
bc9a3a |
ensure_file(self.tmp_path('result.json', self.new_root))
|
|
Packit |
bc9a3a |
write_json(self.status_file,
|
|
Packit |
bc9a3a |
{'v1': {'init': {'start': 1, 'finished': None}}})
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=False, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(0, retcode)
|
|
Packit |
bc9a3a |
self.assertEqual('status: running\n', m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_returns_done(self):
|
|
Packit |
bc9a3a |
'''Report done results.json exists no stages are unfinished.'''
|
|
Packit |
bc9a3a |
ensure_file(self.tmp_path('result.json', self.new_root))
|
|
Packit |
bc9a3a |
write_json(
|
|
Packit |
bc9a3a |
self.status_file,
|
|
Packit |
bc9a3a |
{'v1': {'stage': None, # No current stage running
|
|
Packit |
bc9a3a |
'datasource': (
|
|
Packit |
bc9a3a |
'DataSourceNoCloud [seed=/var/.../seed/nocloud-net]'
|
|
Packit |
bc9a3a |
'[dsmode=net]'),
|
|
Packit |
bc9a3a |
'blah': {'finished': 123.456},
|
|
Packit |
bc9a3a |
'init': {'errors': [], 'start': 124.567,
|
|
Packit |
bc9a3a |
'finished': 125.678},
|
|
Packit |
bc9a3a |
'init-local': {'start': 123.45, 'finished': 123.46}}})
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=False, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(0, retcode)
|
|
Packit |
bc9a3a |
self.assertEqual('status: done\n', m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_returns_done_long(self):
|
|
Packit |
bc9a3a |
'''Long format of done status includes datasource info.'''
|
|
Packit |
bc9a3a |
ensure_file(self.tmp_path('result.json', self.new_root))
|
|
Packit |
bc9a3a |
write_json(
|
|
Packit |
bc9a3a |
self.status_file,
|
|
Packit |
bc9a3a |
{'v1': {'stage': None,
|
|
Packit |
bc9a3a |
'datasource': (
|
|
Packit |
bc9a3a |
'DataSourceNoCloud [seed=/var/.../seed/nocloud-net]'
|
|
Packit |
bc9a3a |
'[dsmode=net]'),
|
|
Packit |
bc9a3a |
'init': {'start': 124.567, 'finished': 125.678},
|
|
Packit |
bc9a3a |
'init-local': {'start': 123.45, 'finished': 123.46}}})
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=True, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(0, retcode)
|
|
Packit |
bc9a3a |
expected = dedent('''\
|
|
Packit |
bc9a3a |
status: done
|
|
Packit |
bc9a3a |
time: Thu, 01 Jan 1970 00:02:05 +0000
|
|
Packit |
bc9a3a |
detail:
|
|
Packit |
bc9a3a |
DataSourceNoCloud [seed=/var/.../seed/nocloud-net][dsmode=net]
|
|
Packit |
bc9a3a |
''')
|
|
Packit |
bc9a3a |
self.assertEqual(expected, m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_on_errors(self):
|
|
Packit |
bc9a3a |
'''Reports error when any stage has errors.'''
|
|
Packit |
bc9a3a |
write_json(
|
|
Packit |
bc9a3a |
self.status_file,
|
|
Packit |
bc9a3a |
{'v1': {'stage': None,
|
|
Packit |
bc9a3a |
'blah': {'errors': [], 'finished': 123.456},
|
|
Packit |
bc9a3a |
'init': {'errors': ['error1'], 'start': 124.567,
|
|
Packit |
bc9a3a |
'finished': 125.678},
|
|
Packit |
bc9a3a |
'init-local': {'start': 123.45, 'finished': 123.46}}})
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=False, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(1, retcode)
|
|
Packit |
bc9a3a |
self.assertEqual('status: error\n', m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_on_errors_long(self):
|
|
Packit |
bc9a3a |
'''Long format of error status includes all error messages.'''
|
|
Packit |
bc9a3a |
write_json(
|
|
Packit |
bc9a3a |
self.status_file,
|
|
Packit |
bc9a3a |
{'v1': {'stage': None,
|
|
Packit |
bc9a3a |
'datasource': (
|
|
Packit |
bc9a3a |
'DataSourceNoCloud [seed=/var/.../seed/nocloud-net]'
|
|
Packit |
bc9a3a |
'[dsmode=net]'),
|
|
Packit |
bc9a3a |
'init': {'errors': ['error1'], 'start': 124.567,
|
|
Packit |
bc9a3a |
'finished': 125.678},
|
|
Packit |
bc9a3a |
'init-local': {'errors': ['error2', 'error3'],
|
|
Packit |
bc9a3a |
'start': 123.45, 'finished': 123.46}}})
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=True, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(1, retcode)
|
|
Packit |
bc9a3a |
expected = dedent('''\
|
|
Packit |
bc9a3a |
status: error
|
|
Packit |
bc9a3a |
time: Thu, 01 Jan 1970 00:02:05 +0000
|
|
Packit |
bc9a3a |
detail:
|
|
Packit |
bc9a3a |
error1
|
|
Packit |
bc9a3a |
error2
|
|
Packit |
bc9a3a |
error3
|
|
Packit |
bc9a3a |
''')
|
|
Packit |
bc9a3a |
self.assertEqual(expected, m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_returns_running_long_format(self):
|
|
Packit |
bc9a3a |
'''Long format reports the stage in which we are running.'''
|
|
Packit |
bc9a3a |
write_json(
|
|
Packit |
bc9a3a |
self.status_file,
|
|
Packit |
bc9a3a |
{'v1': {'stage': 'init',
|
|
Packit |
bc9a3a |
'init': {'start': 124.456, 'finished': None},
|
|
Packit |
bc9a3a |
'init-local': {'start': 123.45, 'finished': 123.46}}})
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=True, wait=False)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(0, retcode)
|
|
Packit |
bc9a3a |
expected = dedent('''\
|
|
Packit |
bc9a3a |
status: running
|
|
Packit |
bc9a3a |
time: Thu, 01 Jan 1970 00:02:04 +0000
|
|
Packit |
bc9a3a |
detail:
|
|
Packit |
bc9a3a |
Running in stage: init
|
|
Packit |
bc9a3a |
''')
|
|
Packit |
bc9a3a |
self.assertEqual(expected, m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_wait_blocks_until_done(self):
|
|
Packit |
bc9a3a |
'''Specifying wait will poll every 1/4 second until done state.'''
|
|
Packit |
bc9a3a |
running_json = {
|
|
Packit |
bc9a3a |
'v1': {'stage': 'init',
|
|
Packit |
bc9a3a |
'init': {'start': 124.456, 'finished': None},
|
|
Packit |
bc9a3a |
'init-local': {'start': 123.45, 'finished': 123.46}}}
|
|
Packit |
bc9a3a |
done_json = {
|
|
Packit |
bc9a3a |
'v1': {'stage': None,
|
|
Packit |
bc9a3a |
'init': {'start': 124.456, 'finished': 125.678},
|
|
Packit |
bc9a3a |
'init-local': {'start': 123.45, 'finished': 123.46}}}
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
self.sleep_calls = 0
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def fake_sleep(interval):
|
|
Packit |
bc9a3a |
self.assertEqual(0.25, interval)
|
|
Packit |
bc9a3a |
self.sleep_calls += 1
|
|
Packit |
bc9a3a |
if self.sleep_calls == 2:
|
|
Packit |
bc9a3a |
write_json(self.status_file, running_json)
|
|
Packit |
bc9a3a |
elif self.sleep_calls == 3:
|
|
Packit |
bc9a3a |
write_json(self.status_file, done_json)
|
|
Packit |
bc9a3a |
result_file = self.tmp_path('result.json', self.new_root)
|
|
Packit |
bc9a3a |
ensure_file(result_file)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=False, wait=True)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'sleep': {'side_effect': fake_sleep},
|
|
Packit |
bc9a3a |
'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(0, retcode)
|
|
Packit |
bc9a3a |
self.assertEqual(4, self.sleep_calls)
|
|
Packit |
bc9a3a |
self.assertEqual('....\nstatus: done\n', m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_wait_blocks_until_error(self):
|
|
Packit |
bc9a3a |
'''Specifying wait will poll every 1/4 second until error state.'''
|
|
Packit |
bc9a3a |
running_json = {
|
|
Packit |
bc9a3a |
'v1': {'stage': 'init',
|
|
Packit |
bc9a3a |
'init': {'start': 124.456, 'finished': None},
|
|
Packit |
bc9a3a |
'init-local': {'start': 123.45, 'finished': 123.46}}}
|
|
Packit |
bc9a3a |
error_json = {
|
|
Packit |
bc9a3a |
'v1': {'stage': None,
|
|
Packit |
bc9a3a |
'init': {'errors': ['error1'], 'start': 124.456,
|
|
Packit |
bc9a3a |
'finished': 125.678},
|
|
Packit |
bc9a3a |
'init-local': {'start': 123.45, 'finished': 123.46}}}
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
self.sleep_calls = 0
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def fake_sleep(interval):
|
|
Packit |
bc9a3a |
self.assertEqual(0.25, interval)
|
|
Packit |
bc9a3a |
self.sleep_calls += 1
|
|
Packit |
bc9a3a |
if self.sleep_calls == 2:
|
|
Packit |
bc9a3a |
write_json(self.status_file, running_json)
|
|
Packit |
bc9a3a |
elif self.sleep_calls == 3:
|
|
Packit |
bc9a3a |
write_json(self.status_file, error_json)
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
cmdargs = myargs(long=False, wait=True)
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
retcode = wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'sleep': {'side_effect': fake_sleep},
|
|
Packit |
bc9a3a |
'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.handle_status_args, 'ignored', cmdargs)
|
|
Packit |
bc9a3a |
self.assertEqual(1, retcode)
|
|
Packit |
bc9a3a |
self.assertEqual(4, self.sleep_calls)
|
|
Packit |
bc9a3a |
self.assertEqual('....\nstatus: error\n', m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
def test_status_main(self):
|
|
Packit |
bc9a3a |
'''status.main can be run as a standalone script.'''
|
|
Packit |
bc9a3a |
write_json(self.status_file,
|
|
Packit |
bc9a3a |
{'v1': {'init': {'start': 1, 'finished': None}}})
|
|
Packit |
bc9a3a |
with self.assertRaises(SystemExit) as context_manager:
|
|
Packit |
bc9a3a |
with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:
|
|
Packit |
bc9a3a |
wrap_and_call(
|
|
Packit |
bc9a3a |
'cloudinit.cmd.status',
|
|
Packit |
bc9a3a |
{'sys.argv': {'new': ['status']},
|
|
Packit |
bc9a3a |
'sys.exit': {'side_effect': self.sys_exit},
|
|
Packit |
bc9a3a |
'_is_cloudinit_disabled': (False, ''),
|
|
Packit |
bc9a3a |
'Init': {'side_effect': self.init_class}},
|
|
Packit |
bc9a3a |
status.main)
|
|
Packit |
bc9a3a |
self.assertEqual(0, context_manager.exception.code)
|
|
Packit |
bc9a3a |
self.assertEqual('status: running\n', m_stdout.getvalue())
|
|
Packit |
bc9a3a |
|
|
Packit |
bc9a3a |
# vi: ts=4 expandtab syntax=python
|