Example #1
0
async def check_impact(
    client: AdminAPI, req: Optional[CheckImpactRequest] = None
) -> CheckImpactResponse:
    """
    Wrapper for checkImpact() Thrift method
    """
    return await client.checkImpact(req or CheckImpactRequest())
Example #2
0
async def check_impact(
    client: AdminAPI,
    node_ids: Optional[Collection[NodeID]] = None,
    shards: Optional[Collection[ShardID]] = None,
    target_storage_state: ShardStorageState = ShardStorageState.DISABLED,
    disable_sequencers: bool = True,
) -> CheckImpactResponse:
    """
    Performs Safety check and returns CheckImpactResponse. If no node_ids and no
    shards passed it still does safety check, but will return current state
    of the cluster.
    """
    node_ids = set(node_ids or [])
    shards = set(shards or [])

    req_shards: Set[ShardID] = _recombine_shards(
        shards.union(
            ShardID(node=n, shard_index=ALL_SHARDS) for n in node_ids))

    return await admin_api.check_impact(
        client=client,
        req=CheckImpactRequest(
            shards=list(req_shards),
            target_storage_state=target_storage_state,
            disable_sequencers=disable_sequencers,
        ),
    )
Example #3
0
async def check_impact(
    client: AdminAPI,
    nodes: Optional[Collection[Node]] = None,
    shards: Optional[Collection[ShardID]] = None,
    target_storage_state: ShardStorageState = ShardStorageState.DISABLED,
    disable_sequencers: bool = True,
) -> CheckImpactResponse:
    """
    Performs Safety check and returns CheckImpactResponse. If no nodes and no
    shards passed it still does safety check, but will return current state
    of the cluster.
    """
    nodes = nodes or []
    shards = shards or []

    req_shards: FrozenSet[ShardID] = _recombine_shards(
        list(shards)  # shards is generic Collection, not List
        + [
            ShardID(
                node=NodeID(node_index=n.node_index,
                            address=n.data_addr.to_thrift()),
                shard_index=-1,
            ) for n in nodes
        ])

    return await admin_api.check_impact(
        client=client,
        req=CheckImpactRequest(
            shards=req_shards,
            target_storage_state=target_storage_state,
            disable_sequencers=disable_sequencers,
        ),
    )
Example #4
0
async def check_impact(
    shards: Optional[List[str]] = None,
    node_indexes: Optional[List[int]] = None,
    node_names: Optional[List[str]] = None,
    target_state: str = "disabled",
    # pyre-fixme[9]: safety_margin has type `Mapping[str, int]`; used as `None`.
    safety_margin: Mapping[str, int] = None,
    timeout: int = 600,
    skip_metadata_logs: bool = False,
    skip_internal_logs: bool = False,
    # pyre-fixme[9]: logs has type `List[int]`; used as `None`.
    logs: List[int] = None,
    short: bool = False,
    max_unavailable_storage_capacity_pct=25,
    max_unavailable_sequencing_capacity_pct=25,
    skip_capacity_checks=False,
):
    """
    Return true if performing operations to the given shards will cause
    loss of read/write availability or data loss.
    """

    if shards is None:
        shards = []

    ctx = context.get_context()

    def _combine(
        cv: ClusterView,
        shards: Optional[List[str]] = None,
        node_names: Optional[List[str]] = None,
        node_indexes: Optional[List[int]] = None,
    ) -> Tuple[ShardID, ...]:

        shards = list(shards or [])
        node_names = list(node_names or [])
        node_indexes = list(node_indexes or [])

        shard_ids = parse_shards(shards)
        for nn in node_names:
            shard_ids.add(ShardID(node=cv.get_node_id(node_name=nn), shard_index=-1))
        for ni in node_indexes:
            shard_ids.add(ShardID(node=NodeID(node_index=ni), shard_index=-1))
        shard_ids_expanded = cv.expand_shards(shard_ids)

        return shard_ids_expanded

    if not ctx.is_connected():
        cprint("LDShell must be connected to a cluster!", "red")
        return 1

    cprint("Starting, this may take a while...", "yellow")

    # pyre-fixme[9]: target_state has type `str`; used as `ShardStorageState`.
    target_state = convert.to_storage_state(target_state)

    if skip_capacity_checks:
        max_unavailable_sequencing_capacity_pct = 100
        max_unavailable_storage_capacity_pct = 100

    async with ctx.get_cluster_admin_client() as client:
        try:
            cv = await get_cluster_view(client)
            # pyre-fixme[9]: shards has type `Optional[List[str]]`; used as
            #  `Tuple[ShardID, ...]`.
            shards = _combine(cv, shards, node_names, node_indexes)
            req = CheckImpactRequest(
                # pyre-fixme[6]: Expected `Optional[Sequence[ShardID]]` for 1st
                #  param but got `List[str]`.
                shards=shards,
                target_storage_state=target_state,
                log_ids_to_check=logs,
                abort_on_negative_impact=True,
                safety_margin=convert.to_replication(safety_margin),
                return_sample_size=20,
                check_metadata_logs=not skip_metadata_logs,
                check_internal_logs=not skip_internal_logs,
                max_unavailable_storage_capacity_pct=max_unavailable_storage_capacity_pct,
                max_unavailable_sequencing_capacity_pct=max_unavailable_sequencing_capacity_pct,
            )
            response = await client.checkImpact(req)
        except OperationError as e:
            cprint(
                f"There was error during check execution, Status {e}, "
                "result is not known",
                "red",
            )
            return 1
        except texceptions.TransportError as e:
            cprint(f"Couldn't connect to the Admin Server: {e}", "red")
            return 1

    delta = response.total_duration
    lines = []
    if not response.impact:
        lines.append(colored("ALL GOOD.\n", "green"))
        lines.append(f"Total logs checked ({response.total_logs_checked}) in {delta}s")
    else:
        lines.append(
            colored(f"UNSAFE. Impact: {impacts_to_string(response.impact)}", "red")
        )
        lines.append(f"Total logs checked ({response.total_logs_checked}) in {delta}s")
    print("\n".join(lines))
    if not short:
        # pyre-fixme[6]: Expected `List[ShardID]` for 2nd param but got `List[str]`.
        print(check_impact_string(response, shards, target_state))
    if not response.impact:
        return 0
    return 1