mirror of
https://github.com/facebook/sapling.git
synced 2024-10-06 23:07:18 +03:00
rename the ProcessFinder class to ProcUtils
Summary: This renames the `ProcessFinder` class to `ProcUtils`, in preparation for adding some more generic process management utilities into this class. This class was originally just used for finding stale processes in `edenfsctl doctor`. However, it seems like a good place to consolidate all platform-specific process querying logic. We are currently need platform-specific querying to tell if specific process IDs are still running for `edenfsctl status` and `edenfsctl stop`, and we also already have some Windows-specific spawning logic in `edenfsctl start`. I plan to move all of that logic into this `proc_utils.py` module. This renames `ProcessFinder` to `ProcUtils` just to better reflect its expanded purpose. Reviewed By: genevievehelsel Differential Revision: D20833243 fbshipit-source-id: 8d33460b7468d877bc327e855af5c620ac5b80a7
This commit is contained in:
parent
17a3c9124d
commit
dbbb0d64c8
@ -10,14 +10,7 @@ from pathlib import Path
|
||||
from textwrap import dedent
|
||||
from typing import Dict, Optional
|
||||
|
||||
from eden.fs.cli import (
|
||||
config as config_mod,
|
||||
filesystem,
|
||||
mtab,
|
||||
process_finder,
|
||||
ui,
|
||||
version,
|
||||
)
|
||||
from eden.fs.cli import config as config_mod, filesystem, mtab, proc_utils, ui, version
|
||||
from eden.fs.cli.config import EdenCheckout, EdenInstance
|
||||
from facebook.eden.ttypes import MountState
|
||||
from fb303_core.ttypes import fb303_status
|
||||
@ -50,7 +43,7 @@ def cure_what_ails_you(
|
||||
dry_run: bool,
|
||||
mount_table: mtab.MountTable,
|
||||
fs_util: filesystem.FsUtil,
|
||||
process_finder: process_finder.ProcessFinder,
|
||||
proc_utils: proc_utils.ProcUtils,
|
||||
out: Optional[ui.Output] = None,
|
||||
) -> int:
|
||||
if out is None:
|
||||
@ -67,7 +60,7 @@ def cure_what_ails_you(
|
||||
check_os.run_operating_system_checks(fixer, instance, out)
|
||||
|
||||
# check multiple edenfs running with some rogue stale PIDs
|
||||
check_rogue_edenfs.check_many_edenfs_are_running(fixer, process_finder)
|
||||
check_rogue_edenfs.check_many_edenfs_are_running(fixer, proc_utils)
|
||||
|
||||
status = instance.check_health()
|
||||
if status.status == fb303_status.ALIVE:
|
||||
|
@ -13,21 +13,21 @@ from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from eden.fs.cli.doctor.problem import Problem, ProblemSeverity, ProblemTracker
|
||||
from eden.fs.cli.process_finder import EdenFSProcess, ProcessFinder, ProcessID
|
||||
from eden.fs.cli.proc_utils import EdenFSProcess, ProcessID, ProcUtils
|
||||
|
||||
|
||||
log: logging.Logger = logging.getLogger("eden.fs.cli.doctor.check_rogue_edenfs")
|
||||
|
||||
|
||||
def find_rogue_processes(
|
||||
process_finder: ProcessFinder, uid: Optional[int] = None
|
||||
proc_utils: ProcUtils, uid: Optional[int] = None
|
||||
) -> List[EdenFSProcess]:
|
||||
# Build a dictionary of eden directory to list of running PIDs,
|
||||
# so that below we can we only check each eden directory once even if there are
|
||||
# multiple processes that appear to be running for it.
|
||||
info_by_eden_dir: Dict[Path, List[EdenFSProcess]] = {}
|
||||
user_id = os.getuid() if uid is None else uid
|
||||
for info in process_finder.get_edenfs_processes():
|
||||
for info in proc_utils.get_edenfs_processes():
|
||||
# Ignore processes not owned by the current user
|
||||
if info.uid != user_id:
|
||||
continue
|
||||
@ -59,7 +59,7 @@ def find_rogue_processes(
|
||||
|
||||
lockfile = eden_dir / "lock"
|
||||
try:
|
||||
lock_pid = ProcessID(process_finder.read_lock_file(lockfile).strip())
|
||||
lock_pid = ProcessID(proc_utils.read_lock_file(lockfile).strip())
|
||||
except OSError:
|
||||
log.warning(f"Lock file cannot be read for {eden_dir}", exc_info=True)
|
||||
continue
|
||||
@ -79,9 +79,9 @@ def find_rogue_processes(
|
||||
|
||||
|
||||
def check_many_edenfs_are_running(
|
||||
tracker: ProblemTracker, process_finder: ProcessFinder, uid: Optional[int] = None
|
||||
tracker: ProblemTracker, proc_utils: ProcUtils, uid: Optional[int] = None
|
||||
) -> None:
|
||||
rogue_processes = find_rogue_processes(process_finder, uid=uid)
|
||||
rogue_processes = find_rogue_processes(proc_utils, uid=uid)
|
||||
if len(rogue_processes) > 0:
|
||||
rogue_pids = [p.pid for p in rogue_processes]
|
||||
rogue_pids_problem = ManyEdenFsRunning(rogue_pids)
|
||||
|
@ -166,7 +166,7 @@ Repairing hg directory contents for {self.checkout.path}...<green>fixed<reset>
|
||||
dry_run,
|
||||
self.instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
return out
|
||||
|
@ -106,7 +106,7 @@ class DoctorTest(DoctorTestBase):
|
||||
dry_run,
|
||||
instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
|
||||
@ -183,7 +183,7 @@ https://fb.facebook.com/groups/eden.users/
|
||||
dry_run,
|
||||
mount_table=instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
|
||||
@ -210,7 +210,7 @@ https://fb.facebook.com/groups/eden.users/
|
||||
dry_run,
|
||||
FakeMountTable(),
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
|
||||
@ -232,7 +232,7 @@ https://fb.facebook.com/groups/eden.users/
|
||||
dry_run,
|
||||
FakeMountTable(),
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
|
||||
@ -267,7 +267,7 @@ https://fb.facebook.com/groups/eden.users/
|
||||
dry_run,
|
||||
FakeMountTable(),
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
|
||||
@ -302,7 +302,7 @@ https://fb.facebook.com/groups/eden.users/
|
||||
dry_run,
|
||||
FakeMountTable(),
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
|
||||
@ -857,7 +857,7 @@ may have important bug fixes or performance improvements.
|
||||
dry_run,
|
||||
instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
|
||||
@ -962,7 +962,7 @@ Would remount {mounts[1]}
|
||||
dry_run,
|
||||
instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
return exit_code, out.getvalue(), mounts
|
||||
@ -984,7 +984,7 @@ Would remount {mounts[1]}
|
||||
dry_run=False,
|
||||
mount_table=instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
|
||||
@ -1059,7 +1059,7 @@ Checking {mount}
|
||||
dry_run=False,
|
||||
mount_table=instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
return exit_code, out.getvalue()
|
||||
|
@ -11,7 +11,7 @@ from typing import Tuple
|
||||
import eden.dirstate
|
||||
import eden.fs.cli.doctor as doctor
|
||||
from eden.fs.cli.config import EdenCheckout
|
||||
from eden.fs.cli.test.lib.fake_process_finder import FakeProcessFinder
|
||||
from eden.fs.cli.test.lib.fake_proc_utils import FakeProcUtils
|
||||
from eden.fs.cli.test.lib.output import TestOutput
|
||||
from eden.test_support.temporary_directory import TemporaryDirectoryMixin
|
||||
|
||||
@ -44,5 +44,5 @@ class DoctorTestBase(unittest.TestCase, TemporaryDirectoryMixin):
|
||||
parents, _tuples_dict, _copymap = eden.dirstate.read(f, str(dirstate_path))
|
||||
self.assertEqual(binascii.hexlify(parents[0]).decode("utf-8"), commit)
|
||||
|
||||
def make_process_finder(self) -> FakeProcessFinder:
|
||||
return FakeProcessFinder(self.make_temporary_directory())
|
||||
def make_proc_utils(self) -> FakeProcUtils:
|
||||
return FakeProcUtils(self.make_temporary_directory())
|
||||
|
@ -10,10 +10,10 @@ import itertools
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import eden.fs.cli.doctor as doctor
|
||||
from eden.fs.cli import process_finder
|
||||
from eden.fs.cli import proc_utils
|
||||
from eden.fs.cli.doctor import check_rogue_edenfs
|
||||
from eden.fs.cli.doctor.test.lib.testcase import DoctorTestBase
|
||||
from eden.fs.cli.test.lib.fake_process_finder import FakeProcessFinder
|
||||
from eden.fs.cli.test.lib.fake_proc_utils import FakeProcUtils
|
||||
|
||||
|
||||
TEST_UID = 99
|
||||
@ -23,23 +23,23 @@ class MultipleEdenfsRunningTest(DoctorTestBase):
|
||||
maxDiff: Optional[int] = None
|
||||
|
||||
def run_check(
|
||||
self, process_finder: process_finder.ProcessFinder, dry_run: bool
|
||||
self, proc_utils: proc_utils.ProcUtils, dry_run: bool
|
||||
) -> Tuple[doctor.ProblemFixer, str]:
|
||||
fixer, out = self.create_fixer(dry_run)
|
||||
check_rogue_edenfs.check_many_edenfs_are_running(
|
||||
fixer, process_finder, uid=TEST_UID
|
||||
fixer, proc_utils, uid=TEST_UID
|
||||
)
|
||||
return fixer, out.getvalue()
|
||||
|
||||
def make_process_finder(self) -> FakeProcessFinder:
|
||||
return FakeProcessFinder(self.make_temporary_directory(), default_uid=TEST_UID)
|
||||
def make_proc_utils(self) -> FakeProcUtils:
|
||||
return FakeProcUtils(self.make_temporary_directory(), default_uid=TEST_UID)
|
||||
|
||||
def test_when_there_are_rogue_pids(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_edenfs(123, "/home/someuser/.eden", set_lockfile=False)
|
||||
process_finder.add_edenfs(456, "/home/someuser/.eden", set_lockfile=False)
|
||||
process_finder.add_edenfs(789, "/home/someuser/.eden", set_lockfile=True)
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_edenfs(123, "/home/someuser/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(456, "/home/someuser/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(789, "/home/someuser/.eden", set_lockfile=True)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assert_results(fixer, num_problems=1, num_manual_fixes=1)
|
||||
self.assertEqual(
|
||||
out,
|
||||
@ -52,56 +52,56 @@ kill -9 123 456
|
||||
)
|
||||
|
||||
def test_when_no_rogue_edenfs_process_running(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
proc_utils = self.make_proc_utils()
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual("", out)
|
||||
self.assert_results(fixer, num_problems=0)
|
||||
|
||||
def test_when_error_reading_proc(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
proc_utils = self.make_proc_utils()
|
||||
# Add some rogue edenfs processes, but then blow away parts of their proc
|
||||
# directories so that the process finder won't be able to read all of their
|
||||
# information.
|
||||
#
|
||||
# This sort of simulates what would happen if the processes exited while the
|
||||
# code was trying to read their information.
|
||||
process_finder.add_edenfs(123, "/home/someuser/.eden", set_lockfile=False)
|
||||
process_finder.add_edenfs(456, "/home/someuser/.eden", set_lockfile=False)
|
||||
process_finder.add_edenfs(789, "/home/someuser/.eden", set_lockfile=True)
|
||||
proc_utils.add_edenfs(123, "/home/someuser/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(456, "/home/someuser/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(789, "/home/someuser/.eden", set_lockfile=True)
|
||||
|
||||
(process_finder.proc_path / "456" / "comm").unlink()
|
||||
(process_finder.proc_path / "789" / "cmdline").unlink()
|
||||
(proc_utils.proc_path / "456" / "comm").unlink()
|
||||
(proc_utils.proc_path / "789" / "cmdline").unlink()
|
||||
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual("", out)
|
||||
self.assert_results(fixer, num_problems=0)
|
||||
|
||||
def test_when_os_found_no_pids_at_all(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
proc_utils = self.make_proc_utils()
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual("", out)
|
||||
self.assert_results(fixer, num_problems=0)
|
||||
|
||||
def test_when_os_found_pids_but_edenDir_not_in_cmdline(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_process(1614248, ["edenfs"])
|
||||
process_finder.add_process(1639164, ["edenfs"])
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_process(1614248, ["edenfs"])
|
||||
proc_utils.add_process(1639164, ["edenfs"])
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual("", out)
|
||||
self.assert_results(fixer, num_problems=0)
|
||||
|
||||
def test_when_many_edenfs_procs_run_for_same_config(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_edenfs(
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_edenfs(
|
||||
475203, "/tmp/eden_test.68yxptnx/.eden", set_lockfile=True
|
||||
)
|
||||
process_finder.add_edenfs(
|
||||
proc_utils.add_edenfs(
|
||||
575204, "/tmp/eden_test.68yxptnx/.eden", set_lockfile=False
|
||||
)
|
||||
process_finder.add_edenfs(
|
||||
proc_utils.add_edenfs(
|
||||
675205, "/tmp/eden_test.68yxptnx/.eden", set_lockfile=False
|
||||
)
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual(
|
||||
out,
|
||||
f"""\
|
||||
@ -114,20 +114,20 @@ kill -9 575204 675205
|
||||
self.assert_results(fixer, num_problems=1, num_manual_fixes=1)
|
||||
|
||||
def test_when_other_processes_with_similar_names_running(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_edenfs(475203, "/home/user/.eden")
|
||||
process_finder.add_process(
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_edenfs(475203, "/home/user/.eden")
|
||||
proc_utils.add_process(
|
||||
575204, ["/foobar/fooedenfs", "--edenDir", "/home/user/.eden", "--edenfs"]
|
||||
)
|
||||
process_finder.add_process(
|
||||
proc_utils.add_process(
|
||||
675205, ["/foobar/edenfsbar", "--edenDir", "/home/user/.eden", "--edenfs"]
|
||||
)
|
||||
process_finder.add_process(
|
||||
proc_utils.add_process(
|
||||
775206, ["/foobar/edenfs", "--edenDir", "/home/user/.eden", "--edenfs"]
|
||||
)
|
||||
process_finder.add_edenfs(775310, "/home/user/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(775310, "/home/user/.eden", set_lockfile=False)
|
||||
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual(
|
||||
f"""\
|
||||
<yellow>- Found problem:<reset>
|
||||
@ -140,41 +140,41 @@ kill -9 775310
|
||||
self.assert_results(fixer, num_problems=1, num_manual_fixes=1)
|
||||
|
||||
def test_when_only_valid_edenfs_process_running(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_edenfs(475203, "/home/someuser/.eden")
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_edenfs(475203, "/home/someuser/.eden")
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual("", out)
|
||||
self.assert_results(fixer, num_problems=0)
|
||||
|
||||
def test_when_os_found_pids_but_edenDir_value_not_in_cmdline(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_process(1614248, ["edenfs", "--edenDir"])
|
||||
process_finder.add_process(1639164, ["edenfs"])
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_process(1614248, ["edenfs", "--edenDir"])
|
||||
proc_utils.add_process(1639164, ["edenfs"])
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual("", out)
|
||||
self.assert_results(fixer, num_problems=0)
|
||||
|
||||
def test_state_directory_from_lock_fd(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_edenfs(
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_edenfs(
|
||||
1234,
|
||||
"/home/someuser/.eden",
|
||||
cmdline=["edenfs", "--edenfs"],
|
||||
set_lockfile=True,
|
||||
)
|
||||
process_finder.add_edenfs(
|
||||
proc_utils.add_edenfs(
|
||||
5678,
|
||||
"/home/someuser/.eden",
|
||||
cmdline=["edenfs", "--edenfs"],
|
||||
set_lockfile=False,
|
||||
)
|
||||
process_finder.add_edenfs(
|
||||
proc_utils.add_edenfs(
|
||||
9876,
|
||||
"/home/someuser/.eden",
|
||||
cmdline=["edenfs", "--edenfs"],
|
||||
set_lockfile=False,
|
||||
)
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual(
|
||||
f"""\
|
||||
<yellow>- Found problem:<reset>
|
||||
@ -189,14 +189,14 @@ kill -9 5678 9876
|
||||
def test_when_differently_configured_edenfs_processes_running_with_rogue_pids(
|
||||
self
|
||||
) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_edenfs(475203, "/tmp/config1/.eden")
|
||||
process_finder.add_edenfs(475304, "/tmp/config1/.eden", set_lockfile=False)
|
||||
process_finder.add_edenfs(475405, "/tmp/config1/.eden", set_lockfile=False)
|
||||
process_finder.add_edenfs(575203, "/tmp/config2/.eden")
|
||||
process_finder.add_edenfs(575304, "/tmp/config2/.eden", set_lockfile=False)
|
||||
process_finder.add_edenfs(575405, "/tmp/config2/.eden", set_lockfile=False)
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_edenfs(475203, "/tmp/config1/.eden")
|
||||
proc_utils.add_edenfs(475304, "/tmp/config1/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(475405, "/tmp/config1/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(575203, "/tmp/config2/.eden")
|
||||
proc_utils.add_edenfs(575304, "/tmp/config2/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(575405, "/tmp/config2/.eden", set_lockfile=False)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
|
||||
self.assert_results(fixer, num_problems=1, num_manual_fixes=1)
|
||||
self.assertEqual(
|
||||
@ -218,18 +218,18 @@ kill -9 475304 475405 575304 575405
|
||||
# pid if edenfs was in the middle of (re)starting. Therefore we intentionally
|
||||
# only report rogue processes when we can actually confirm there is more than
|
||||
# one edenfs process running for a given directory.
|
||||
process_finder = self.make_process_finder()
|
||||
proc_utils = self.make_proc_utils()
|
||||
# In config1/ replace the lock file contents with a different process ID
|
||||
process_finder.add_edenfs(123203, "/tmp/config1/.eden", set_lockfile=False)
|
||||
process_finder.set_file_contents("/tmp/config1/.eden/lock", b"9765\n")
|
||||
proc_utils.add_edenfs(123203, "/tmp/config1/.eden", set_lockfile=False)
|
||||
proc_utils.set_file_contents("/tmp/config1/.eden/lock", b"9765\n")
|
||||
# In config2/ do not write a lock file at all
|
||||
process_finder.add_edenfs(123456, "/tmp/config2/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(123456, "/tmp/config2/.eden", set_lockfile=False)
|
||||
# In config3/ report two separate edenfs processes, with one legitimate rogue
|
||||
# process
|
||||
process_finder.add_edenfs(123900, "/tmp/config3/.eden")
|
||||
process_finder.add_edenfs(123991, "/tmp/config3/.eden", set_lockfile=False)
|
||||
proc_utils.add_edenfs(123900, "/tmp/config3/.eden")
|
||||
proc_utils.add_edenfs(123991, "/tmp/config3/.eden", set_lockfile=False)
|
||||
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual(
|
||||
out,
|
||||
f"""\
|
||||
@ -241,15 +241,15 @@ kill -9 123991
|
||||
)
|
||||
|
||||
def test_when_lock_file_op_has_io_exception(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_edenfs(
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_edenfs(
|
||||
475203, "/tmp/eden_test.68yxptnx/.eden", set_lockfile=False
|
||||
)
|
||||
process_finder.add_edenfs(
|
||||
proc_utils.add_edenfs(
|
||||
475304, "/tmp/eden_test.68yxptnx/.eden", set_lockfile=False
|
||||
)
|
||||
with self.assertLogs() as logs_assertion:
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual("", out)
|
||||
self.assert_results(fixer, num_problems=0)
|
||||
logs = "\n".join(logs_assertion.output)
|
||||
@ -260,16 +260,16 @@ kill -9 123991
|
||||
)
|
||||
|
||||
def test_when_lock_file_data_is_garbage(self) -> None:
|
||||
process_finder = self.make_process_finder()
|
||||
process_finder.add_edenfs(
|
||||
proc_utils = self.make_proc_utils()
|
||||
proc_utils.add_edenfs(
|
||||
475203, "/tmp/eden_test.68yxptnx/.eden", set_lockfile=False
|
||||
)
|
||||
process_finder.add_edenfs(
|
||||
proc_utils.add_edenfs(
|
||||
475304, "/tmp/eden_test.68yxptnx/.eden", set_lockfile=False
|
||||
)
|
||||
process_finder.set_file_contents("/tmp/eden_test.68yxptnx/.eden/lock", b"asdf")
|
||||
proc_utils.set_file_contents("/tmp/eden_test.68yxptnx/.eden/lock", b"asdf")
|
||||
with self.assertLogs() as logs_assertion:
|
||||
fixer, out = self.run_check(process_finder, dry_run=False)
|
||||
fixer, out = self.run_check(proc_utils, dry_run=False)
|
||||
self.assertEqual("", out)
|
||||
self.assert_results(fixer, num_problems=0)
|
||||
self.assertIn(
|
||||
|
@ -31,7 +31,7 @@ class NfsTest(DoctorTestBase):
|
||||
dry_run,
|
||||
instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
expected = f"""\
|
||||
@ -140,7 +140,7 @@ The Mercurial data directory for {v.client_path}/.hg/sharedpath is at\
|
||||
dry_run,
|
||||
instance.mount_table,
|
||||
fs_util=FakeFsUtil(),
|
||||
process_finder=self.make_process_finder(),
|
||||
proc_utils=self.make_proc_utils(),
|
||||
out=out,
|
||||
)
|
||||
v.stdout = out.getvalue()
|
||||
|
@ -30,7 +30,7 @@ from . import (
|
||||
doctor as doctor_mod,
|
||||
filesystem,
|
||||
mtab,
|
||||
process_finder,
|
||||
proc_utils,
|
||||
redirect as redirect_mod,
|
||||
stats as stats_mod,
|
||||
subcmd as subcmd_mod,
|
||||
@ -743,7 +743,7 @@ class DoctorCmd(Subcmd):
|
||||
args.dry_run,
|
||||
mount_table=mtab.new(),
|
||||
fs_util=filesystem.LinuxFsUtil(),
|
||||
process_finder=process_finder.new(),
|
||||
proc_utils=proc_utils.new(),
|
||||
)
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ from pathlib import Path
|
||||
from typing import Iterable, List, NamedTuple, Optional, Tuple
|
||||
|
||||
|
||||
log: logging.Logger = logging.getLogger("eden.fs.cli.process_finder")
|
||||
log: logging.Logger = logging.getLogger("eden.fs.cli.proc_utils")
|
||||
ProcessID = int
|
||||
|
||||
|
||||
@ -92,7 +92,14 @@ except ImportError:
|
||||
return None
|
||||
|
||||
|
||||
class ProcessFinder(abc.ABC):
|
||||
class ProcUtils(abc.ABC):
|
||||
"""ProcUtils provides APIs for querying running processes on the system.
|
||||
|
||||
This API helps abstract out platform-specific logic that varies across Linux, Mac,
|
||||
and Windows. These APIs are grouped together in class (instead of just standalone
|
||||
functions) primarily to make it easier to stub out this logic during unit tests.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_edenfs_processes(self) -> Iterable[EdenFSProcess]:
|
||||
"""Returns a list of running EdenFS processes on the system."""
|
||||
@ -110,17 +117,17 @@ class ProcessFinder(abc.ABC):
|
||||
return path.read_bytes()
|
||||
|
||||
|
||||
class NopProcessFinder(ProcessFinder):
|
||||
class NopProcUtils(ProcUtils):
|
||||
def get_edenfs_processes(self) -> Iterable[EdenFSProcess]:
|
||||
return []
|
||||
|
||||
def get_process_start_time(self, pid: int) -> float:
|
||||
raise NotImplementedError(
|
||||
"NopProcessFinder does not currently implement get_process_start_time()"
|
||||
"NopProcUtils does not currently implement get_process_start_time()"
|
||||
)
|
||||
|
||||
|
||||
class LinuxProcessFinder(ProcessFinder):
|
||||
class LinuxProcUtils(ProcUtils):
|
||||
proc_path = Path("/proc")
|
||||
_system_boot_time: Optional[float] = None
|
||||
_jiffies_per_sec: Optional[int] = None
|
||||
@ -253,7 +260,7 @@ class LinuxProcessFinder(ProcessFinder):
|
||||
return jps
|
||||
|
||||
|
||||
def new() -> ProcessFinder:
|
||||
def new() -> ProcUtils:
|
||||
if platform.system() == "Linux":
|
||||
return LinuxProcessFinder()
|
||||
return NopProcessFinder()
|
||||
return LinuxProcUtils()
|
||||
return NopProcUtils()
|
@ -18,7 +18,7 @@ from . import (
|
||||
doctor as doctor_mod,
|
||||
filesystem,
|
||||
mtab,
|
||||
process_finder,
|
||||
proc_utils,
|
||||
stats as stats_mod,
|
||||
ui as ui_mod,
|
||||
)
|
||||
@ -79,7 +79,7 @@ def print_eden_doctor_report(instance: EdenInstance, out: IO[bytes]) -> None:
|
||||
dry_run=dry_run,
|
||||
mount_table=mtab.new(),
|
||||
fs_util=filesystem.LinuxFsUtil(),
|
||||
process_finder=process_finder.new(),
|
||||
proc_utils=proc_utils.new(),
|
||||
out=ui_mod.PlainOutput(doctor_output),
|
||||
)
|
||||
out.write(
|
||||
|
@ -14,24 +14,24 @@ import time
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
from eden.fs.cli import process_finder
|
||||
from eden.fs.cli.proc_utils import BuildInfo, EdenFSProcess, LinuxProcUtils
|
||||
|
||||
|
||||
class FakeEdenFSProcess(process_finder.EdenFSProcess):
|
||||
build_info: process_finder.BuildInfo = process_finder.BuildInfo()
|
||||
class FakeEdenFSProcess(EdenFSProcess):
|
||||
build_info: BuildInfo = BuildInfo()
|
||||
|
||||
def get_build_info(self) -> process_finder.BuildInfo:
|
||||
def get_build_info(self) -> BuildInfo:
|
||||
return self.build_info
|
||||
|
||||
|
||||
_default_start_age = datetime.timedelta(hours=1)
|
||||
|
||||
|
||||
class FakeProcessFinder(process_finder.LinuxProcessFinder):
|
||||
class FakeProcUtils(LinuxProcUtils):
|
||||
_file_contents: Dict[Path, Union[bytes, Exception]] = {}
|
||||
_process_stat: Dict[int, os.stat_result] = {}
|
||||
_default_uid: int
|
||||
_build_info: Dict[int, process_finder.BuildInfo] = {}
|
||||
_build_info: Dict[int, BuildInfo] = {}
|
||||
|
||||
def __init__(self, tmp_dir: str, default_uid: Optional[int] = None) -> None:
|
||||
self.proc_path = Path(tmp_dir)
|
||||
@ -44,7 +44,7 @@ class FakeProcessFinder(process_finder.LinuxProcessFinder):
|
||||
uid: Optional[int] = None,
|
||||
comm: Optional[str] = None,
|
||||
fds: Optional[Dict[int, str]] = None,
|
||||
build_info: Optional[process_finder.BuildInfo] = None,
|
||||
build_info: Optional[BuildInfo] = None,
|
||||
ppid: int = 1,
|
||||
start_age: datetime.timedelta = _default_start_age,
|
||||
) -> None:
|
||||
@ -86,7 +86,7 @@ class FakeProcessFinder(process_finder.LinuxProcessFinder):
|
||||
cmdline: Optional[List[str]] = None,
|
||||
build_time: int = 0,
|
||||
start_age: datetime.timedelta = _default_start_age,
|
||||
) -> process_finder.BuildInfo:
|
||||
) -> BuildInfo:
|
||||
"""Add a fake EdenFS instance.
|
||||
Note that this will add 2 processes: the main EdenFS process with the
|
||||
specified PID, and its corresponding privhelper process using PID+1
|
||||
@ -202,7 +202,7 @@ class FakeProcessFinder(process_finder.LinuxProcessFinder):
|
||||
eden_dir: Optional[Path],
|
||||
holding_lock: Optional[bool],
|
||||
) -> FakeEdenFSProcess:
|
||||
build_info = self._build_info.get(pid, process_finder.BuildInfo())
|
||||
build_info = self._build_info.get(pid, BuildInfo())
|
||||
p = FakeEdenFSProcess(
|
||||
pid=pid,
|
||||
cmdline=cmdline,
|
||||
@ -283,15 +283,15 @@ class FakeProcessFinder(process_finder.LinuxProcessFinder):
|
||||
return f"{pid} ({command}) S {stat_fields_str}\n"
|
||||
|
||||
|
||||
def make_edenfs_build_info(build_time: int) -> process_finder.BuildInfo:
|
||||
def make_edenfs_build_info(build_time: int) -> BuildInfo:
|
||||
if build_time == 0:
|
||||
# Return an empty BuildInfo if the build time is 0
|
||||
return process_finder.BuildInfo()
|
||||
return BuildInfo()
|
||||
|
||||
utc = datetime.timezone.utc
|
||||
build_datetime = datetime.datetime.fromtimestamp(build_time, tz=utc)
|
||||
revision = "1" * 40
|
||||
return process_finder.BuildInfo(
|
||||
return BuildInfo(
|
||||
package_name="fb-eden",
|
||||
package_version=build_datetime.strftime("%Y%m%d"),
|
||||
package_release=build_datetime.strftime("%H%M%S"),
|
@ -15,27 +15,27 @@ from datetime import timedelta
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from eden.fs.cli.process_finder import BuildInfo, EdenFSProcess
|
||||
from eden.fs.cli.test.lib.fake_process_finder import FakeProcessFinder
|
||||
from eden.fs.cli.proc_utils import BuildInfo, EdenFSProcess
|
||||
from eden.fs.cli.test.lib.fake_proc_utils import FakeProcUtils
|
||||
|
||||
|
||||
class ProcessFinderTests(unittest.TestCase):
|
||||
class ProcUtilsTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.maxDiff: Optional[int] = None
|
||||
self.tmpdir = Path(tempfile.mkdtemp(prefix="eden_test."))
|
||||
self.addCleanup(shutil.rmtree, self.tmpdir)
|
||||
self.process_finder = FakeProcessFinder(str(self.tmpdir))
|
||||
self.proc_utils = FakeProcUtils(str(self.tmpdir))
|
||||
|
||||
def test_find_edenfs(self) -> None:
|
||||
# Add some non-EdenFS processes
|
||||
self.process_finder.add_process(pid=1111, uid=99, cmdline=["sleep", "60"])
|
||||
self.process_finder.add_process(pid=7868, uid=99, cmdline=["bash"])
|
||||
self.proc_utils.add_process(pid=1111, uid=99, cmdline=["sleep", "60"])
|
||||
self.proc_utils.add_process(pid=7868, uid=99, cmdline=["bash"])
|
||||
|
||||
# Add a couple EdenFS processes owned by user 99
|
||||
# Set counters to indicate that process 1234 has done a checkout recently.
|
||||
build_time_1234 = 0
|
||||
start_age_1234 = timedelta(days=1)
|
||||
self.process_finder.add_edenfs(
|
||||
self.proc_utils.add_edenfs(
|
||||
pid=1234,
|
||||
uid=99,
|
||||
eden_dir="/home/nobody/eden_dir_1",
|
||||
@ -44,7 +44,7 @@ class ProcessFinderTests(unittest.TestCase):
|
||||
)
|
||||
build_time_4567 = 1577836800 # 2020-01-01 00:00:00, UTC
|
||||
start_age_4567 = timedelta(hours=4)
|
||||
self.process_finder.add_edenfs(
|
||||
self.proc_utils.add_edenfs(
|
||||
pid=4567,
|
||||
uid=99,
|
||||
eden_dir="/home/nobody/local/.eden",
|
||||
@ -56,7 +56,7 @@ class ProcessFinderTests(unittest.TestCase):
|
||||
# Add an EdenFS processes owned by user 65534
|
||||
build_time_9999 = 1576240496 # 2019-12-13 12:34:56 UTC
|
||||
start_age_9999 = timedelta(hours=27)
|
||||
self.process_finder.add_edenfs(
|
||||
self.proc_utils.add_edenfs(
|
||||
pid=9999,
|
||||
uid=65534,
|
||||
eden_dir="/data/users/nfsnobody/.eden",
|
||||
@ -65,7 +65,7 @@ class ProcessFinderTests(unittest.TestCase):
|
||||
)
|
||||
|
||||
# Call get_edenfs_processes() and check the results
|
||||
found_processes = {p.pid: p for p in self.process_finder.get_edenfs_processes()}
|
||||
found_processes = {p.pid: p for p in self.proc_utils.get_edenfs_processes()}
|
||||
found_minus_cmdline = {
|
||||
p.pid: p._replace(cmdline=[]) for p in found_processes.values()
|
||||
}
|
||||
@ -127,13 +127,13 @@ class ProcessFinderTests(unittest.TestCase):
|
||||
|
||||
# Check the process start times
|
||||
self.assert_age_near(
|
||||
start_age_1234, self.process_finder.get_process_start_time(1234)
|
||||
start_age_1234, self.proc_utils.get_process_start_time(1234)
|
||||
)
|
||||
self.assert_age_near(
|
||||
start_age_4567, self.process_finder.get_process_start_time(4567)
|
||||
start_age_4567, self.proc_utils.get_process_start_time(4567)
|
||||
)
|
||||
self.assert_age_near(
|
||||
start_age_9999, self.process_finder.get_process_start_time(9999)
|
||||
start_age_9999, self.proc_utils.get_process_start_time(9999)
|
||||
)
|
||||
|
||||
def assert_age_near(self, age: timedelta, timestamp: float) -> None:
|
||||
|
Loading…
Reference in New Issue
Block a user