예제 #1
0
def get_providers(skip, take, json, api):
    """Retrieve a list of endpoint providers."""
    api = sdk.AgentsApi(api)
    providers = WithPagination(api.v1_network_agents_providers_get)(
        skip=skip, take=take, _preload_content=False)["data"]
    fields = [
        ("ID", "agent_provider_id"),
        ("Name", "agent_provider_name"),
    ]
    print_table(providers, fields, to_json=json)
예제 #2
0
def expand_agents_tags(api, dst_dict, silent=False):
    """Expand tag endpoints into individual endpoints.

    Args:
        api (PlatformApi): API object to communicate with the platform.
        dst_dict (dict): Connections dictionary that contain tags as endpoints.
        silent (bool, optional): Indicates whether to suppress messages - used with Ansible. Defaults to False.

    Raises:
        ConfigureNetworkError: In case of any errors

    Returns:
        Union[dict, None]: Dictionary with expanded endpoints where key is the name and value is the config(id, state, type).
    """
    items = {}

    # First expand tags
    for name, dst in dst_dict.items():
        if dst.get(ConfigFields.PEER_TYPE) != PeerType.TAG:
            continue

        agents = (sdk.AgentsApi(api).v1_network_agents_search(
            models.V1NetworkAgentsSearchRequest(filter=models.V1AgentFilter(
                agent_tag_name=[name]), ), ).to_dict()["data"])

        if not agents:
            error = f"Could not find endpoints by the tag {name}"
            if not silent:
                click.secho(error, err=True, fg="red")
                return
            else:
                raise ConfigureNetworkError(error)

        tag_state = dst.get(ConfigFields.STATE, PeerState.PRESENT)
        for agent in agents:
            agent_name = agent["agent_name"]
            if agent_name not in items or (
                    tag_state == PeerState.ABSENT
                    and items[agent_name][ConfigFields.STATE]
                    == PeerState.PRESENT):
                items[agent_name] = {
                    ConfigFields.ID: agent["agent_id"],
                    ConfigFields.STATE: tag_state,
                    ConfigFields.PEER_TYPE: PeerType.ENDPOINT,
                    ConfigFields.SERVICES: dst.get(ConfigFields.SERVICES),
                }

    # Then override with explicit configs
    for name, dst in dst_dict.items():
        if dst.get(ConfigFields.PEER_TYPE) != PeerType.TAG:
            items[name] = dst
            continue

    return items
예제 #3
0
def create_connections(agents, use_names, json, api):
    """Create connections between endpoints. Number of endpoints must be even.

    \b
    Arguments:
        agents - a list of endpoint ids or names separated by spaces.

    In order to use endpoint names instead of ids provide --use-names option.

    Example:

        syntropyctl create-connections 1 2 3 4 5 6 7 8

        This command will create 4 connections from Endpoint 1 to Endpoint 2 like this:

        \b
        Endpoint 1 ID | Endpoint 2 ID
        1             | 2
        3             | 4
        5             | 6
        7             | 8
    """

    if use_names:
        all_agents = WithPagination(sdk.AgentsApi(api).v1_network_agents_get)(
            _preload_content=False)["data"]
        agents = find_by_name(all_agents, agents, "agent")
        if any(i is None for i in agents):
            raise SystemExit(1)
    else:
        try:
            agents = [int(i) for i in agents]
        except ValueError:
            click.secho("Invalid agent id", err=True, fg="red")
            raise SystemExit(1)

    if len(agents) == 0 or len(agents) % 2 != 0:
        click.secho("Number of agents must be even.", err=True, fg="red")
        raise SystemExit(1)
    agents = list(zip(agents[:-1:2], agents[1::2]))

    body = models.V1NetworkConnectionsCreateP2PRequest(agent_pairs=[
        models.V1NetworkConnectionsCreateP2PRequestAgentPairs(
            agent_1_id=a,
            agent_2_id=b,
        ) for a, b in agents
    ], )
    result = sdk.ConnectionsApi(api).v1_network_connections_create_p2_p(
        body=body, _preload_content=False)

    if result and "errors" in result:
        for error in result["errors"]:
            click.secho(f"Error: {error.get('message')}", err=True, fg="red")
예제 #4
0
def export(topology, to_json, api):
    """Exports existing connections to configuration YAML/JSON file.

    If exact topology export is required - use P2P topology.
    """
    all_agents = sdk.utils.WithPagination(sdk.AgentsApi(api).v1_network_agents_get)(
        _preload_content=False
    )["data"]
    all_agents = {agent["agent_id"]: agent for agent in all_agents}

    network = utils.export_network(api, all_agents, topology)
    if to_json:
        click.echo(json.dumps(network, indent=4))
    else:
        click.echo(yaml.dump_all([network]))
예제 #5
0
def get_connections(id, name, skip, take, show_services, json, api):
    """Retrieves connections.

    Connection service status is added to the end of the service name with the following possible symbols:

    \b
    ^ - Service is online.
    ! - There was an error exposing the service
    ~ - Service is in PENDING state
    ? - Unknown state

    By default this command will retrieve up to 42 connections. You can use --take parameter to get more connections.
    """
    if name or id:
        if name:
            agents = (sdk.AgentsApi(api).v1_network_agents_search(
                models.V1NetworkAgentsSearchRequest(
                    filter=models.V1AgentFilter(
                        agent_name=name)), ).to_dict()["data"])
            id = [agent["agent_id"] for agent in agents]
        else:
            id = [int(id)]

        filters = models.V1ConnectionFilter(agent_id=id)

        connections = (sdk.ConnectionsApi(api).v1_network_connections_search(
            body=models.V1NetworkConnectionsSearchRequest(
                filter=filters,
                skip=skip,
                take=take,
            ), ).to_dict()["data"])
    else:
        connections = WithPagination(
            sdk.ConnectionsApi(api).v1_network_connections_get)(
                skip=skip,
                take=take,
                _preload_content=False,
            )["data"]

    fields = [
        ("ID", "agent_connection_group_id"),
        ("Endpoint 1", ("agent_1", "agent_name")),
        ("ID 1", ("agent_1", "agent_id")),
        ("IP 1", ("agent_1", "agent_public_ipv4")),
        ("Endpoint 2", ("agent_2", "agent_name")),
        ("ID 2", ("agent_2", "agent_id")),
        ("IP 2", ("agent_2", "agent_public_ipv4")),
        ("Status", "agent_connection_group_status"),
        ("Modified At", "agent_connection_group_updated_at"),
        ("Latency", "agent_connection_latency_ms"),
        ("Packet Loss", "agent_connection_packet_loss"),
    ]

    if show_services:
        ids = [
            connection["agent_connection_group_id"]
            for connection in connections
        ]
        connections_services = BatchedRequestFilter(
            sdk.ConnectionsApi(api).v1_network_connections_services_get,
            max_query_size=MAX_QUERY_FIELD_SIZE,
        )(filter=ids, _preload_content=False)["data"]
        connection_services = {
            connection["agent_connection_group_id"]: connection
            for connection in connections_services
        }
        connections = [{
            **connection,
            "agent_connection_services":
            connection_services[connection["agent_connection_group_id"]],
        } for connection in connections]
        fields.append(("Services", "agent_connection_services",
                       collect_connection_services))

    print_table(connections, fields, to_json=json)
예제 #6
0
def configure_endpoints(
    api,
    endpoint,
    set_provider,
    set_tag,
    set_service,
    add_tag,
    enable_service,
    remove_tag,
    disable_service,
    clear_tags,
    disable_all_services,
    enable_all_services,
    name,
    take,
    skip,
    json,
):
    """Configures an endpoint with provided provider, tags. Also, allows to enable/disable services.
    Endpoint can be an ID or a name (use -n option). Multiple endpoints can be configured if names match partially with the provided name.

    It is possible to supply multiple --set-tag, --add-tag and --remove-tag options. The sequence of operations is set, add and then remove.
    So if you run this:

        syntropyctl configure-endpoints --set-tag tag1 --set-tag tag2 --add-tag tag3 --add-tag tag4 --remove-tag tag1 -n <endpoint-name>

    \b
    then syntropyctl will:
        1. clear all tags and add tag1 and tag2,
        2. add tag3 and tag4,
        3. remove tag1.

    The same applies to services.
    """
    body = models.V1NetworkAgentsSearchRequest(filter=models.V1AgentFilter(
        agent_name=endpoint) if name else models.V1AgentFilter(
            agent_id=endpoint))
    agents = (sdk.AgentsApi(api).v1_network_agents_search(
        body, ).to_dict()["data"])

    if not agents:
        click.secho("Could not find any endpoints.", err=True, fg="red")
        raise SystemExit(1)
    else:
        click.secho(f"Found {len(agents)} endpoints.", fg="green")

    if set_provider or set_tag or add_tag or remove_tag or clear_tags:
        agents_tags = {
            agent["agent_id"]: [
                tag["agent_tag_name"] for tag in agent.get("agent_tags", [])
                if tag
            ]
            for agent in agents if "agent_tags" in agent
        }
        for agent in agents:
            original_tags = agents_tags.get(agent["agent_id"], [])
            tags = update_list(original_tags, set_tag, add_tag, remove_tag,
                               clear_tags)
            payload = {}
            current_provider = (agent.get("agent_provider")
                                if agent.get("agent_provider") else {})
            if set_provider and set_provider != current_provider.get(
                    "agent_provider_name"):
                payload["agent_provider_name"] = set_provider
            if (set_tag or add_tag or remove_tag
                    or clear_tags) and set(original_tags) != set(tags):
                payload["agent_tags"] = tags
            if payload:
                sdk.AgentsApi(api).v1_network_agents_update(
                    payload, agent["agent_id"])
                click.secho("Tags and provider configured.", fg="green")
            else:
                click.secho(
                    "Nothing to do for tags and provider configuration.",
                    fg="yellow")

    show_services = False
    if (set_service or enable_service or disable_service or enable_all_services
            or disable_all_services):
        show_services = True
        ids = [agent["agent_id"] for agent in agents]
        agents_services_all = sdk.utils.BatchedRequestFilter(
            sdk.AgentsApi(api).v1_network_agents_services_get,
            max_query_size=MAX_QUERY_FIELD_SIZE,
        )(filter=ids, _preload_content=False)["data"]

        agents_services = defaultdict(list)
        for agent in agents_services_all:
            agents_services[agent["agent_id"]].append(agent)
        for agent in agents:
            services = {
                service["agent_service_name"]: service
                for service in agents_services[agent["agent_id"]]
            }
            enabled_services = [
                service["agent_service_name"]
                for service in agents_services[agent["agent_id"]]
                if ((all(subnet["agent_service_subnet_is_user_enabled"]
                         for subnet in service["agent_service_subnets"])
                     and service["agent_service_is_active"])
                    or enable_all_services)
            ]
            enabled_services = update_list(
                enabled_services,
                set_service,
                enable_service,
                disable_service,
                disable_all_services,
                validate=False,
            )
            missing_services = [
                service for service in enabled_services
                if service not in services
            ]
            if missing_services:
                click.secho(
                    f"Warning: the following services were not found: {', '.join(missing_services)}",
                    err=True,
                    fg="yellow",
                )
            subnets = [
                models.V1NetworkAgentsServicesUpdateRequestSubnetsToUpdate(
                    is_enabled=name in enabled_services,
                    agent_service_subnet_id=subnet["agent_service_subnet_id"],
                ) for name, service in services.items()
                for subnet in service["agent_service_subnets"]
                if subnet["agent_service_subnet_is_user_enabled"] != (
                    name in enabled_services)
            ]
            if subnets:
                payload = models.V1NetworkAgentsServicesUpdateRequest(
                    subnets_to_update=subnets)
                sdk.AgentsApi(api).v1_network_agents_services_update(payload)
                click.secho("Service subnets updated.", fg="green")
            else:
                click.secho("Nothing to do for service configuration.",
                            fg="yellow")

    name_param, id_param = None, None
    if name:
        name_param = endpoint
    else:
        id_param = endpoint

    _get_endpoints(
        name_param,
        id_param,
        None,
        skip,
        take,
        show_services,
        None,
        None,
        json,
        api,
    )
예제 #7
0
def _get_endpoints(name, id, tag, skip, take, show_services, online, offline,
                   json, api):
    if not name and not id and not tag and not online and not offline:
        agents = WithPagination(sdk.AgentsApi(api).v1_network_agents_get)(
            skip=skip,
            take=take,
            _preload_content=False,
        )["data"]
    else:
        filters = models.V1AgentFilter()
        if name:
            filters.agent_name = name
        elif id:
            filters.agent_id = [id]
        if tag:
            filters.agent_tag_name = [tag]

        if online:
            filters.agent_status = [models.AgentFilterAgentStatus.CONNECTED]
        elif offline:
            filters.agent_status = [
                models.AgentFilterAgentStatus.DISCONNECTED,
                models.AgentFilterAgentStatus.CONNECTED_WITH_ERRORS,
            ]

        agents = (
            sdk.AgentsApi(api).v1_network_agents_search(
                models.V1NetworkAgentsSearchRequest(
                    filter=filters,
                    skip=skip,
                    take=take,
                ),
                # _preload_content=False,
            ).to_dict()["data"])

    fields = [
        ("Agent ID", "agent_id"),
        ("Name", "agent_name"),
        ("Public IP", "agent_public_ipv4"),
        ("Provider", ("agent_provider", "agent_provider_name")),
        ("Location", "agent_location_city"),
        ("Online", "agent_is_online"),
        (
            "Tags",
            "agent_tags",
            lambda x: x and ", ".join(i["agent_tag_name"] for i in x) or "-",
        ),
    ]

    if show_services:
        ids = [agent["agent_id"] for agent in agents]
        agents_services = BatchedRequestFilter(
            sdk.AgentsApi(api).v1_network_agents_services_get,
            max_query_size=MAX_QUERY_FIELD_SIZE,
        )(filter=ids, _preload_content=False)["data"]
        agent_services = defaultdict(list)
        for agent in agents_services:
            agent_services[agent["agent_id"]].append(agent)
        agents = [{
            **agent,
            "agent_services":
            agent_services.get(agent["agent_id"], []),
        } for agent in agents]
        fields.append(
            ("Services", "agent_services", collect_endpoint_services))

    print_table(agents, fields, to_json=json)
예제 #8
0
def export_connections(api, all_agents, network, net_agents, connections,
                       topology):
    topology = Topology.P2M if not topology else topology.upper()
    ids = [
        connection["agent_connection_group_id"] for connection in connections
    ]
    if ids:
        connections_services = sdk.utils.BatchedRequestFilter(
            sdk.ConnectionsApi(api).v1_network_connections_services_get,
            MAX_QUERY_FIELD_SIZE,
        )(filter=ids, _preload_content=False)["data"]

        connection_services = {
            connection["agent_connection_group_id"]: connection
            for connection in connections_services
        }
    net_connections = [{
        **connection,
        "agent_connection_services":
        connection_services.get(connection["agent_connection_group_id"], {}),
    } for connection in connections]
    transformed_connections = transform.transform_connections(
        all_agents,
        net_connections,
        topology if topology else network[fields.ConfigFields.TOPOLOGY],
    )
    if transformed_connections:
        network[fields.ConfigFields.CONNECTIONS] = transformed_connections
    network[fields.ConfigFields.TOPOLOGY] = topology

    # NOTE: Currently, SDN is disabled.
    if fields.ConfigFields.USE_SDN in network:
        del network[fields.ConfigFields.USE_SDN]

    # Filter out unused endpoints
    used_endpoints = [
        con[agent]["agent_id"] for con in net_connections
        for agent in ("agent_1", "agent_2")
    ]
    unused_endpoints = [id for id in net_agents if id not in used_endpoints]

    if unused_endpoints:
        agents_services = sdk.utils.BatchedRequestFilter(
            sdk.AgentsApi(api).v1_network_agents_services_get,
            MAX_QUERY_FIELD_SIZE,
        )(filter=unused_endpoints, _preload_content=False)["data"]

        agent_services = defaultdict(list)
        for agent_id, agent in zip(unused_endpoints, agents_services):
            id = (agent["agent_id"]
                  if "agent_id" in agent and agent["agent_id"] else agent_id)
            agent_services[id].append(agent)

        network[fields.ConfigFields.ENDPOINTS] = {
            all_agents[id]["agent_name"]: {
                fields.ConfigFields.ID:
                id,
                fields.ConfigFields.SERVICES: [
                    service["agent_service_name"]
                    for service in agent_services[id]
                ],
                fields.ConfigFields.TAGS: [
                    tag["agent_tag_name"]
                    for tag in all_agents[id].get("agent_tags", [])
                ],
            }
            for id in unused_endpoints
        }

    return network
예제 #9
0
def get_all_agents(api, silent=False):
    agents = sdk.utils.WithPagination(
        sdk.AgentsApi(api).v1_network_agents_get)(
            _preload_content=False, )["data"]

    return {agent["agent_id"]: agent for agent in agents}
예제 #10
0
def resolve_agent_by_name(api, name, silent=False):
    agents = (sdk.AgentsApi(api).v1_network_agents_search(
        models.V1NetworkAgentsSearchRequest(filter=models.V1AgentFilter(
            agent_name=name), ), ).to_dict()["data"])

    return [agent["agent_id"] for agent in agents]