From acba6f369cdee9e83f961e67b840281d39f2dd90 Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Mon, 27 Mar 2023 12:17:35 +0100 Subject: [PATCH 1/2] client.py: Add trailing slash to path The Python implementation requires it. --- scripts/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/client.py b/scripts/client.py index 8905473..117be98 100644 --- a/scripts/client.py +++ b/scripts/client.py @@ -19,7 +19,7 @@ reducer = 'min' response = requests.post( - f'http://localhost:8080/v1/{reducer}', + f'http://localhost:8000/v1/{reducer}/', json=request_data, auth=('minioadmin', 'minioadmin') ) From fedfbe399a75ad44fefb9e895a820d40ad539894 Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Tue, 28 Mar 2023 15:56:04 +0100 Subject: [PATCH 2/2] Make Python client more flexible This is helpful for testing. --- scripts/client.py | 114 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 23 deletions(-) diff --git a/scripts/client.py b/scripts/client.py index 117be98..e4ac866 100644 --- a/scripts/client.py +++ b/scripts/client.py @@ -1,30 +1,98 @@ # Make a request to the active storage server. +# Example usage with minio and sum of uint32 sample data: +# +# python ./scripts/client.py \ +# sum \ +# --server http://localhost:8080 \ +# --source http://localhost:9000 \ +# --username minioadmin --password minioadmin \ +# --bucket sample-data --object data-uint32.dat \ +# --dtype uint32 + +import argparse +import http.client import json import requests import numpy as np import sys -request_data = { - 'source': 'http://localhost:9000', - 'bucket': 'sample-data', - 'object': 'data-uint32.dat', - 'dtype': 'uint32', - # All other fields assume their default values -} - -if len(sys.argv) > 1: - reducer = sys.argv[1] -else: - reducer = 'min' - -response = requests.post( - f'http://localhost:8000/v1/{reducer}/', - json=request_data, - auth=('minioadmin', 'minioadmin') -) -print(response.content) -sum_result = np.frombuffer(response.content, dtype=response.headers['x-activestorage-dtype']) -shape = json.loads(response.headers['x-activestorage-shape']) -sum_result = sum_result.reshape(shape) -print(sum_result) + +DTYPES = ["int32", "int64", "uint32", "uint64", "float32", "float64"] + + +def get_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("operation") + parser.add_argument("--server", required=True, type=str) + parser.add_argument("--source", required=True, type=str) + parser.add_argument("--username", required=True, type=str) + parser.add_argument("--password", required=True, type=str) + parser.add_argument("--bucket", required=True, type=str) + parser.add_argument("--object", required=True, type=str) + parser.add_argument("--dtype", required=True, type=str) #, choices=DTYPES) allow invalid + parser.add_argument("--offset", type=int) + parser.add_argument("--size", type=int) + parser.add_argument("--shape", type=str) + parser.add_argument("--order", default="C") #, choices=["C", "F"]) allow invalid for testing + parser.add_argument("--selection", type=str) + return parser.parse_args() + + +def build_request_data(args: argparse.Namespace) -> dict: + request_data = { + 'source': args.source, + 'bucket': args.bucket, + 'object': args.object, + 'dtype': args.dtype, + 'offset': args.offset, + 'size': args.size, + 'order': args.order, + } + if args.shape: + request_data["shape"] = json.loads(args.shape) + if args.selection: + request_data["selection"] = json.loads(args.selection) + return {k: v for k, v in request_data.items() if v is not None} + + +def request(url: str, username: str, password: str, request_data: dict): + response = requests.post( + url, + json=request_data, + auth=(username, password) + ) + return response + + +def display(response): + #print(response.content) + dtype = response.headers['x-activestorage-dtype'] + shape = json.loads(response.headers['x-activestorage-shape']) + result = np.frombuffer(response.content, dtype=dtype) + result = result.reshape(shape) + print(result) + + +def display_error(response): + print(response.status_code, http.client.responses[response.status_code]) + try: + print(json.dumps(response.json())) + except requests.exceptions.JSONDecodeError: + print(response.content) + + +def main(): + args = get_args() + request_data = build_request_data(args) + url = f'{args.server}/v1/{args.operation}/' + response = request(url, args.username, args.password, request_data) + if response.ok: + display(response) + else: + display_error(response) + sys.exit(1) + + +if __name__ == "__main__": + main()