Example #1
0
async def update_cluster_handler(request: web.Request) -> web.Response:
    path, _, _ = await extract_and_validate(request)
    user_id: UserID = request[RQT_USERID_KEY]
    primary_group, std_groups, all_group = await list_user_groups(
        request.app, user_id)

    body = await request.json()
    try:
        updated_cluster = ClusterPatch.parse_obj(body)
        clusters_repo = ClustersRepository(request)
        cluster = await clusters_repo.update_cluster(
            GroupID(primary_group["gid"]),
            [GroupID(g["gid"]) for g in std_groups],
            GroupID(all_group["gid"]),
            path["cluster_id"],
            updated_cluster,
        )
        data = cluster.dict(by_alias=True)
        return web.json_response(data={"data": data}, dumps=json_dumps)
    except ValidationError as exc:
        raise web.HTTPUnprocessableEntity(
            reason=f"Invalid cluster definition: {exc} ") from exc
    except ClusterNotFoundError as exc:
        raise web.HTTPNotFound(reason=f"{exc}")
    except ClusterAccessForbidden as exc:
        raise web.HTTPForbidden(reason=f"{exc}")
Example #2
0
async def test_delete_cluster(
    enable_dev_features: None,
    client: TestClient,
    postgres_db: sa.engine.Engine,
    logged_user: Dict[str, Any],
    second_user: Dict[str, Any],
    cluster: Callable[..., Coroutine[Any, Any, Cluster]],
    faker: Faker,
    user_role: UserRole,
    expected: ExpectedResponse,
):
    # deleting a non-existing cluster returns not found
    url = client.app.router["delete_cluster_handler"].url_for(cluster_id=f"{25}")
    rsp = await client.delete(f"{url}")
    data, error = await assert_status(rsp, expected.not_found)
    if error and user_role in [UserRole.ANONYMOUS, UserRole.GUEST]:
        return
    assert data is None

    # create our own cluster allows us to delete it
    admin_cluster: Cluster = await cluster(GroupID(logged_user["primary_gid"]))
    url = client.app.router["delete_cluster_handler"].url_for(
        cluster_id=f"{admin_cluster.id}"
    )
    rsp = await client.delete(f"{url}")
    data, error = await assert_status(rsp, expected.no_content)
    assert data is None

    # check it was deleted
    result: ResultProxy = postgres_db.execute(
        sa.select([clusters]).where(clusters.c.id == admin_cluster.id)
    )
    assert result.rowcount == 0
Example #3
0
async def list_clusters_handler(request: web.Request) -> web.Response:
    await extract_and_validate(request)
    user_id: UserID = request[RQT_USERID_KEY]

    primary_group, std_groups, all_group = await list_user_groups(
        request.app, user_id)

    clusters_repo = ClustersRepository(request)

    clusters_list: List[Cluster] = await clusters_repo.list_clusters(
        GroupID(primary_group["gid"]),
        [GroupID(g["gid"]) for g in std_groups],
        GroupID(all_group["gid"]),
    )

    data = [d.dict(by_alias=True) for d in clusters_list]

    return web.json_response(data={"data": data}, dumps=json_dumps)
Example #4
0
async def delete_cluster_handler(request: web.Request) -> web.Response:
    path, _, _ = await extract_and_validate(request)
    user_id: UserID = request[RQT_USERID_KEY]
    primary_group, std_groups, all_group = await list_user_groups(
        request.app, user_id)
    clusters_repo = ClustersRepository(request)
    try:
        await clusters_repo.delete_cluster(
            GroupID(primary_group["gid"]),
            [GroupID(g["gid"]) for g in std_groups],
            GroupID(all_group["gid"]),
            path["cluster_id"],
        )
        return web.json_response(status=web.HTTPNoContent.status_code)
    except ClusterNotFoundError as exc:
        raise web.HTTPNotFound(reason=f"{exc}")
    except ClusterAccessForbidden as exc:
        raise web.HTTPForbidden(reason=f"{exc}")
Example #5
0
async def get_cluster_handler(request: web.Request) -> web.Response:
    path, _, _ = await extract_and_validate(request)
    user_id: UserID = request[RQT_USERID_KEY]
    primary_group, std_groups, all_group = await list_user_groups(
        request.app, user_id)

    clusters_repo = ClustersRepository(request)
    try:
        cluster = await clusters_repo.get_cluster(
            GroupID(primary_group["gid"]),
            [GroupID(g["gid"]) for g in std_groups],
            GroupID(all_group["gid"]),
            path["cluster_id"],
        )
        data = cluster.dict(by_alias=True)
        return web.json_response(data={"data": data}, dumps=json_dumps)
    except ClusterNotFoundError as exc:
        raise web.HTTPNotFound(reason=f"{exc}")
    except ClusterAccessForbidden as exc:
        raise web.HTTPForbidden(reason=f"{exc}")
Example #6
0
async def test_update_cluster(
    enable_dev_features: None,
    client: TestClient,
    logged_user: Dict[str, Any],
    second_user: Dict[str, Any],
    all_group: Dict[str, Any],
    cluster: Callable[..., Coroutine[Any, Any, Cluster]],
    user_role: UserRole,
    expected: ExpectedResponse,
    cluster_authentication: Callable[[], Dict[str, Any]],
):
    _PATCH_EXPORT = {"by_alias": True, "exclude_unset": True, "exclude_none": True}
    # check modifying invalid returns not found
    assert client.app
    url = client.app.router["update_cluster_handler"].url_for(cluster_id=f"{25}")
    rsp = await client.patch(
        f"{url}",
        json=ClusterPatch().dict(**_PATCH_EXPORT),
    )
    data, error = await assert_status(rsp, expected.not_found)
    if error and user_role in [UserRole.ANONYMOUS, UserRole.GUEST]:
        return

    # create our own cluster, allows us to modify it
    admin_cluster: Cluster = await cluster(GroupID(logged_user["primary_gid"]))
    url = client.app.router["update_cluster_handler"].url_for(
        cluster_id=f"{admin_cluster.id}"
    )
    # we can modify these simple things
    expected_admin_cluster = admin_cluster.copy()
    for cluster_patch in [
        ClusterPatch(name="My patched cluster name"),
        ClusterPatch(description="My patched cluster description"),
        ClusterPatch(type=ClusterType.ON_PREMISE),
        ClusterPatch(thumbnail="https://placeimg.com/640/480/nature"),
        ClusterPatch(endpoint="https://some_other_endpoint.com"),
        ClusterPatch(authentication=cluster_authentication()),
    ]:
        jsonable_cluster_patch = json.loads(cluster_patch.json(**_PATCH_EXPORT))
        print(f"--> patching cluster with {jsonable_cluster_patch}")
        rsp = await client.patch(f"{url}", json=jsonable_cluster_patch)
        data, error = await assert_status(rsp, expected.ok)
        expected_admin_cluster = expected_admin_cluster.copy(
            update=cluster_patch.dict(**_PATCH_EXPORT)
        )
        assert Cluster.parse_obj(data) == expected_admin_cluster

    # we can change the access rights, the owner rights are always kept
    for rights in [
        CLUSTER_ADMIN_RIGHTS,
        CLUSTER_MANAGER_RIGHTS,
        CLUSTER_USER_RIGHTS,
        CLUSTER_NO_RIGHTS,
    ]:
        cluster_patch = ClusterPatch(accessRights={second_user["primary_gid"]: rights})
        rsp = await client.patch(
            f"{url}",
            json=cluster_patch.dict(**_PATCH_EXPORT),
        )
        data, error = await assert_status(rsp, expected.ok)
        expected_admin_cluster.access_rights[second_user["primary_gid"]] = rights
        assert Cluster.parse_obj(data) == expected_admin_cluster

    # we can change the owner since we are admin
    cluster_patch = ClusterPatch(owner=second_user["primary_gid"])
    rsp = await client.patch(
        f"{url}",
        json=cluster_patch.dict(**_PATCH_EXPORT),
    )
    data, error = await assert_status(rsp, expected.ok)
    expected_admin_cluster.owner = second_user["primary_gid"]
    expected_admin_cluster.access_rights[
        second_user["primary_gid"]
    ] = CLUSTER_ADMIN_RIGHTS
    assert Cluster.parse_obj(data) == expected_admin_cluster

    # we should not be able to reduce the rights of the new owner
    cluster_patch = ClusterPatch(
        accessRights={second_user["primary_gid"]: CLUSTER_NO_RIGHTS}
    )
    rsp = await client.patch(
        f"{url}",
        json=cluster_patch.dict(**_PATCH_EXPORT),
    )
    data, error = await assert_status(rsp, expected.forbidden)

    # we have a second user that creates a few clusters, some are shared with the first user
    a_cluster_that_may_be_administrated: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_ADMIN_RIGHTS},
    )
    a_cluster_that_may_be_managed: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_MANAGER_RIGHTS},
    )
    a_cluster_that_may_be_used: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_USER_RIGHTS},
    )
    a_cluster_that_is_not_shared: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
    )
    a_cluster_that_may_not_be_used: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {
            GroupID(all_group["gid"]): CLUSTER_ADMIN_RIGHTS,
            GroupID(logged_user["primary_gid"]): CLUSTER_NO_RIGHTS,
        },
    )
    # we can manage so we shall be ok here changing the name
    for cl in [a_cluster_that_may_be_administrated, a_cluster_that_may_be_managed]:
        url = client.app.router["update_cluster_handler"].url_for(cluster_id=f"{cl.id}")
        rsp = await client.patch(
            f"{url}",
            json=ClusterPatch(name="I prefer this new name here").dict(**_PATCH_EXPORT),
        )
        data, error = await assert_status(rsp, expected.ok)

    # we can NOT change the owner of this one
    url = client.app.router["update_cluster_handler"].url_for(
        cluster_id=f"{a_cluster_that_may_be_managed.id}"
    )
    rsp = await client.patch(
        f"{url}",
        json=ClusterPatch(owner=logged_user["primary_gid"]).dict(**_PATCH_EXPORT),
    )
    data, error = await assert_status(rsp, expected.forbidden)

    # we can NOT change ourself to become an admin
    url = client.app.router["update_cluster_handler"].url_for(
        cluster_id=f"{a_cluster_that_may_be_managed.id}"
    )
    rsp = await client.patch(
        f"{url}",
        json=ClusterPatch(
            accessRights={logged_user["primary_gid"]: CLUSTER_ADMIN_RIGHTS}
        ).dict(**_PATCH_EXPORT),
    )
    data, error = await assert_status(rsp, expected.forbidden)

    # but I can add a user
    url = client.app.router["update_cluster_handler"].url_for(
        cluster_id=f"{a_cluster_that_may_be_managed.id}"
    )
    rsp = await client.patch(
        f"{url}",
        json=ClusterPatch(
            accessRights={
                **a_cluster_that_may_be_managed.access_rights,
                **{
                    logged_user["primary_gid"]: CLUSTER_MANAGER_RIGHTS,
                    all_group["gid"]: CLUSTER_USER_RIGHTS,
                },
            },
        ).dict(**_PATCH_EXPORT),
    )
    data, error = await assert_status(rsp, expected.ok)

    # and I shall be able to deny a user
    url = client.app.router["update_cluster_handler"].url_for(
        cluster_id=f"{a_cluster_that_may_be_managed.id}"
    )
    rsp = await client.patch(
        f"{url}",
        json=ClusterPatch(
            accessRights={
                logged_user["primary_gid"]: CLUSTER_MANAGER_RIGHTS,
                all_group["gid"]: CLUSTER_NO_RIGHTS,
            }
        ).dict(**_PATCH_EXPORT),
    )
    data, error = await assert_status(rsp, expected.ok)

    # and I shall be able to remove a user (provided that is not the owner)
    url = client.app.router["update_cluster_handler"].url_for(
        cluster_id=f"{a_cluster_that_may_be_managed.id}"
    )
    rsp = await client.patch(
        f"{url}",
        json=ClusterPatch(
            accessRights={
                logged_user["primary_gid"]: CLUSTER_MANAGER_RIGHTS,
            }
        ).dict(**_PATCH_EXPORT),
    )
    data, error = await assert_status(rsp, expected.ok)

    # but I canNOT add a manager or an admin
    for rights in [CLUSTER_ADMIN_RIGHTS, CLUSTER_MANAGER_RIGHTS]:
        url = client.app.router["update_cluster_handler"].url_for(
            cluster_id=f"{a_cluster_that_may_be_managed.id}"
        )
        rsp = await client.patch(
            f"{url}",
            json=ClusterPatch(accessRights={all_group["gid"]: rights}).dict(
                **_PATCH_EXPORT
            ),
        )
        data, error = await assert_status(rsp, expected.forbidden)

    # we can NOT manage so we shall be forbidden changing the name
    for cl in [
        a_cluster_that_may_be_used,
        a_cluster_that_may_not_be_used,
        a_cluster_that_is_not_shared,
    ]:
        url = client.app.router["update_cluster_handler"].url_for(cluster_id=f"{cl.id}")
        rsp = await client.patch(
            f"{url}",
            json=ClusterPatch(
                name="I prefer this new name here, but I am not allowed"
            ).dict(**_PATCH_EXPORT),
        )
        data, error = await assert_status(rsp, expected.forbidden)
Example #7
0
async def test_get_cluster(
    enable_dev_features: None,
    client: TestClient,
    logged_user: Dict[str, Any],
    second_user: Dict[str, Any],
    all_group: Dict[str, Any],
    cluster: Callable[..., Coroutine[Any, Any, Cluster]],
    user_role: UserRole,
    expected: ExpectedResponse,
):
    # check not found
    assert client.app
    url = client.app.router["get_cluster_handler"].url_for(cluster_id=f"{25}")
    rsp = await client.get(f"{url}")
    data, error = await assert_status(rsp, expected.not_found)
    if error and user_role in [UserRole.ANONYMOUS, UserRole.GUEST]:
        return
    assert data is None

    # create our own cluster, and we can get it
    admin_cluster: Cluster = await cluster(GroupID(logged_user["primary_gid"]))
    url = client.app.router["get_cluster_handler"].url_for(
        cluster_id=f"{admin_cluster.id}"
    )
    rsp = await client.get(f"{url}")
    data, error = await assert_status(rsp, expected.ok)
    assert Cluster.parse_obj(data) == admin_cluster

    # we have a second user that creates a few clusters, some are shared with the first user
    a_cluster_that_may_be_administrated: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_MANAGER_RIGHTS},
    )
    a_cluster_that_may_be_managed: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_MANAGER_RIGHTS},
    )
    a_cluster_that_may_be_used: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_USER_RIGHTS},
    )
    a_cluster_that_is_not_shared: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
    )
    a_cluster_that_may_not_be_used: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {
            GroupID(all_group["gid"]): CLUSTER_USER_RIGHTS,
            GroupID(logged_user["primary_gid"]): CLUSTER_NO_RIGHTS,
        },
    )

    # we should have access to that one
    for cl in [
        a_cluster_that_may_be_administrated,
        a_cluster_that_may_be_managed,
        a_cluster_that_may_be_used,
    ]:
        url = client.app.router["get_cluster_handler"].url_for(cluster_id=f"{cl.id}")
        rsp = await client.get(f"{url}")
        data, error = await assert_status(rsp, expected.ok)
        assert Cluster.parse_obj(data) == cl

    # we should not have access to these
    for cl in [a_cluster_that_is_not_shared, a_cluster_that_may_not_be_used]:
        url = client.app.router["get_cluster_handler"].url_for(cluster_id=f"{cl.id}")
        rsp = await client.get(f"{url}")
        data, error = await assert_status(rsp, expected.forbidden)
Example #8
0
async def test_list_clusters(
    enable_dev_features: None,
    client: TestClient,
    logged_user: Dict[str, Any],
    second_user: Dict[str, Any],
    all_group: Dict[str, Any],
    cluster: Callable[..., Coroutine[Any, Any, Cluster]],
    expected: ExpectedResponse,
):
    # check empty clusters
    assert client.app
    url = client.app.router["list_clusters_handler"].url_for()
    rsp = await client.get(f"{url}")
    data, error = await assert_status(rsp, expected.ok)
    if error:
        # we are done here, anonymous and guests cannot list
        return
    assert data == []

    # create our own cluster, and check it is listed
    admin_cluster: Cluster = await cluster(GroupID(logged_user["primary_gid"]))
    rsp = await client.get(f"{url}")
    data, error = await assert_status(rsp, expected.ok)
    assert len(data) == 1
    assert Cluster.parse_obj(data[0]) == admin_cluster

    # we have a second user that creates a few clusters, some are shared with the first user
    a_cluster_that_may_be_administred: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_MANAGER_RIGHTS},
    )
    a_cluster_that_may_be_managed: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_MANAGER_RIGHTS},
    )

    a_cluster_that_may_be_used: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {GroupID(logged_user["primary_gid"]): CLUSTER_USER_RIGHTS},
    )

    a_cluster_that_is_not_shared: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
    )

    a_cluster_that_may_not_be_used: Cluster = await cluster(
        GroupID(second_user["primary_gid"]),
        {
            GroupID(all_group["gid"]): CLUSTER_USER_RIGHTS,
            GroupID(logged_user["primary_gid"]): CLUSTER_NO_RIGHTS,
        },
    )

    # now listing should retrieve both clusters
    rsp = await client.get(f"{url}")
    data, error = await assert_status(rsp, expected.ok)
    assert len(data) == (1 + 3)
    for d in data:
        assert Cluster.parse_obj(d) in [
            admin_cluster,
            a_cluster_that_may_be_administred,
            a_cluster_that_may_be_managed,
            a_cluster_that_may_be_used,
        ]