def ceph_conf_file_fs(request: SubRequest, fs: fake_filesystem.FakeFilesystem): """ This fixture uses pyfakefs to stub filesystem calls and return any files created with the parent `fs` fixture. """ fs.add_real_file( # pyright: reportUnknownMemberType=false os.path.join( DATA_DIR, request.param # pyright: reportUnknownArgumentType=false ), target_path='/etc/ceph/ceph.conf') yield fs
def test_not_mounted(fs: fake_filesystem.FakeFilesystem) -> None: fs.add_real_file( source_path=os.path.join(DATA_DIR, "mounts_without_aquarium.raw"), target_path="/proc/mounts", ) from gravel.controllers.nodes.systemdisk import SystemDisk systemdisk = SystemDisk() assert not systemdisk.mounted
def test_silly_mounts(fs: fake_filesystem.FakeFilesystem) -> None: fs.add_real_file( source_path=os.path.join(DATA_DIR, "mounts_silly.raw"), target_path="/proc/mounts", ) from gravel.controllers.nodes.systemdisk import MountEntry, get_mounts lst: List[MountEntry] = get_mounts() assert len(lst) == 2 assert lst[0].source == "foo" and lst[0].dest == "bar" assert lst[1].source == "asd" and lst[1].dest == "fgh"
def test_get_mounts(fs: fake_filesystem.FakeFilesystem) -> None: fs.add_real_file( source_path=os.path.join(DATA_DIR, "mounts_with_aquarium.raw"), target_path="/proc/mounts", ) from gravel.controllers.nodes.systemdisk import MountEntry, get_mounts lst: List[MountEntry] = get_mounts() found = False for entry in lst: if (entry.source == "/dev/mapper/aquarium-systemdisk" and entry.dest == "/var/lib/aquarium-system"): found = True break assert found
def fake_filesystem(fs: FakeFilesystem) -> FakeFilesystem: """A pytest fixture which mocks the filesystem before each test.""" # The "fs" argument triggers pyfakefs' own pytest fixture to register # After pyfakefs has started all filesystem actions will happen on a fake in-memory filesystem # Proxy access to certifi's certificate authority bundle to the real filesystem # This is required to be able to send HTTP requests using requests fs.add_real_file(certifi.where()) # Proxy access to package data to the real filesystem fs.add_real_directory(os.path.join(os.path.dirname(__file__), "../lean/ssh")) # Create a fake home directory and set the cwd to an empty directory fs.create_dir(Path.home() / "testing") os.chdir(Path.home() / "testing") # Reset all singletons so Path instances get recreated # Path instances are bound to the filesystem that was active at the time of their creation # When the filesystem changes, old Path instances bound to previous filesystems may cause weird behavior container.reset_singletons() return fs
def test_ceph_conf(fs: fake_filesystem.FakeFilesystem): # default location fs.add_real_file( # pyright: reportUnknownMemberType=false os.path.join(TEST_DIR, 'data/default_ceph.conf'), target_path='/etc/ceph/ceph.conf' ) Mgr() Mon() # custom location conf_file = '/foo/bar/baz.conf' fs.add_real_file( os.path.join(TEST_DIR, 'data/default_ceph.conf'), target_path=conf_file ) Mgr(conf_file=conf_file) Mon(conf_file=conf_file) # invalid location conf_file = "missing.conf" with pytest.raises(FileNotFoundError, match=conf_file): Mgr(conf_file=conf_file) Mon(conf_file=conf_file)
def test_ceph_conf(fs: fake_filesystem.FakeFilesystem, mocker: MockerFixture): mock_ceph_modules(mocker) from gravel.controllers.orch.ceph import Ceph # default location fs.add_real_file( # pyright: reportUnknownMemberType=false os.path.join(TEST_DIR, "data/default_ceph.conf"), target_path="/etc/ceph/ceph.conf", ) ceph = Ceph() ceph._check_config() # pyright: reportPrivateUsage=false # custom location conf_file = "/foo/bar/baz.conf" fs.add_real_file(os.path.join(TEST_DIR, "data/default_ceph.conf"), target_path=conf_file) ceph = Ceph(conf_file=conf_file) ceph._check_config() # pyright: reportPrivateUsage=false # invalid location conf_file = "missing.conf" with pytest.raises(FileNotFoundError, match=conf_file): ceph = Ceph(conf_file=conf_file) ceph._check_config() # pyright: reportPrivateUsage=false
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_network( mocker: MockerFixture, fs: fake_filesystem.FakeFilesystem, ) -> None: async def mock_restart_network( cmd: List[str], ) -> Tuple[int, Optional[str], Optional[str]]: assert cmd == ["systemctl", "restart", "network.service"] return 0, None, None mocker.patch( "gravel.controllers.resources.network.aqr_run_cmd", new=mock_restart_network, ) from gravel.controllers.resources.network import ( InterfaceConfigModel, InterfaceModel, Network, RouteModel, ) fs.create_dir( "/sys/devices/pci0000:00/0000:00:02.0/0000:01:00.0/net/enp1s0") fs.create_symlink( "/sys/class/net/enp1s0/device", "/sys/devices/pci0000:00/0000:00:02.0/0000:01:00.0/net/enp1s0", ) fs.create_dir("/sys/class/net/virbr0") fs.add_real_file( source_path=os.path.join(DATA_DIR, "ifcfg-eth0"), target_path="/etc/sysconfig/network/ifcfg-eth0", ) fs.create_file("/etc/sysconfig/network/ifcfg-eth0~") fs.create_file("/etc/sysconfig/network/ifcfg-eth0.rpmsave") fs.create_file("/etc/sysconfig/network/ifcfg-lo") fs.add_real_file( source_path=os.path.join(DATA_DIR, "config"), target_path="/etc/sysconfig/network/config", ) network = Network(5.0) assert await network._should_tick() await network._do_tick() ifaces = network.interfaces assert len(ifaces) > 0 assert "eth0" in ifaces assert ifaces["eth0"].name == "eth0" assert ifaces["eth0"].config.bootproto == "dhcp" assert ifaces["eth0"].config.ipaddr == "" assert ifaces["eth0"].config.bonding_slaves == [] assert "eth0~" not in ifaces assert "eth0.rpmsave" not in ifaces assert "enp1s0" in ifaces assert ifaces["enp1s0"].config is None assert "virbr0" not in ifaces assert "lo" not in ifaces assert network.nameservers == [] assert network.routes == [] ifaces["bond0"] = InterfaceModel( name="bond0", config=InterfaceConfigModel( bootproto="static", ipaddr="192.168.121.10/24", bonding_slaves=["enp1s0", "enp2s0"], ), ) await network.apply_config( ifaces, ["8.8.8.8", "1.1.1.1"], routes=[ RouteModel(destination="default", gateway="192.168.121.1"), RouteModel(destination="192.168.0.0/16", interface="bond0"), ], ) ifaces = network.interfaces assert "bond0" in ifaces assert os.path.exists("/etc/sysconfig/network/ifcfg-enp1s0") assert os.path.exists("/etc/sysconfig/network/ifcfg-enp2s0") assert network.nameservers == ["8.8.8.8", "1.1.1.1"] assert os.path.exists("/etc/sysconfig/network/routes") assert os.path.exists("/etc/sysconfig/network/ifroute-bond0") assert len(network.routes) == 2