From 11a7314326d2f09075f77dc97d5de83c508025b8 Mon Sep 17 00:00:00 2001 From: Kirill Zaitsev Date: Fri, 30 Dec 2016 16:29:02 +0300 Subject: [PATCH] Add bindings to runbook real api's Expands client to have post, put and delete methods required for API interaction --- ceagle/api/client.py | 73 ++++++++++++++++++++++++++++++++++++++- ceagle/api/v1/runbooks.py | 53 ++++++++++++++++++++++++---- ceagle/config.py | 3 ++ 3 files changed, 122 insertions(+), 7 deletions(-) diff --git a/ceagle/api/client.py b/ceagle/api/client.py index d26abb6..6652c69 100644 --- a/ceagle/api/client.py +++ b/ceagle/api/client.py @@ -32,12 +32,14 @@ class UnknownService(Exception): class Client(base.Client): + # TODO(kzaitsev): remove duplicating code into 'request' method + # and make these methods call it def get(self, uri="/", **kwargs): """Make GET request and decode JSON data. :param uri: resource URI :param kwargs: query parameters - :returns: dict response data + :returns: tuple: response data-dict and response code """ url = "%s%s" % (self.endpoint, uri) try: @@ -53,6 +55,75 @@ def get(self, uri="/", **kwargs): return result, response.status_code + def post(self, uri="/", **kwargs): + """Make POST request and decode JSON data. + + :param uri: resource URI + :param kwargs: query parameters + :returns: tuple: response data-dict and response code + """ + url = "%s%s" % (self.endpoint, uri) + try: + response = requests.post(url, **kwargs) + except requests.exceptions.ConnectionError: + mesg = "Service '%(name)s' is not available at '%(endpoint)s'" % ( + {"name": self.name, "endpoint": self.endpoint}) + return {"error": {"message": mesg}}, 502 + try: + result = response.json() + except ValueError: + return {"error": {"message": "Response can not be decoded"}}, 500 + + return result, response.status_code + + def put(self, uri="/", **kwargs): + """Make PUT request and decode JSON data. + + :param uri: resource URI + :param kwargs: query parameters + :returns: tuple: response data-dict and response code + """ + url = "%s%s" % (self.endpoint, uri) + try: + response = requests.put(url, **kwargs) + except requests.exceptions.ConnectionError: + mesg = "Service '%(name)s' is not available at '%(endpoint)s'" % ( + {"name": self.name, "endpoint": self.endpoint}) + return {"error": {"message": mesg}}, 502 + try: + result = response.json() + except ValueError: + return {"error": {"message": "Response can not be decoded"}}, 500 + + return result, response.status_code + + def delete(self, uri="/", **kwargs): + """Make DELETE request and decode JSON data. + + :param uri: resource URI + :param kwargs: query parameters + :returns: tuple: response data-dict and response code + """ + url = "%s%s" % (self.endpoint, uri) + try: + response = requests.put(url, **kwargs) + except requests.exceptions.ConnectionError: + mesg = "Service '%(name)s' is not available at '%(endpoint)s'" % ( + {"name": self.name, "endpoint": self.endpoint}) + return {"error": {"message": mesg}}, 502 + + if response.status_code == 204: + # NO_CONTENT is expected for delete methods + result = '' + else: + try: + result = response.json() + except ValueError: + return {"error": { + "message": "Response can not be decoded"}}, 500 + + return result, response.status_code + def get_client(service_name): """Return client for given service name, if possible. diff --git a/ceagle/api/v1/runbooks.py b/ceagle/api/v1/runbooks.py index a535be7..cdfcf17 100644 --- a/ceagle/api/v1/runbooks.py +++ b/ceagle/api/v1/runbooks.py @@ -15,6 +15,7 @@ import flask +from ceagle.api import client from ceagle.api_fake_data import fake_runbooks @@ -25,35 +26,75 @@ @bp.route("/region//runbooks", methods=["GET", "POST"]) @fake_runbooks.handle_runbooks -def handle_runbooks(region=None): - return flask.jsonify("fixme!") +def handle_runbooks(region=''): + api_endpoint = "/api/v1/region/{}/runbooks".format(region) + + if flask.request.method == "GET": + read_client = client.get_client("runbook-read") + if not region: + api_endpoint = "/api/v1/runbooks" + params = flask.request.args + result, code = read_client.get(api_endpoint, params=params) + else: # POST + write_client = client.get_client("runbook-write") + new_runbook = flask.request.get_json(silent=True) or {} + result, code = write_client.post(api_endpoint, json=new_runbook) + return flask.jsonify(result), code @bp.route("/region//runbooks/", methods=["GET", "PUT", "DELETE"]) @fake_runbooks.handle_single_runbook def handle_single_runbook(region, book_id): - return flask.jsonify("fixme!") + api_endpoint = "/api/v1/region/{}/runbooks/{}".format( + region, book_id) + + if flask.request.method == "GET": + read_client = client.get_client("runbook-read") + result, code = read_client.get(api_endpoint) + elif flask.request.method == "PUT": + write_client = client.get_client("runbook-write") + new_runbook = flask.request.get_json(silent=True) or {} + result, code = write_client.put(api_endpoint, json=new_runbook) + elif flask.request.method == "DELETE": + write_client = client.get_client("runbook-write") + result, code = write_client.delete(api_endpoint) + return flask.jsonify(result), code @bp.route("/region//runbooks//run", methods=["POST"]) @fake_runbooks.run_runbook def run_runbook(region, book_id): - return flask.jsonify("fixme!") + run_client = client.get_client("runbook-run") + run_settings = flask.request.get_json(silent=True) or {} + api_endpoint = "/api/v1/region/{}/runbooks/{}/run".format(region, book_id) + result, code = run_client.post(api_endpoint, json=run_settings) + return flask.jsonify(result), code @bp.route("/runbook_runs") @bp.route("/region//runbook_runs") @fake_runbooks.runbook_runs def runbook_runs(region=None): - return flask.jsonify("fixme!") + read_client = client.get_client("runbook-read") + if region: + api_endpoint = "/api/v1/region/{}/runbook_runs".format(region) + else: + api_endpoint = "/api/v1/runbook_runs" + params = flask.request.args + result, code = read_client.get(api_endpoint, params=params) + return flask.jsonify(result), code @bp.route("/region//runbook_runs/") @fake_runbooks.single_runbook_run def single_runbook_run(region, run_id): - return flask.jsonify("fixme!") + read_client = client.get_client("runbook-read") + api_endpoint = "/api/v1/region/{}/runbook_runs/{}".format(region, run_id) + params = flask.request.args + result, code = read_client.get(api_endpoint, params=params) + return flask.jsonify(result), code def get_blueprints(): diff --git a/ceagle/config.py b/ceagle/config.py index 50e3a17..56a6fc7 100644 --- a/ceagle/config.py +++ b/ceagle/config.py @@ -31,6 +31,9 @@ "health": {"type": "string"}, "optimization": {"type": "string"}, "performance": {"type": "string"}, + "runbook-read": {"type": "string"}, + "runbook-write": {"type": "string"}, + "runbook-run": {"type": "string"}, "security": {"type": "string"}, "infra": { "type": "object",