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:
Adam Simpkins 2020-04-03 16:48:29 -07:00 committed by Facebook GitHub Bot
parent 17a3c9124d
commit dbbb0d64c8
12 changed files with 143 additions and 143 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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())

View File

@ -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(

View File

@ -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()

View File

@ -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(),
)

View File

@ -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()

View File

@ -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(

View File

@ -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"),

View File

@ -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: