Commit 7f5845ce authored by Daniele Venzano's avatar Daniele Venzano

Implement ZApp validation endpoint, update docs and tests

parent f16c6073
......@@ -5,7 +5,7 @@ Zoe REST API
Zoe can be used from the command line or the web interface. For more complex tasks also an API is provided, so that Zoe functionality can be accesses programmatically.
The API is provided by the zoe-api processes, on the same port of the web interface (5001 by default). Every URL of the API contains, after the hostname and port, the path ``/api/<api version>/``. This document describes API version 0.6.
The API is provided by the zoe-api processes, on the same port of the web interface (5001 by default). Every URL of the API contains, after the hostname and port, the path ``/api/<api version>/``. **The current API version is 0.7**.
In case the request causes an error, an appropriate HTTP status code is returned. The reply will also contain a JSON document in this format::
......@@ -22,16 +22,16 @@ Info endpoint
This endpoint does not need authentication. It returns general, static, information about the Zoe software. It is meant for checking that the client is able to talk correctly to the API server::
curl http://bf5:8080/api/0.6/info
curl http://bf5:8080/api/<api_version>/info
Will return a JSON document, like this::
{
"version" : "0.10.1-beta",
"version" : "2017.06",
"deployment_name" : "prod",
"application_format_version" : 2,
"api_version" : "0.6"
"application_format_version" : 3,
"api_version" : "0.7"
}
Where:
......@@ -41,6 +41,27 @@ Where:
* ``application_format_version`` is the version of ZApp format this Zoe is able to understand
* ``api_version`` is the API version supported by this Zoe and should match the one used in the request URL
ZApp validation endpoint
------------------------
This endpoint does not need authentication. Use this endpoint to validate ZApp descriptions against the deployed Zoe version.
Usage::
curl -X POST --data-urlencode @filename http://bf5:8080/api/<api_version>/zapp_validate
Needs a JSON document passed as the request body::
{
"application": <zapp json>,
}
Where:
* ``application`` is the full ZApp JSON document, the application description
Will return a 201 HTTP status in case the JSON document passes validation, 400 otherwise.
Execution endpoint
------------------
......@@ -51,7 +72,7 @@ Execution details
Request (GET)::
curl -u 'username:password' http://bf5:8080/api/0.6/execution/<execution_id>
curl -u 'username:password' http://bf5:8080/api/<api_version>/execution/<execution_id>
Where:
......@@ -97,7 +118,7 @@ This endpoint terminates a running execution.
Request (DELETE)::
curl -X DELETE -u 'username:password' http://bf5:8080/api/0.6/execution/<execution_id>
curl -X DELETE -u 'username:password' http://bf5:8080/api/<api_version>/execution/<execution_id>
If the request is successful an empty response with status code 200 will be returned.
......@@ -107,7 +128,7 @@ This endpoint deletes an execution from the database, terminating it if it is ru
Request (DELETE)::
curl -u 'username:password' http://bf5:8080/api/0.6/execution/delete/<execution_id>
curl -u 'username:password' http://bf5:8080/api/<api_version>/execution/delete/<execution_id>
If the request is successful an empty response with status code 200 will be returned.
......@@ -118,7 +139,7 @@ This endpoint will list all executions belonging to the calling user. If the use
Request (GET)::
curl -u 'username:password' http://bf5:8080/api/0.6/execution
curl -u 'username:password' http://bf5:8080/api/<api_version>/execution
Will return a JSON document like this::
......@@ -149,7 +170,7 @@ Start execution
Request (POST)::
curl -X POST -u 'username:password' --data-urlencode @filename http://bf5:8080/api/0.6/execution
curl -X POST -u 'username:password' --data-urlencode @filename http://bf5:8080/api/<api_version>/execution
Needs a JSON document passed as the request body::
......@@ -183,7 +204,7 @@ Service details
Request::
curl -u 'username:password' http://bf5:8080/api/0.6/service/<service_id>
curl -u 'username:password' http://bf5:8080/api/<api_version>/service/<service_id>
Will return a JSON document like this::
......@@ -225,7 +246,7 @@ Service standard output and error
Request::
curl -u 'username:password' http://bf5:8080/api/0.6/service/logs/<service_id>
curl -u 'username:password' http://bf5:8080/api/<api_version>/service/logs/<service_id>
Will stream the service instance output, starting from the time the service started. It will close the connection when the service exits.
......@@ -236,7 +257,7 @@ This endpoint does not need authentication. It returns a list of services that m
Request::
curl http://bf5:8080/api/0.6/discovery/by_group/<execution_id>/<service_type>
curl http://bf5:8080/api/<api_version>/discovery/by_group/<execution_id>/<service_type>
Where:
......@@ -268,7 +289,7 @@ Scheduler
^^^^^^^^^
Request::
curl http://bf5:8080/api/0.6/statistics/scheduler
curl http://bf5:8080/api/<api_version>/statistics/scheduler
Will return a JSON document, like this::
......@@ -292,7 +313,7 @@ Request new access token
Request::
curl -u 'username:password' http://bf5:8080/api/0.6/oauth/token -X POST -H 'Content-Type: application/json' -d '{"grant_type": "password"}'
curl -u 'username:password' http://bf5:8080/api/<api_version>/oauth/token -X POST -H 'Content-Type: application/json' -d '{"grant_type": "password"}'
Will return a JSON document, like this::
......@@ -315,7 +336,7 @@ Refresh an access token
Request::
curl -H 'Authorization: Bearer 9bab190f-e211-42aa-917e-20ce987e355e' http://bf5:8080/api/0.6/oauth/token -X POST -H 'Content-Type: application/json' -d '{"grant_type": "refresh_token"}'
curl -H 'Authorization: Bearer 9bab190f-e211-42aa-917e-20ce987e355e' http://bf5:8080/api/<api_version>/oauth/token -X POST -H 'Content-Type: application/json' -d '{"grant_type": "refresh_token"}'
Will return a JSON document, like this::
......@@ -334,7 +355,7 @@ Revoke an access/refresh token
Request::
curl -u 'usernam:password' -X DELETE http://bf5:8080/api/0.6/oauth/revoke/<token>
curl -u 'usernam:password' -X DELETE http://bf5:8080/api/<api_version>/oauth/revoke/<token>
Where:
......@@ -352,7 +373,7 @@ Instead of sending raw username, password to request results from other api endp
Example::
curl -H 'Authorization: Bearer 378f8d5f-2eb5-4181-b632-ad23c4534d32' http://bf5:8080/api/0.6/execution
curl -H 'Authorization: Bearer 378f8d5f-2eb5-4181-b632-ad23c4534d32' http://bf5:8080/api/<api_version>/execution
Login endpoint
--------------
......@@ -360,7 +381,7 @@ Get back a cookie for further authentication/authorization with other api endpoi
Request::
curl -u 'username:password' -c zoe_cookie.txt http://bf5:8080/api/0.6/login
curl -u 'username:password' -c zoe_cookie.txt http://bf5:8080/api/<api_version>/login
Will return a JSON document, like this::
......@@ -375,11 +396,10 @@ Pass this cookie on each api request which requires authentication.
Example::
curl -b zoe_cookie.txt http://bf5:8080/api/0.6/execution
curl -b zoe_cookie.txt http://bf5:8080/api/<api_version>/execution
Note:
- For zoe web interface, we require cookie_based mechanism for authentication/authorization.
- Every unauthorized request will be redirected to **http://bf5:8080/login**
- After successfully login, a cookie will be saved at browser for further authentication/authorization purpose.
......@@ -77,6 +77,16 @@ class ZoeRestTestSuccess(unittest.TestCase):
self.assertEqual(req.status_code, 201)
self.__class__.id = str(req.json()['execution_id'])
def test_zapp_validate(self):
"""Test ZApp validation endpoint"""
print("Test ZApp validation endpoint")
with open('zapp.json', encoding='utf-8') as data_file:
data = json.loads(data_file.read())
req = requests.post(self.__class__.uri + 'zapp_validate', json={"application": data})
self.assertEqual(req.status_code, 201)
if __name__ == '__main__':
if len(sys.argv) > 1:
API_SERVER = sys.argv.pop()
......
......@@ -68,6 +68,13 @@ class APIEndpoint:
proxy = None
return proxy
def zapp_validate(self, application_description):
"""Validates the passed ZApp description against the supported schema."""
try:
zoe_lib.applications.app_validate(application_description)
except zoe_lib.exceptions.InvalidApplicationDescription as e:
raise zoe_api.exceptions.ZoeException('Invalid application description: ' + e.message)
def execution_start(self, uid, role, exec_name, application_description):
"""Start an execution."""
try:
......
......@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""RESTful Flask API definition."""
"""RESTful Tornado API definition."""
from typing import List
......@@ -27,6 +27,7 @@ from zoe_api.rest_api.discovery import DiscoveryAPI
from zoe_api.rest_api.statistics import SchedulerStatsAPI
from zoe_api.rest_api.oauth import OAuthGetAPI, OAuthRevokeAPI
from zoe_api.rest_api.login import LoginAPI
from zoe_api.rest_api.validation import ZAppValidateAPI
from zoe_lib.version import ZOE_API_VERSION
......@@ -43,6 +44,7 @@ def api_init(api_endpoint) -> List[tornado.web.URLSpec]:
tornado.web.url(API_PATH + r'/info', InfoAPI, route_args),
tornado.web.url(API_PATH + r'/login', LoginAPI, route_args),
tornado.web.url(API_PATH + r'/userinfo', UserInfoAPI, route_args),
tornado.web.url(API_PATH + r'/zapp_validate', ZAppValidateAPI, route_args),
tornado.web.url(API_PATH + r'/execution/([0-9]+)', ExecutionAPI, route_args),
tornado.web.url(API_PATH + r'/execution/delete/([0-9]+)', ExecutionDeleteAPI, route_args),
......
# Copyright (c) 2017, Daniele Venzano
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""The Info API endpoint."""
from tornado.web import RequestHandler
import tornado.escape
from zoe_api.rest_api.utils import catch_exceptions, manage_cors_headers
from zoe_api.api_endpoint import APIEndpoint # pylint: disable=unused-import
import zoe_api.exceptions
class ZAppValidateAPI(RequestHandler):
"""The Info API endpoint."""
def initialize(self, **kwargs):
"""Initializes the request handler."""
self.api_endpoint = kwargs['api_endpoint'] # type: APIEndpoint
def set_default_headers(self):
"""Set up the headers for enabling CORS."""
manage_cors_headers(self)
def options(self):
"""Needed for CORS."""
self.set_status(204)
self.finish()
@catch_exceptions
def post(self):
"""HTTP GET method."""
try:
data = tornado.escape.json_decode(self.request.body)
except ValueError:
raise zoe_api.exceptions.ZoeRestAPIException('Error decoding JSON data')
application_description = data['application']
self.api_endpoint.zapp_validate(application_description)
self.write({'validation': 'ok'})
def data_received(self, chunk):
"""Not implemented as we do not use stream uploads"""
pass
# Copyright (c) 2016, Daniele Venzano
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module contains the Zoe Info API.
"""
import logging
from zoe_lib.api_base import ZoeAPIBase
from zoe_lib.exceptions import ZoeAPIException
log = logging.getLogger(__name__)
class ZoeValidationAPI(ZoeAPIBase):
"""
The Info API class. This API exports static information about Zoe, versions and configuration.
"""
def validate(self, application_description):
"""
Queries Zoe for versions and local configuration parameters.
:return:
"""
zapp = {
"application": application_description,
}
data, status_code = self._rest_post('/zapp_validate', zapp)
if status_code != 201:
raise False
else:
return True
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment