Files
scadalink-design/infra/tools/restapi_tool.py

153 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""REST API client tool for ScadaLink test infrastructure."""
import argparse
import json
import sys
import requests
DEFAULT_URL = "http://localhost:5200"
DEFAULT_API_KEY = "scadalink-test-key-1"
def cmd_check(args):
"""Test API server connectivity and report status."""
headers = {"X-API-Key": args.api_key}
# Test health endpoint (no auth required)
try:
resp = requests.get(f"{args.url}/api/Ping", timeout=5)
ping_ok = resp.status_code == 200
except Exception as e:
ping_ok = False
ping_err = str(e)
print(f"Ping ({args.url}/api/Ping): {'OK' if ping_ok else 'FAILED - ' + ping_err}")
if not ping_ok:
sys.exit(1)
# Test authenticated endpoint
try:
resp = requests.post(f"{args.url}/api/GetStatus", json={}, headers=headers, timeout=5)
if resp.status_code == 200:
data = resp.json()
print(f"Status: {data.get('status', 'unknown')}")
print(f"Uptime: {data.get('uptime', 0)}s")
auth_ok = True
elif resp.status_code == 401:
print("Auth: FAILED - invalid API key")
auth_ok = False
else:
print(f"Status check: HTTP {resp.status_code}")
auth_ok = False
except Exception as e:
print(f"Status check: FAILED - {e}")
auth_ok = False
# List available methods
try:
resp = requests.get(f"{args.url}/api/methods", headers=headers, timeout=5)
if resp.status_code == 200:
methods = resp.json().get("methods", [])
print(f"Available methods: {len(methods)}")
except Exception:
pass
if ping_ok and auth_ok:
print("\nREST API server is healthy.")
else:
sys.exit(1)
def cmd_call(args):
"""Call an API method."""
headers = {"X-API-Key": args.api_key, "Content-Type": "application/json"}
url = f"{args.url}/api/{args.method}"
params = {}
if args.params:
try:
params = json.loads(args.params)
except json.JSONDecodeError as e:
print(f"Error: invalid JSON params: {e}", file=sys.stderr)
sys.exit(1)
try:
if args.method == "Ping":
resp = requests.get(url, headers=headers, timeout=args.timeout)
else:
resp = requests.post(url, json=params, headers=headers, timeout=args.timeout)
except requests.exceptions.Timeout:
print(f"Error: request timed out after {args.timeout}s", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
print(f"HTTP {resp.status_code}")
try:
print(json.dumps(resp.json(), indent=2))
except Exception:
print(resp.text)
if resp.status_code >= 400:
sys.exit(1)
def cmd_methods(args):
"""List all available API methods."""
headers = {"X-API-Key": args.api_key}
try:
resp = requests.get(f"{args.url}/api/methods", headers=headers, timeout=5)
if resp.status_code != 200:
print(f"Error: HTTP {resp.status_code}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
methods = resp.json().get("methods", [])
print(f"{'Method':<25} {'HTTP':<6} {'Path':<30} {'Description'}")
print("-" * 95)
for m in methods:
print(f"{m['method']:<25} {m['httpMethod']:<6} {m['path']:<30} {m.get('description', '')}")
if m.get("params"):
params_str = ", ".join(f"{k}: {v}" for k, v in m["params"].items())
print(f" {'Params:':<23} {params_str}")
def main():
parser = argparse.ArgumentParser(description="REST API client tool for ScadaLink test infrastructure")
parser.add_argument("--url", default=DEFAULT_URL, help=f"API base URL (default: {DEFAULT_URL})")
parser.add_argument("--api-key", default=DEFAULT_API_KEY, help=f"API key (default: {DEFAULT_API_KEY})")
sub = parser.add_subparsers(dest="command", required=True)
sub.add_parser("check", help="Test API connectivity and report status")
call_p = sub.add_parser("call", help="Call an API method")
call_p.add_argument("--method", required=True, help="Method name (e.g. Add, GetProductionReport)")
call_p.add_argument("--params", help="JSON params (e.g. '{\"a\": 2, \"b\": 3}')")
call_p.add_argument("--timeout", type=float, default=30, help="Request timeout in seconds (default: 30)")
sub.add_parser("methods", help="List all available API methods")
args = parser.parse_args()
commands = {
"check": cmd_check,
"call": cmd_call,
"methods": cmd_methods,
}
commands[args.command](args)
if __name__ == "__main__":
main()