diff options
| author | Chad Smith <chad.smith@canonical.com> | 2018-02-08 20:57:23 -0700 | 
|---|---|---|
| committer | Chad Smith <chad.smith@canonical.com> | 2018-02-08 20:57:23 -0700 | 
| commit | 86d2fc7f515f70a5117f00baf701a0bed6310b3e (patch) | |
| tree | cf973b320f8477ce13e953ea8219d43d82ada900 | |
| parent | 0d30c9575f9e3e4cfb7771cee992e7f669ac3e76 (diff) | |
| download | vyos-cloud-init-86d2fc7f515f70a5117f00baf701a0bed6310b3e.tar.gz vyos-cloud-init-86d2fc7f515f70a5117f00baf701a0bed6310b3e.zip  | |
cli: fix cloud-init status to report running when before result.json
Fix various corner cases for cloud-init status subcommand. Report
'runnning' under the following conditions:
 - No /run/cloud-init/result.json file exists
 - Any stage in status.json is unfinished
 - status.json reports a non-null stage it is in progress on
LP: #1747965
| -rw-r--r-- | cloudinit/cmd/status.py | 5 | ||||
| -rw-r--r-- | cloudinit/cmd/tests/test_status.py | 35 | 
2 files changed, 32 insertions, 8 deletions
diff --git a/cloudinit/cmd/status.py b/cloudinit/cmd/status.py index d7aaee9d..ea79a85b 100644 --- a/cloudinit/cmd/status.py +++ b/cloudinit/cmd/status.py @@ -105,12 +105,12 @@ def _get_status_details(paths):      Values are obtained from parsing paths.run_dir/status.json.      """ -      status = STATUS_ENABLED_NOT_RUN      status_detail = ''      status_v1 = {}      status_file = os.path.join(paths.run_dir, 'status.json') +    result_file = os.path.join(paths.run_dir, 'result.json')      (is_disabled, reason) = _is_cloudinit_disabled(          CLOUDINIT_DISABLED_FILE, paths) @@ -118,12 +118,15 @@ def _get_status_details(paths):          status = STATUS_DISABLED          status_detail = reason      if os.path.exists(status_file): +        if not os.path.exists(result_file): +            status = STATUS_RUNNING          status_v1 = load_json(load_file(status_file)).get('v1', {})      errors = []      latest_event = 0      for key, value in sorted(status_v1.items()):          if key == 'stage':              if value: +                status = STATUS_RUNNING                  status_detail = 'Running in stage: {0}'.format(value)          elif key == 'datasource':              status_detail = value diff --git a/cloudinit/cmd/tests/test_status.py b/cloudinit/cmd/tests/test_status.py index a7c0a91a..4a5a8c06 100644 --- a/cloudinit/cmd/tests/test_status.py +++ b/cloudinit/cmd/tests/test_status.py @@ -7,7 +7,7 @@ from textwrap import dedent  from cloudinit.atomic_helper import write_json  from cloudinit.cmd import status -from cloudinit.util import write_file +from cloudinit.util import ensure_file  from cloudinit.tests.helpers import CiTestCase, wrap_and_call, mock  mypaths = namedtuple('MyPaths', 'run_dir') @@ -36,7 +36,7 @@ class TestStatus(CiTestCase):      def test__is_cloudinit_disabled_false_on_sysvinit(self):          '''When not in an environment using systemd, return False.''' -        write_file(self.disable_file, '')  # Create the ignored disable file +        ensure_file(self.disable_file)  # Create the ignored disable file          (is_disabled, reason) = wrap_and_call(              'cloudinit.cmd.status',              {'uses_systemd': False}, @@ -47,7 +47,7 @@ class TestStatus(CiTestCase):      def test__is_cloudinit_disabled_true_on_disable_file(self):          '''When using systemd and disable_file is present return disabled.''' -        write_file(self.disable_file, '')  # Create observed disable file +        ensure_file(self.disable_file)  # Create observed disable file          (is_disabled, reason) = wrap_and_call(              'cloudinit.cmd.status',              {'uses_systemd': True}, @@ -58,7 +58,7 @@ class TestStatus(CiTestCase):      def test__is_cloudinit_disabled_false_on_kernel_cmdline_enable(self):          '''Not disabled when using systemd and enabled via commandline.''' -        write_file(self.disable_file, '')  # Create ignored disable file +        ensure_file(self.disable_file)  # Create ignored disable file          (is_disabled, reason) = wrap_and_call(              'cloudinit.cmd.status',              {'uses_systemd': True, @@ -96,7 +96,7 @@ class TestStatus(CiTestCase):      def test__is_cloudinit_disabled_false_when_enabled_in_systemd(self):          '''Report enabled when systemd generator creates the enabled file.'''          enabled_file = os.path.join(self.paths.run_dir, 'enabled') -        write_file(enabled_file, '') +        ensure_file(enabled_file)          (is_disabled, reason) = wrap_and_call(              'cloudinit.cmd.status',              {'uses_systemd': True, @@ -149,8 +149,25 @@ class TestStatus(CiTestCase):          ''')          self.assertEqual(expected, m_stdout.getvalue()) +    def test_status_returns_running_on_no_results_json(self): +        '''Report running when status.json exists but result.json does not.''' +        result_file = self.tmp_path('result.json', self.new_root) +        write_json(self.status_file, {}) +        self.assertFalse( +            os.path.exists(result_file), 'Unexpected result.json found') +        cmdargs = myargs(long=False, wait=False) +        with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout: +            retcode = wrap_and_call( +                'cloudinit.cmd.status', +                {'_is_cloudinit_disabled': (False, ''), +                 'Init': {'side_effect': self.init_class}}, +                status.handle_status_args, 'ignored', cmdargs) +        self.assertEqual(0, retcode) +        self.assertEqual('status: running\n', m_stdout.getvalue()) +      def test_status_returns_running(self):          '''Report running when status exists with an unfinished stage.''' +        ensure_file(self.tmp_path('result.json', self.new_root))          write_json(self.status_file,                     {'v1': {'init': {'start': 1, 'finished': None}}})          cmdargs = myargs(long=False, wait=False) @@ -164,10 +181,11 @@ class TestStatus(CiTestCase):          self.assertEqual('status: running\n', m_stdout.getvalue())      def test_status_returns_done(self): -        '''Reports done when stage is None and all stages are finished.''' +        '''Report done results.json exists no stages are unfinished.''' +        ensure_file(self.tmp_path('result.json', self.new_root))          write_json(              self.status_file, -            {'v1': {'stage': None, +            {'v1': {'stage': None,  # No current stage running                      'datasource': (                          'DataSourceNoCloud [seed=/var/.../seed/nocloud-net]'                          '[dsmode=net]'), @@ -187,6 +205,7 @@ class TestStatus(CiTestCase):      def test_status_returns_done_long(self):          '''Long format of done status includes datasource info.''' +        ensure_file(self.tmp_path('result.json', self.new_root))          write_json(              self.status_file,              {'v1': {'stage': None, @@ -303,6 +322,8 @@ class TestStatus(CiTestCase):                  write_json(self.status_file, running_json)              elif self.sleep_calls == 3:                  write_json(self.status_file, done_json) +                result_file = self.tmp_path('result.json', self.new_root) +                ensure_file(result_file)          cmdargs = myargs(long=False, wait=True)          with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout:  | 
