#!/usr/bin/env python3 # SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0 # encoding: utf-8 import argparse import logging import sys from google.protobuf.internal import encoder from ud3tn_utils.aap2 import ( AAP2TCPClient, AAP2UnixClient, AuthType, BundleADU, BundleADUFlags, ResponseStatus, ) from ud3tn_utils.aap2.bin.helpers import ( add_agentid_parser_argument, add_common_parser_arguments, argparse_non_empty_str, get_secret_from_args, initialize_logger, ) from ud3tn_utils.storage_agent import StorageCall, StorageOperation logger = logging.getLogger(__name__) def _init_parser(): parser = argparse.ArgumentParser( description="send StorageAgent commands via uD3TN's AAP2 interface", ) add_common_parser_arguments(parser) add_agentid_parser_argument(parser) parser.add_argument( "--storage-agent-eid", type=argparse_non_empty_str, default="dtn://ud3tn.dtn/sqlite", help="destination EID (dtn or ipn URI) of the StorageAgent", ) subparser = parser.add_subparsers(dest="cmd") delete_parser = subparser.add_parser("delete") delete_parser.add_argument( "--dest-eid-glob", type=argparse_non_empty_str, help="delete bundles that match the specified destination EID glob" ) delete_parser.add_argument( "--compound-bundle-id", type=str, nargs=6, metavar=( 'SOURCE', 'DESTINATION', 'CREATION_TIMESTAMP', 'SEQUENCE_NUMBER', 'FRAGMENT_OFFSET', 'PAYLOAD_LENGTH' ), help="delete the bundle that matches the compound bundle id" ) push_parser = subparser.add_parser("push") push_parser.add_argument( "--dest-eid-glob", type=argparse_non_empty_str, help="push bundles that match the specified destination EID glob" ) push_parser.add_argument( "--compound-bundle-id", type=str, nargs=6, metavar=( 'SOURCE', 'DESTINATION', 'CREATION_TIMESTAMP', 'SEQUENCE_NUMBER', 'FRAGMENT_OFFSET', 'PAYLOAD_LENGTH' ), help="push the bundle that match the compound bundle id" ) return parser def main(): parser = _init_parser() args = parser.parse_args() global logger logger = initialize_logger(args.verbosity) cmd = StorageCall() if args.cmd == "delete": cmd.operation = StorageOperation.STORAGE_OPERATION_DELETE_BUNDLES elif args.cmd == "push": cmd.operation = StorageOperation.STORAGE_OPERATION_PUSH_BUNDLES else: logger.error(f"Invalid `cmd` argument: {args.cmd}") parser.print_help() sys.exit(1) if args.compound_bundle_id: cmd.id.source_eid = args.compound_bundle_id[0] cmd.id.destination_eid = args.compound_bundle_id[1] cmd.id.creation_timestamp = int(args.compound_bundle_id[2]) cmd.id.sequence_number = int(args.compound_bundle_id[3]) cmd.id.fragment_offset = int(args.compound_bundle_id[4]) cmd.id.payload_length = int(args.compound_bundle_id[5]) elif args.dest_eid_glob: cmd.metadata.eid_glob = args.dest_eid_glob else: logger.error("Missing filter") parser.print_help() sys.exit(1) cmd_bytes = cmd.SerializeToString() proto_msg = encoder._VarintBytes(len(cmd_bytes)) + cmd_bytes if args.tcp: aap2_client = AAP2TCPClient(address=args.tcp) else: aap2_client = AAP2UnixClient(address=args.socket) with aap2_client: secret = aap2_client.configure( args.agentid, subscribe=False, secret=get_secret_from_args(args), auth_type=AuthType.AUTH_TYPE_BUNDLE_DISPATCH, ) logger.info("Assigned agent secret: '%s'", secret) aap2_client.send_adu( BundleADU( dst_eid=args.storage_agent_eid, payload_length=len(proto_msg), adu_flags=[BundleADUFlags.BUNDLE_ADU_WITH_BDM_AUTH], ), proto_msg, ) response = aap2_client.receive_response() if response.response_status != ResponseStatus.RESPONSE_STATUS_SUCCESS: logger.warning( "µD3TN responded with unexpected status: %s (%d)", aap2_client.response_status_name(response.response_status), response.response_status, ) sys.exit(1) if __name__ == "__main__": main()