From 7a909f6168daa180bb94bce06577a149438266fd Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 25 Jan 2018 14:59:22 -0800 Subject: [PATCH] avoid a crash in `eden doctor` if any active mounts are unconfigured Summary: My stale mounts check regressed eden doctor's handling of unconfigured mounts. For now, just skip them, and add a test that eden doctor doesn't crash. Reviewed By: simpkins Differential Revision: D6801445 fbshipit-source-id: 65d2f9028af651ef487a7ce6c334f387b541492d --- eden/cli/doctor.py | 7 +++++ eden/cli/test/doctor_test.py | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/eden/cli/doctor.py b/eden/cli/doctor.py index 4af39a87ea..7efd16908b 100644 --- a/eden/cli/doctor.py +++ b/eden/cli/doctor.py @@ -89,6 +89,13 @@ def cure_what_ails_you( watchman_roots = _get_watch_roots_for_watchman() for mount_path in active_mount_points: + if mount_path not in config.get_mount_paths(): + # TODO: if there are mounts in active_mount_points that aren't in + # config.get_mount_paths(), should we try to add them to the config? + # I've only seen this happen in the wild if a clone fails partway, for + # example, if a post-clone hook fails. + continue + # For now, we assume that each mount_path is actively mounted. We should # update the listMounts() Thrift API to return information that notes # whether a mount point is active and use it here. diff --git a/eden/cli/test/doctor_test.py b/eden/cli/test/doctor_test.py index 2ac063f1a3..b81ab9575e 100644 --- a/eden/cli/test/doctor_test.py +++ b/eden/cli/test/doctor_test.py @@ -475,6 +475,63 @@ All is well. mock_rpm_q.assert_has_calls(calls) + def test_unconfigured_mounts_dont_crash(self): + # If Eden advertises that a mount is active, but it is not in the + # configuration, then at least don't throw an exception. + tmp_dir = tempfile.mkdtemp(prefix='eden_test.') + try: + edenfs_path1 = os.path.join(tmp_dir, 'path1') + edenfs_path2 = os.path.join(tmp_dir, 'path2') + + mount_paths = OrderedDict() + mount_paths[edenfs_path1] = { + 'bind-mounts': {}, + 'mount': edenfs_path1, + 'scm_type': 'hg', + 'snapshot': 'abcd' * 10, + 'client-dir': '/I_DO_NOT_EXIST1' + } + # path2 is not configured in the config... + config = FakeConfig(mount_paths, is_healthy=True) + # ... but is advertised by the daemon... + config.get_thrift_client()._mounts = [ + eden_ttypes.MountInfo(mountPoint=edenfs_path1), + eden_ttypes.MountInfo(mountPoint=edenfs_path2), + ] + + # ... and is in the system mount table. + mount_table = FakeMountTable() + mount_table.stats[edenfs_path1] = mtab.MTStat( + st_uid=os.getuid(), + st_dev=11) + mount_table.stats[edenfs_path2] = mtab.MTStat( + st_uid=os.getuid(), + st_dev=12) + + os.mkdir(edenfs_path1) + hg_dir = os.path.join(edenfs_path1, '.hg') + os.mkdir(hg_dir) + dirstate = os.path.join(hg_dir, 'dirstate') + dirstate_hash = b'\xab\xcd' * 10 + parents = (dirstate_hash, b'\x00' * 20) + with open(dirstate, 'wb') as f: + eden.dirstate.write(f, parents, tuples_dict={}, copymap={}) + + dry_run = False + out = io.StringIO() + exit_code = doctor.cure_what_ails_you( + config, dry_run, out, mount_table) + finally: + shutil.rmtree(tmp_dir) + + self.assertEqual( + f'''\ +Performing 3 checks for {edenfs_path1}. +All is well. +''', out.getvalue() + ) + self.assertEqual(0, exit_code) + class StaleMountsCheckTest(unittest.TestCase): maxDiff = None