示例#1
0
def gpudb_cmd(argv):
    """A command line interface to send a specified request to a GPUDB server.
       Can be used to print the parameters for a request as well.
    """

    # Default values
    file_name = ""

    # Add arguments to the parser
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-g',
        '--gpudb',
        nargs='?',
        default="127.0.0.1:9191",
        help=
        "IP address and port of GPUdb in the format: IP_ADDRESS:PORT (default 127.0.0.1:9191)"
    )
    parser.add_argument('--username',
                        nargs='?',
                        default="",
                        help="Username used when connecting to GPUdb.")
    parser.add_argument('--password',
                        nargs='?',
                        default="",
                        help="Password used when connecting to GPUdb.")
    parser.add_argument(
        '--ask-password',
        action="store_true",
        help=
        "Ask for the password to use when connecting to GPUdb (more secure than --password)"
    )
    parser.add_argument(
        '--json-encoding',
        action="store_true",
        help=
        "Use avro JSON encoding of request message to GPUdb (default is avro binary)"
    )
    parser.add_argument(
        '-f',
        '--format',
        action='store',
        dest="format",
        default="json",
        choices=["json", "oneline", "ini", "raw"],
        help=
        "Format the returned GPUDB response in a few ways. (default 'json')")
    parser.add_argument(
        "--print-query",
        action='store_true',
        help=
        "Print the request query before sending it using the specified format."
    )

    # User must provide one or the other
    query_group = parser.add_mutually_exclusive_group(required=True)
    query_group.add_argument("--list-queries",
                             action='store_true',
                             help="Lists all available GPUDB request queries.")
    query_group.add_argument(
        "--print-schemas",
        action='store',
        help=
        "Print the JSON schema of the specified request and response query.")
    query_group.add_argument( '--query', nargs = argparse.REMAINDER,
                         help = "Send a request query by specifying the name of the query and the parameters associated with the query. " \
                                "Help is provided if only the query name is specified. " \
                                "Note that unspecified parameters will take a default value. " \
                                "Example: '--query aggregate_min_max --column_name x --table_name DataTable'" )

    # Print the help message and quit if no arguments are given
    if (len(sys.argv) == 1):  # None provided
        parser.print_help()
        sys.exit(2)

    # Parse the command line arguments
    args = parser.parse_args()

    # --------------------------------------
    # Set up GPUdb
    GPUdb_IP, GPUdb_Port = args.gpudb.split(":")
    password = args.password
    if args.ask_password:
        password = getpass.getpass("GPUdb password:"******"Unknown query name: '%s'" % query_name)
            sys.exit(2)

        req_schema_str = gpudb.gpudb_schemas[query_name]["REQ_SCHEMA_STR"]
        rsp_schema_str = gpudb.gpudb_schemas[query_name]["RSP_SCHEMA_STR"]
        req_odict = json.JSONDecoder(
            object_pairs_hook=collections.OrderedDict).decode(req_schema_str)
        rsp_odict = json.JSONDecoder(
            object_pairs_hook=collections.OrderedDict).decode(rsp_schema_str)

        # Use desired formatting
        print_dict(req_odict, args.format)
        print_dict(rsp_odict, args.format)
        sys.exit(0)

    # --------------------------------------
    # List all endpoint/query names, if desired by user
    if (args.list_queries == True) or (len(args.query) == 0):
        for q in sorted(query_names):
            print(q)
        sys.exit(
            0)  # Succesful termination after printing the desired help message

    # --------------------------------------
    # Get the query JSON string from GPUdb
    query_name = args.query[0]
    if query_name not in query_names:
        print("Unknown query name: '%s'" % query_name)
        sys.exit(2)
    request_json = gpudb.gpudb_schemas[query_name]["REQ_SCHEMA_STR"]

    # Parse the request JSON to get the parameters
    request_schema = gpudb.gpudb_schemas[query_name]["REQ_SCHEMA"]
    request_json = request_schema.to_json()["fields"]

    # Create a dictionary of (param name, param type) pairs based on the JSON
    param_name_type = {}
    param_vals = {}
    for param in request_json:
        param_name_type[param['name']] = param['type']
        # Binary/bytes parameters will be skipped
        if param['type'] == "string" or param['type'] == "bytes":
            param_vals[param['name']] = ""  # Default is empty string
        if param['type'] == "map":
            param_vals[param['name']] = {}  # Default is empty map
        if param['type'] == "list":
            param_vals[param['name']] = []  # Default is empty list
        # Note that numeric attributes are not getting a default
        # User MUST provide such values, or we output an error

    # Create a parser for query-specific parameters
    query_parser = argparse.ArgumentParser()

    # Add parameters to be parsed
    for pname, ptype in param_name_type.items():
        if ptype == "string":  # Make string arguments optional
            query_parser.add_argument("--" + pname,
                                      nargs='?',
                                      default="",
                                      help="Defaults to empty string")
        elif ptype == "double" or ptype == "float":
            query_parser.add_argument("--" + pname,
                                      type=float,
                                      required=True,
                                      help="Required parameter, type %s" %
                                      ptype)
        elif ptype == "long":
            query_parser.add_argument("--" + pname,
                                      type=long,
                                      required=True,
                                      help="Required parameter, type %s" %
                                      ptype)
        elif ptype == "int":
            query_parser.add_argument("--" + pname,
                                      type=int,
                                      required=True,
                                      help="Required parameter, type %s" %
                                      ptype)
        elif ptype == "bytes":
            continue  # ignore bytes
        elif ptype == "boolean":  # Boolean flag
            # User must provide one or the other
            bool_group = query_parser.add_mutually_exclusive_group(
                required=True)
            bool_group.add_argument(
                "--" + pname,
                action='store_true',
                dest=pname,
                help="Boolean parameter, include to set %s to TRUE" % pname)
            bool_group.add_argument(
                "--no-" + pname,
                action='store_false',
                dest=pname,
                help="Boolean parameter, include to set %s to FALSE" % pname)
        else:  # Maps and lists get empty ones by default; handling is delicate; ignore 'bytes'
            if ptype['type'] == "map":
                query_parser.add_argument(
                    "--" + pname,
                    nargs='?',
                    type=json.loads,
                    default={},
                    help=
                    "Expected map value of type: %s; surround the whole map with single quotes (') and any string (key or value) within with double quotes (\"). E.g. for random, --param_map '{\"x\":{\"min\":2}}'. When omitted, defaults to empty map"
                    % ptype['values'])
            else:  # Arrays
                query_parser.add_argument(
                    "--" + pname,
                    type=json.loads,
                    default=[],
                    help=
                    "Comma separated list (escape spaces with \) enclosed in []. For example, for filter_by_nai, --x_vector [1,2,3,4] or --x_vector [1,\ 2,\ 3,\ 4]. If contains strings, then enclose the whole thing within single quotes and the individual string in double quotes.  E.g., for filter_by_string, --attributes '[\"x\",\"y\"]'. When omitted, defaults to an empty list."
                )

    # Print the help message and quit if no arguments are given (and none is expected)
    if (len(args.query[1:]) == 0 and len(param_name_type) > 0):
        print("No parameters provided for query: ", query_name)
        query_parser.print_help()
        sys.exit(2)

    # Parse the parameters and store in a dictionary
    query_args = vars(query_parser.parse_args(args.query[1:]))

    # Copy the parsed values to the ordered dictionary to pass to GPUdb
    for key, val in query_args.items():
        param_vals[key] = val

    # --------------------------------------
    # Call the GPUDB query:

    # Obtain the request and response schemas for the given query
    (req_schema, resp_schema) = gpudb._GPUdb__get_schemas(query_name)
    endpoint = gpudb._GPUdb__get_endpoint(query_name)

    # --------------------------------------
    if args.print_query:
        encoded_datum = gpudb.encode_datum(req_schema, param_vals)
        request_odict = gpudb._GPUdb__read_orig_datum(req_schema,
                                                      encoded_datum)
        print(endpoint)
        print_dict(request_odict, args.format)

    # --------------------------------------
    # Perform the GPUDB query
    response = gpudb._GPUdb__post_then_get(req_schema, resp_schema, param_vals,
                                           endpoint)

    print_dict(response, args.format)