diff --git a/README.rst b/README.rst index 422cceb..31b72fd 100644 --- a/README.rst +++ b/README.rst @@ -129,99 +129,88 @@ Examples $ oscurl -p /servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559 -m DELETE -Output Format -------------- +Output mode +----------- -* RAW: Both HTTP response headers and body (Default):: +``--show-mode`` controls what are shown. - $ oscurl -p /servers - HTTP/1.1 200 OK - X-Compute-Request-Id: req-f2c0adc9-288b-4a65-8243-b112d1dc60b6 - Content-Type: application/json - Content-Length: 366 - Date: Sun, 22 Jun 2014 12:25:16 GMT +* ``ALL`` shows request and response including both headers and body. +* ``RESP`` shows response headers and body. Request headers and body + are not shown. +* ``BODY`` shows response body only. Useful if you pass output + to another program like ``jq``. - {"servers": [{"id": "fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "links": [{"href": "http://192.168.0.11:8774/v2/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "rel": "self"}, {"href": "http://192.168.0.11:8774/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "rel": "bookmark"}], "name": "server-test-1"}]} +Output Format +------------- + +``--format`` controls the output format of response body. -* HEADER: Only HTTP response headers:: +* ``RAW``: Show response body as-is (Default):: - $ oscurl -p /servers -f HEADER + $ oscurl -p /servers -r RESP HTTP/1.1 200 OK - X-Compute-Request-Id: req-f2c0adc9-288b-4a65-8243-b112d1dc60b6 + Content-Length: 296 Content-Type: application/json - Content-Length: 366 - Date: Sun, 22 Jun 2014 12:25:16 GMT - - -* BODY: Only HTTP response body:: + Openstack-Api-Version: compute 2.42 + X-Openstack-Nova-Api-Version: 2.42 + Vary: OpenStack-API-Version, X-OpenStack-Nova-API-Version + X-Compute-Request-Id: req-565bb028-c144-40cc-8fb5-52f1c5ff3b58 + Date: Fri, 24 Mar 2017 09:07:08 GMT + Connection: keep-alive - $ oscurl -p /servers -f BODY - {"servers": [{"id": "fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "links": [{"href": "http://192.168.0.11:8774/v2/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "rel": "self"}, {"href": "http://192.168.0.11:8774/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "rel": "bookmark"}], "name": "server-test-1"}]} + {"servers": [{"id": "2820fcfc-3cd2-4a40-8c01-3c9544cfbc59", "links": [{"href": "http://172.27.201.206:8774/v2.1/servers/2820fcfc-3cd2-4a40-8c01-3c9544cfbc59", "rel": "self"}, {"href": "http://172.27.201.206:8774/servers/2820fcfc-3cd2-4a40-8c01-3c9544cfbc59", "rel": "bookmark"}], "name": "vm1"}]} -* JSON: Human-readable JSON format:: +* ``JSON``: Human-readable JSON format:: - $ oscurl -p /servers -f JSON + $ oscurl -p /servers --show-mode RESP -f JSON HTTP/1.1 200 OK - X-Compute-Request-Id: req-cf070813-5259-4b83-86bd-e4e2c6d31d1f + Content-Length: 296 Content-Type: application/json - Content-Length: 366 - Date: Sun, 22 Jun 2014 12:27:38 GMT + Openstack-Api-Version: compute 2.42 + X-Openstack-Nova-Api-Version: 2.42 + Vary: OpenStack-API-Version, X-OpenStack-Nova-API-Version + X-Compute-Request-Id: req-3293cc26-c336-454a-b361-0a97aaa8c571 + Date: Fri, 24 Mar 2017 09:09:14 GMT + Connection: keep-alive { "servers": [ { - "id": "fdec5b9e-9b6a-4eb4-8684-6c75cd275559", + "id": "2820fcfc-3cd2-4a40-8c01-3c9544cfbc59", "links": [ { - "href": "http://192.168.0.11:8774/v2/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559", + "href": "http://172.27.201.206:8774/v2.1/servers/2820fcfc-3cd2-4a40-8c01-3c9544cfbc59", "rel": "self" - }, + }, { - "href": "http://192.168.0.11:8774/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559", + "href": "http://172.27.201.206:8774/servers/2820fcfc-3cd2-4a40-8c01-3c9544cfbc59", "rel": "bookmark" } - ], - "name": "server-test-1" + ], + "name": "vm1" } ] } -* YAML: HTTP response body in YAML:: +* ``YAML``: HTTP response body in YAML:: - $ oscurl -p /servers -f YAML + $ oscurl -p /servers --show-mode RESP -f YAML HTTP/1.1 200 OK - X-Compute-Request-Id: req-14638074-8093-42d1-b872-5a4e6a5ebb6a + Content-Length: 296 Content-Type: application/json - Content-Length: 366 - Date: Sun, 22 Jun 2014 12:29:30 GMT + Openstack-Api-Version: compute 2.42 + X-Openstack-Nova-Api-Version: 2.42 + Vary: OpenStack-API-Version, X-OpenStack-Nova-API-Version + X-Compute-Request-Id: req-69d39243-cd55-4ee8-a6cf-9eb7a7e94fad + Date: Fri, 24 Mar 2017 09:11:18 GMT + Connection: keep-alive servers: - - id: fdec5b9e-9b6a-4eb4-8684-6c75cd275559 + - id: 2820fcfc-3cd2-4a40-8c01-3c9544cfbc59 links: - - {href: 'http://192.168.0.11:8774/v2/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559', + - {href: 'http://172.27.201.206:8774/v2.1/servers/2820fcfc-3cd2-4a40-8c01-3c9544cfbc59', rel: self} - - {href: 'http://192.168.0.11:8774/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559', + - {href: 'http://172.27.201.206:8774/servers/2820fcfc-3cd2-4a40-8c01-3c9544cfbc59', rel: bookmark} - name: server-test-1 - -* ``-r``: With HTTP request:: - - $ oscurl -p /servers -r - ==== HTTP REQUEST ==== - GET /v2/d046e2315c27456b9eb26740a9e39143/servers HTTP/1.1 - Host: 192.168.0.11:8774 - Accept-Encoding: identity - Content-Type: application/json - Accept: application/json - X-Auth-Token: MIIKswYJKoZ...KZ1BBJg== - - - ==== HTTP RESPONSE ==== - HTTP/1.1 200 OK - X-Compute-Request-Id: req-85955345-f8c4-41e9-859c-c20b5b1355f6 - Content-Type: application/json - Content-Length: 366 - Date: Sun, 22 Jun 2014 12:31:31 GMT - - {"servers": [{"id": "fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "links": [{"href": "http://192.168.0.11:8774/v2/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "rel": "self"}, {"href": "http://192.168.0.11:8774/d046e2315c27456b9eb26740a9e39143/servers/fdec5b9e-9b6a-4eb4-8684-6c75cd275559", "rel": "bookmark"}], "name": "server-test-1"}]} + name: vm1 diff --git a/oscurl/oscurl.py b/oscurl/oscurl.py index 3870092..6c9c568 100755 --- a/oscurl/oscurl.py +++ b/oscurl/oscurl.py @@ -6,6 +6,7 @@ import json import logging import os +import pprint import sys import time @@ -95,7 +96,11 @@ def do_request(body, cloud_config, options): requests_log.setLevel(logging.DEBUG) requests_log.propagate = True - if options.dump_request: + show_request = options.show_mode == 'ALL' + show_resp_header = options.show_mode in ['ALL', 'RESP'] + show_resp_body = options.show_mode in ['ALL', 'RESP', 'BODY'] + + if show_request: patch_send() headers = {} @@ -105,29 +110,33 @@ def do_request(body, cloud_config, options): response = client.request(url, method, data=body, headers=headers, raise_exc=False) - format = options.format - response_top = format_response_top(response) - response_headers = format_response_headers(response.headers) - if format == 'RAW': - print(response_top) - print(response_headers) - print(response.content) - elif format == 'HEADER': - print(response_top) - print(response_headers) - elif format == 'BODY': + if show_resp_header: + print(format_response_top(response)) + print(format_response_headers(response.headers)) + + if show_resp_body: + dump_body(response, options.body_format) + + +def dump_body(response, body_format): + if body_format == 'RAW': print(response.content) - elif format == 'YAML': - print(response_top) - print(response_headers) - if not response.content: - return - print(yaml.safe_dump(response.json(), encoding='utf-8')) - elif format == 'JSON': - print(response_top) - print(response_headers) - if not response.content: - return + return + + # YAML or JSON format + try: + data = response.json() + except ValueError: + # Output raw data as fallback + msg = '[!!!] Non-JSON data is returned. Displaying raw data.' + print('-' * len(msg), file=sys.stderr) + print(msg, file=sys.stderr) + print('-' * len(msg), file=sys.stderr) + pprint.pprint(response.content) + return + if body_format == 'YAML': + print(yaml.safe_dump(data, encoding='utf-8')) + else: print(json.dumps(response.json(), sort_keys=True, indent=2)) @@ -144,8 +153,10 @@ def main(): default_service = os.environ.get('OSCURL_SERVICE', 'compute') supported_methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'] default_method = os.environ.get('OSCURL_METHOD', 'GET') - supported_formats = ['RAW', 'HEADER', 'BODY', 'YAML', 'JSON', 'NONE'] + supported_formats = ['RAW', 'YAML', 'JSON'] default_format = os.environ.get('OSCURL_FORMAT', 'RAW') + supported_show_modes = ['ALL', 'RESP', 'BODY'] + default_show_mode = 'ALL' parser = argparse.ArgumentParser(description='oscurl %s' % VERSION) parser.add_argument("--full-help", @@ -179,16 +190,23 @@ def main(): default='') parser.add_argument("-P", "--full-path", help="full path of URL") - parser.add_argument("-f", "--format", dest="format", + parser.add_argument("-f", "--format", dest="body_format", help=("format of response output, " "default=%s (env[OSCURL_FORMAT] or RAW)" % default_format), type=string_upper, choices=supported_formats, default=default_format) - parser.add_argument("-r", "--dump-request", - action="store_true", - help="dump HTTP request") + parser.add_argument("-M", "--show-mode", + help=("Specify which part of request/response " + "should be displayed, " + "ALL (request and response), " + "RESP (response header and body), " + "BODY (response body only), " + "default: ALL"), + type=string_upper, + choices=supported_show_modes, + default=default_show_mode) parser.add_argument("-t", "--api", choices=['public', 'internal', 'admin'], help=("API type, default=public"))