def test_init_state_fail(gstate: GlobalState, fs: fake_filesystem.FakeFilesystem) -> None: from gravel.controllers.nodes.mgr import NodeError if fs.exists("/etc/aquarium/node.json"): fs.remove("/etc/aquarium/node.json") nodemgr = NodeMgr(gstate) assert fs.exists("/etc/aquarium/node.json") for f in fs.listdir("/etc/aquarium"): fs.remove(f"/etc/aquarium/{f}") assert fs.exists("/etc/aquarium") fs.rmdir("/etc/aquarium") fs.create_dir("/etc/aquarium", perm_bits=0o500) throws = False try: nodemgr._init_state() except NodeError: throws = True assert throws # clean up for f in fs.listdir("/etc/aquarium"): fs.remove(f"/etc/aquarium/{f}") fs.rmdir("/etc/aquarium")
async def test_mount_error( gstate: GlobalState, fs: fake_filesystem.FakeFilesystem, mocker: MockerFixture, ) -> None: async def mock_call( cmd: List[str], ) -> Tuple[int, Optional[str], Optional[str]]: raise Exception("Failed mount.") mocker.patch( "gravel.controllers.nodes.systemdisk.aqr_run_cmd", new=mock_call ) from gravel.controllers.nodes.systemdisk import MountError, SystemDisk systemdisk = SystemDisk(gstate) asserted = False try: await systemdisk.mount() except AssertionError: asserted = True assert asserted fs.create_file("/dev/mapper/aquarium-systemdisk") throws = False try: await systemdisk.mount() except MountError: throws = True assert throws assert fs.exists("/var/lib/aquarium-system")
def test_ctor(gstate: GlobalState, fs: fake_filesystem.FakeFilesystem) -> None: NodeMgr(gstate) assert fs.exists("/etc/aquarium/node.json") # clean up for f in fs.listdir("/etc/aquarium"): fs.remove(f"/etc/aquarium/{f}")
async def test_set_hostname( mocker: MockerFixture, fs: fake_filesystem.FakeFilesystem, get_data_contents: Callable[[str, str], str], ) -> None: called_set_hostname = False async def mock_call( cmd: List[str], ) -> Tuple[int, Optional[str], Optional[str]]: nonlocal called_set_hostname called_set_hostname = True assert cmd[0] == "hostnamectl" assert cmd[1] == "set-hostname" assert cmd[2] == "foobar" return 0, None, None async def mock_call_fail( cmd: List[str], ) -> Tuple[int, Optional[str], Optional[str]]: return 1, None, "oops" from gravel.controllers.nodes.host import HostnameCtlError, set_hostname mocker.patch("socket.gethostname", return_value="myhostname") mocker.patch("gravel.controllers.nodes.host.aqr_run_cmd", new=mock_call_fail) throws = False try: await set_hostname("foobar") except HostnameCtlError as e: assert "oops" in e.message throws = True assert throws assert not fs.exists("/etc/hosts") mocker.patch("gravel.controllers.nodes.host.aqr_run_cmd", new=mock_call) fs.create_file("/etc/hosts") hosts = get_data_contents(DATA_DIR, "hosts.raw") with open("/etc/hosts", "w") as f: f.write(hosts) await set_hostname("foobar") assert called_set_hostname with open("/etc/hosts", "r") as f: text = f.read() assert text.count("myhostname") == 0 assert text.count("foobar") == 2
def test_fail_ctor(gstate: GlobalState, fs: fake_filesystem.FakeFilesystem) -> None: from gravel.controllers.nodes.mgr import NodeError if fs.exists("/etc/aquarium/node.json"): fs.remove("/etc/aquarium/node.json") fs.create_dir("/etc/aquarium/node.json") throws = False try: NodeMgr(gstate) except NodeError: throws = True except Exception: assert False assert throws # clean up fs.rmdir("/etc/aquarium/node.json")
async def test_enable( gstate: GlobalState, fs: fake_filesystem.FakeFilesystem, mocker: MockerFixture, ) -> None: from gravel.controllers.nodes.systemdisk import ( MountError, OverlayError, SystemDisk, ) async def mount_fail() -> None: raise MountError("Failed mount.") overlayed_paths = [] bindmounts = [] async def mock_call( cmd: List[str], ) -> Tuple[int, Optional[str], Optional[str]]: if cmd[2] == "overlay": assert "lower" in cmd[4] lowerstr = (cmd[4].split(","))[0] lower = (lowerstr.split("="))[1] overlayed_paths.append(lower) elif cmd[1] == "--bind": assert len(cmd) == 4 bindmounts.append(cmd[3]) else: raise Exception(f"Unknown call: {cmd}") return 0, None, None # ensure we don't have a mounted fs fs.add_real_file( source_path=os.path.join(DATA_DIR, "mounts_without_aquarium.raw"), target_path="/proc/mounts", ) systemdisk = SystemDisk(gstate) assert not systemdisk.mounted systemdisk.mount = mount_fail mocker.patch( "gravel.controllers.nodes.systemdisk.aqr_run_cmd", new=mock_call ) throws = False try: await systemdisk.enable() except OverlayError as e: assert "failed mount" in e.message.lower() throws = True assert throws systemdisk.mount = mocker.AsyncMock() for upper in systemdisk._overlaydirs.keys(): fs.create_dir(f"/var/lib/aquarium-system/{upper}/overlay") fs.create_dir(f"/var/lib/aquarium-system/{upper}/temp") for ours in systemdisk._bindmounts.keys(): fs.create_dir(f"/var/lib/aquarium-system/{ours}") await systemdisk.enable() for lower in systemdisk._overlaydirs.values(): assert fs.exists(lower) assert lower in overlayed_paths for theirs in systemdisk._bindmounts.values(): assert fs.exists(theirs) assert theirs in bindmounts
async def test_init(fs: fake_filesystem.FakeFilesystem) -> None: from gravel.controllers.deployment.mgr import ( AlreadyInitedError, DeploymentMgr, InitError, InitStateEnum, NotPreInitedError, ) mgr = DeploymentMgr() raised: bool = False try: await mgr.init() except NotPreInitedError: raised = True except Exception: assert False assert raised mgr._preinited = True mgr._inited = True raised = False try: await mgr.init() except AlreadyInitedError: raised = True except Exception: assert False assert raised mgr._preinited = True mgr._inited = False await mgr.init() # succeeds because we're not installed yet. assert mgr._init_state < InitStateEnum.INSTALLED # test canonical case, we're installed but don't have a state yet. fs.reset() mgr = DeploymentMgr() mgr._preinited = True mgr._inited = False mgr._init_state = InitStateEnum.INSTALLED assert not fs.exists("/etc/aquarium") await mgr.init() assert mgr._inited assert fs.exists("/etc/aquarium/") assert fs.isdir("/etc/aquarium") assert fs.exists("/etc/aquarium/state.json") # ensure we have a malformed file in /etc/aquarium/state.json fs.reset() mgr = DeploymentMgr() mgr._preinited = True mgr._inited = False mgr._init_state = InitStateEnum.INSTALLED fs.create_dir("/etc/aquarium") with open("/etc/aquarium/state.json", "w") as f: f.write("foobarbaz") raised = False try: await mgr.init() except InitError: raised = True except Exception: assert False assert raised # now we have something in state.json that is not a file fs.reset() mgr = DeploymentMgr() mgr._preinited = True mgr._inited = False mgr._init_state = InitStateEnum.INSTALLED fs.create_dir("/etc/aquarium/state.json") raised = False try: await mgr.init() except InitError: raised = True except Exception: assert False assert raised