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)
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
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")
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]))
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)
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, )
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)
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
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}
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]