Esempio n. 1
0
async def test_deploy_checks(gstate: GlobalState, nodemgr: NodeMgr) -> None:

    from gravel.controllers.nodes.deployment import NodeStageEnum
    from gravel.controllers.nodes.mgr import (
        DeployParamsModel,
        NodeCantDeployError,
        NodeInitStage,
        NodeNotStartedError,
    )

    nodemgr._init_stage = NodeInitStage.NONE
    throws = False
    try:
        await nodemgr.deploy(
            DeployParamsModel(hostname="barbaz", ntpaddr="my.ntp.addr")
        )
    except NodeNotStartedError:
        throws = True
    assert throws

    nodemgr._init_stage = NodeInitStage.PREPARE
    throws = False
    try:
        await nodemgr.deploy(
            DeployParamsModel(hostname="barbaz", ntpaddr="my.ntp.addr")
        )
    except NodeNotStartedError:
        throws = True
    assert throws

    nodemgr._init_stage = NodeInitStage.AVAILABLE
    nodemgr._deployment._state._stage = NodeStageEnum.ERROR
    throws = False
    try:
        await nodemgr.deploy(
            DeployParamsModel(hostname="barbaz", ntpaddr="my.ntp.addr")
        )
    except NodeCantDeployError:
        throws = True
    assert throws

    nodemgr._deployment._state._stage = NodeStageEnum.NONE
    throws = False
    try:
        await nodemgr.deploy(
            DeployParamsModel(hostname="", ntpaddr="my.ntp.addr")
        )
    except NodeCantDeployError as e:
        assert e.message == "missing hostname parameter"
        throws = True
    assert throws

    throws = False
    try:
        await nodemgr.deploy(DeployParamsModel(hostname="barbaz", ntpaddr=""))
    except NodeCantDeployError as e:
        assert e.message == "missing ntp server address"
        throws = True
    assert throws
Esempio n. 2
0
async def test_deploy_check_disk_solution(gstate: GlobalState,
                                          mocker: MockerFixture,
                                          nodemgr: NodeMgr) -> None:
    from gravel.controllers.nodes.disks import DiskSolution
    from gravel.controllers.nodes.mgr import NodeCantDeployError, NodeInitStage

    nodemgr._init_stage = NodeInitStage.AVAILABLE

    def empty_solution(gstate: GlobalState) -> DiskSolution:
        return DiskSolution()

    def fail_solution(gstate: GlobalState) -> DiskSolution:
        return DiskSolution(possible=True)

    mocker.patch("gravel.controllers.nodes.disks.Disks.gen_solution",
                 new=empty_solution)
    throws = False
    try:
        await nodemgr.deploy(
            DeployParamsModel(hostname="barbaz", ntpaddr="my.ntp.addr"))
    except NodeCantDeployError as e:
        assert e.message == "No possible deployment solution found."
        throws = True
    assert throws

    mocker.patch("gravel.controllers.nodes.disks.Disks.gen_solution",
                 new=fail_solution)
    throws = False
    try:
        await nodemgr.deploy(
            DeployParamsModel(hostname="barbaz", ntpaddr="my.ntp.addr"))
    except AssertionError:
        throws = True
    assert throws
Esempio n. 3
0
async def test_join_checks(gstate: GlobalState) -> None:

    from gravel.controllers.nodes.mgr import (
        JoinParamsModel,
        NodeCantJoinError,
        NodeError,
        NodeInitStage,
        NodeNotStartedError,
    )

    nodemgr = NodeMgr(gstate)

    throws = False
    nodemgr._init_stage = NodeInitStage.NONE
    try:
        await nodemgr.join(
            "1.2.3.4", "751b-51fd-10d7-f7b4", JoinParamsModel(hostname="foobar")
        )
    except NodeNotStartedError:
        throws = True
    assert throws

    throws = False
    nodemgr._init_stage = NodeInitStage.STARTED
    try:
        await nodemgr.join(
            "1.2.3.4", "751b-51fd-10d7-f7b4", JoinParamsModel(hostname="foobar")
        )
    except NodeCantJoinError:
        throws = True
    assert throws

    throws = False
    nodemgr._init_stage = NodeInitStage.AVAILABLE
    try:
        await nodemgr.join(
            "1.2.3.4", "751b-51fd-10d7-f7b4", JoinParamsModel(hostname="")
        )
    except NodeError as e:
        throws = True
        assert "hostname" in e.message
    assert throws
Esempio n. 4
0
async def test_bootstrap_finisher_cb(gstate: GlobalState,
                                     mocker: MockerFixture,
                                     nodemgr: NodeMgr) -> None:

    from gravel.controllers.nodes.mgr import NodeInitStage

    nodemgr._init_stage = NodeInitStage.NONE
    assert await expect_assertion(nodemgr._post_bootstrap_finisher(True, None))
    nodemgr._init_stage = NodeInitStage.PREPARE
    assert await expect_assertion(nodemgr._post_bootstrap_finisher(True, None))
    nodemgr._init_stage = NodeInitStage.STARTED
    assert await expect_assertion(nodemgr._post_bootstrap_finisher(True, None))

    nodemgr._init_stage = NodeInitStage.AVAILABLE
    nodemgr._save_state = mocker.AsyncMock()
    nodemgr._post_bootstrap_config = mocker.AsyncMock()

    await nodemgr._post_bootstrap_finisher(True, None)

    nodemgr._save_state.assert_called_once()  # type: ignore
    nodemgr._post_bootstrap_config.assert_called_once()  # type: ignore
Esempio n. 5
0
async def test_finish_deployment_cb(gstate: GlobalState, mocker: MockerFixture,
                                    nodemgr: NodeMgr) -> None:

    from gravel.controllers.nodes.mgr import NodeInitStage

    nodemgr._init_stage = NodeInitStage.NONE
    assert await expect_assertion(nodemgr._finish_deployment(True, None))
    nodemgr._init_stage = NodeInitStage.PREPARE
    assert await expect_assertion(nodemgr._finish_deployment(True, None))
    nodemgr._init_stage = NodeInitStage.STARTED
    assert await expect_assertion(nodemgr._finish_deployment(True, None))

    nodemgr._init_stage = NodeInitStage.AVAILABLE
    nodemgr._deployment.finish_deployment = mocker.MagicMock()
    nodemgr._load = mocker.AsyncMock()
    nodemgr._node_start = mocker.AsyncMock()

    await nodemgr._finish_deployment(True, None)

    nodemgr._deployment.finish_deployment.assert_called_once()  # type: ignore
    nodemgr._load.assert_called_once()  # type: ignore
    nodemgr._node_start.assert_called_once()  # type: ignore
Esempio n. 6
0
def test_node_shutdown(gstate: GlobalState, mocker: MockerFixture) -> None:

    from gravel.controllers.nodes.mgr import NodeInitStage, NodeMgr

    class FakeTask:
        called = False

        def cancel(self) -> None:
            self.called = True

    nodemgr = NodeMgr(gstate)
    nodemgr._incoming_task = FakeTask()  # type: ignore
    nodemgr._init_stage = NodeInitStage.NONE
    nodemgr._node_shutdown()
    assert nodemgr._init_stage == NodeInitStage.STOPPING
    assert nodemgr._incoming_task.called
Esempio n. 7
0
async def test_join_check_disk_solution(
    gstate: GlobalState, mocker: MockerFixture, nodemgr: NodeMgr
) -> None:

    from gravel.controllers.nodes.disks import DiskSolution
    from gravel.controllers.nodes.mgr import (
        JoinParamsModel,
        NodeCantJoinError,
        NodeInitStage,
    )

    nodemgr._init_stage = NodeInitStage.AVAILABLE

    def empty_solution(gstate: GlobalState) -> DiskSolution:
        return DiskSolution()

    mocker.patch(
        "gravel.controllers.nodes.disks.Disks.gen_solution", new=empty_solution
    )

    throws = False
    try:
        await nodemgr.join(
            "1.2.3.4", "751b-51fd-10d7-f7b4", JoinParamsModel(hostname="foobar")
        )
    except NodeCantJoinError as e:
        assert e.message == "no disk deployment solution found"
        throws = True
    assert throws

    def fail_solution(gstate: GlobalState) -> DiskSolution:
        return DiskSolution(possible=True)

    mocker.patch(
        "gravel.controllers.nodes.disks.Disks.gen_solution", new=fail_solution
    )

    throws = False
    try:
        await nodemgr.join(
            "1.2.3.4", "751b-51fd-10d7-f7b4", JoinParamsModel(hostname="foobar")
        )
    except AssertionError:
        throws = True
    assert throws
Esempio n. 8
0
async def test_deploy(gstate: GlobalState, mocker: MockerFixture,
                      nodemgr: NodeMgr) -> None:

    from gravel.controllers.auth import UserMgr, UserModel
    from gravel.controllers.inventory.disks import DiskDevice
    from gravel.controllers.nodes.deployment import DeploymentConfig
    from gravel.controllers.nodes.disks import DiskSolution
    from gravel.controllers.nodes.mgr import NodeInitStage

    called_mock_deploy = False

    def mock_solution(gstate: GlobalState) -> DiskSolution:
        return DiskSolution(
            systemdisk=DiskDevice(
                id="foo01",
                name="foo",
                path="/dev/foo",
                product="Foo",
                vendor="Foo Inc",
                size=1000,
                rotational=False,
                available=True,
                rejected_reasons=[],
            ),
            storage=[
                DiskDevice(
                    id="bar01",
                    name="bar",
                    path="/dev/bar",
                    product="Bar",
                    vendor="Bar LLC",
                    size=2000,
                    rotational=False,
                    available=True,
                    rejected_reasons=[],
                ),
                DiskDevice(
                    id="baz01",
                    name="baz",
                    path="/dev/baz",
                    product="Baz",
                    vendor="Baz Ltd",
                    size=2000,
                    rotational=False,
                    available=True,
                    rejected_reasons=[],
                ),
            ],
            storage_size=4000,
            possible=True,
        )

    async def mock_deploy(
        config: DeploymentConfig,
        post_bootstrap_cb: Callable[[bool, Optional[str]], Awaitable[None]],
        finisher: Callable[[bool, Optional[str]], Awaitable[None]],
    ) -> None:

        import inspect

        nonlocal called_mock_deploy
        called_mock_deploy = True

        assert config.hostname == "barbaz"
        assert config.address == "1.2.3.4"
        assert config.token == "751b-51fd-10d7-f7b4"
        assert config.ntp_addr == "my.ntp.addr"
        assert config.disks.system == "/dev/foo"
        assert len(config.disks.storage) == 2
        assert "/dev/bar" in config.disks.storage
        assert "/dev/baz" in config.disks.storage
        assert post_bootstrap_cb is not None
        assert finisher is not None
        assert inspect.iscoroutinefunction(post_bootstrap_cb)
        assert inspect.iscoroutinefunction(finisher)

    mocker.patch("gravel.controllers.nodes.disks.Disks.gen_solution",
                 new=mock_solution)

    nodemgr._init_stage = NodeInitStage.AVAILABLE

    nodemgr._generate_token = mocker.MagicMock(
        return_value="751b-51fd-10d7-f7b4")
    nodemgr._save_token = mocker.AsyncMock()
    nodemgr._deployment.deploy = mock_deploy

    await gstate.store.ensure_connection()

    await nodemgr.deploy(
        DeployParamsModel(hostname="barbaz", ntpaddr="my.ntp.addr"))

    assert called_mock_deploy
    assert nodemgr._token == "751b-51fd-10d7-f7b4"
    assert nodemgr._state.hostname == "barbaz"
    nodemgr._save_token.assert_called_once()  # type: ignore

    ntpaddr = await gstate.store.get("/nodes/ntp_addr")
    assert ntpaddr == "my.ntp.addr"

    usermgr = UserMgr(gstate.store)
    assert await usermgr.exists("admin")
    user: Optional[UserModel] = await usermgr.get("admin")
    assert user is not None
    assert user.username == "admin"
    # We can't test the plain password here because it will fail
    # and we don't care particularly about the password itself, just that
    # the user has been populated. We'll leave for the 'UserMgr' tests to
    # validate the correctness of its operations.
    assert len(user.password) > 0
Esempio n. 9
0
async def test_join(gstate: GlobalState, mocker: MockerFixture,
                    nodemgr: NodeMgr) -> None:

    from uuid import UUID

    from gravel.controllers.inventory.disks import DiskDevice
    from gravel.controllers.nodes.deployment import DeploymentDisksConfig
    from gravel.controllers.nodes.disks import DiskSolution
    from gravel.controllers.nodes.mgr import JoinParamsModel, NodeInitStage

    def mock_solution(gstate: GlobalState) -> DiskSolution:
        return DiskSolution(
            systemdisk=DiskDevice(
                id="foo01",
                name="foo",
                path="/dev/foo",
                product="Foo",
                vendor="Foo Inc",
                size=1000,
                rotational=False,
                available=True,
                rejected_reasons=[],
            ),
            storage=[
                DiskDevice(
                    id="bar01",
                    name="bar",
                    path="/dev/bar",
                    product="Bar",
                    vendor="Bar LLC",
                    size=2000,
                    rotational=False,
                    available=True,
                    rejected_reasons=[],
                ),
                DiskDevice(
                    id="baz01",
                    name="baz",
                    path="/dev/baz",
                    product="Baz",
                    vendor="Baz Ltd",
                    size=2000,
                    rotational=False,
                    available=True,
                    rejected_reasons=[],
                ),
            ],
            storage_size=4000,
            possible=True,
        )

    async def mock_join(
        leader_address: str,
        token: str,
        uuid: UUID,
        hostname: str,
        address: str,
        disks: DeploymentDisksConfig,
    ) -> bool:
        assert leader_address == "10.1.2.3"
        assert token == "751b-51fd-10d7-f7b4"
        assert str(uuid) == "bba35d93-d4a5-48b3-804b-99c406555c89"
        assert hostname == "foobar"
        assert address == "1.2.3.4"
        assert disks.system == "/dev/foo"
        assert len(disks.storage) == 2
        assert "/dev/bar" in disks.storage
        assert "/dev/baz" in disks.storage
        return True

    mocker.patch("gravel.controllers.nodes.disks.Disks.gen_solution",
                 new=mock_solution)

    nodemgr._init_stage = NodeInitStage.AVAILABLE

    nodemgr._deployment.join = mocker.AsyncMock(side_effects=Exception())
    throws = False
    try:
        await nodemgr.join(
            "10.1.2.3",
            "751b-51fd-10d7-f7b4",
            JoinParamsModel(hostname="foobar"),
        )
    except Exception:
        throws = True
    assert throws
    nodemgr._deployment.join.assert_called_once()  # type: ignore

    nodemgr._deployment.join = mocker.AsyncMock(return_value=False)
    res = await nodemgr.join("10.1.2.3", "751b-51fd-10d7-f7b4",
                             JoinParamsModel(hostname="foobar"))
    assert not res
    nodemgr._deployment.join.assert_called_once()  # type: ignore

    nodemgr._save_state = mocker.AsyncMock()
    nodemgr._node_start = mocker.AsyncMock()
    nodemgr._deployment.join = mock_join
    res = await nodemgr.join("10.1.2.3", "751b-51fd-10d7-f7b4",
                             JoinParamsModel(hostname="foobar"))
    assert res
    assert nodemgr._token == "751b-51fd-10d7-f7b4"
    nodemgr._save_state.assert_called_once()  # type: ignore
    nodemgr._node_start.assert_called_once()  # type: ignore