From 50dd3d67b384c27d1a36d5dc0f8ba02b7086f1ac Mon Sep 17 00:00:00 2001 From: eanylin Date: Thu, 1 Jun 2017 18:55:26 -0500 Subject: [PATCH 1/2] Initial Commit --- helm_shipyard/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 helm_shipyard/__init__.py diff --git a/helm_shipyard/__init__.py b/helm_shipyard/__init__.py new file mode 100644 index 00000000..f10bbbf6 --- /dev/null +++ b/helm_shipyard/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2017 AT&T Intellectual Property. All other rights reserved. +# +# 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. From 3268c6a13dfc288c777e7454ee1fd17cb28a6530 Mon Sep 17 00:00:00 2001 From: eanylin Date: Thu, 1 Jun 2017 21:05:05 -0500 Subject: [PATCH 2/2] WIP - Initial API implementation with Falcon --- helm_shipyard/{ => control}/__init__.py | 0 helm_shipyard/control/api.py | 29 ++++++++++ helm_shipyard/control/base.py | 66 ++++++++++++++++++++++ helm_shipyard/control/middleware.py | 73 +++++++++++++++++++++++++ helm_shipyard/control/tasks.py | 20 +++++++ 5 files changed, 188 insertions(+) rename helm_shipyard/{ => control}/__init__.py (100%) create mode 100644 helm_shipyard/control/api.py create mode 100644 helm_shipyard/control/base.py create mode 100644 helm_shipyard/control/middleware.py create mode 100644 helm_shipyard/control/tasks.py diff --git a/helm_shipyard/__init__.py b/helm_shipyard/control/__init__.py similarity index 100% rename from helm_shipyard/__init__.py rename to helm_shipyard/control/__init__.py diff --git a/helm_shipyard/control/api.py b/helm_shipyard/control/api.py new file mode 100644 index 00000000..af905bb3 --- /dev/null +++ b/helm_shipyard/control/api.py @@ -0,0 +1,29 @@ +# Copyright 2017 AT&T Intellectual Property. All other rights reserved. +# +# 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. +import falcon + +from .tasks import TasksResource +from .base import ShipyardRequest +from .middleware import AuthMiddleware, ContextMiddleware, LoggingMiddleware + +def start_api(state_manager): + control_api = falcon.API(request_type=ShipyardRequest, + middleware=[AuthMiddleware(), ContextMiddleware(), LoggingMiddleware()]) + + # API for managing region data + control_api.add_route('/region/{region_id}', TasksResource) + control_api.add_route('/region/{region_id}/server/{name}', TasksResource) + control_api.add_route('/region/{region_id}/service/{kind}', TasksResource) + + return control_api diff --git a/helm_shipyard/control/base.py b/helm_shipyard/control/base.py new file mode 100644 index 00000000..e380a995 --- /dev/null +++ b/helm_shipyard/control/base.py @@ -0,0 +1,66 @@ +# Copyright 2017 AT&T Intellectual Property. All other rights reserved. +# +# 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. +import falcon.request as request +import uuid + +class BaseResource(object): + + def on_options(self, req, resp): + self_attrs = dir(self) + methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'PATCH'] + allowed_methods = [] + + for m in methods: + if 'on_' + m.lower() in self_attrs: + allowed_methods.append(m) + + resp.headers['Allow'] = ','.join(allowed_methods) + resp.status = falcon.HTTP_200 + + # By default, no one is authorized to use a resource + def authorize_roles(self, role_list): + return False + + +class ShipyardRequestContext(object): + + def __init__(self): + self.log_level = 'error' + self.user = None + self.roles = ['anyone'] + self.request_id = str(uuid.uuid4()) + self.external_marker = None + + def set_log_level(self, level): + if level in ['error', 'info', 'debug']: + self.log_level = level + + def set_user(self, user): + self.user = user + + def add_role(self, role): + self.roles.append(role) + + def add_roles(self, roles): + self.roles.extend(roles) + + def remove_role(self, role): + self.roles = [x for x in self.roles + if x != role] + + def set_external_marker(self, marker): + self.external_marker = str(marker)[:32] + +class ShipyardRequest(request.Request) + context_type = ShipyardRequestContext diff --git a/helm_shipyard/control/middleware.py b/helm_shipyard/control/middleware.py new file mode 100644 index 00000000..3a35370c --- /dev/null +++ b/helm_shipyard/control/middleware.py @@ -0,0 +1,73 @@ +# Copyright 2017 AT&T Intellectual Property. All other rights reserved. +# +# 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. + +import falcon + +class AuthMiddleware(object): + + # Authentication + def process_request(self, req, resp): + ctx = req.context + token = req.get_header('X-Auth-Token') + + user = self.validate_token(token) + + if user is not None: + ctx.set_user(user) + user_roles = self.role_list(user) + ctx.add_roles(user_roles) + else: + ctx.add_role('anyone') + + # Authorization + def process_resource(self, req, resp, resource): + ctx = req.context + + if not resource.authorize_roles(ctx.roles): + raise falcon.HTTPUnauthorized('Authentication required', + ('This resource requires an authorized role.')) + + # Return the username associated with an authenticated token or None + def validate_token(self, token): + if token == '10': + return 'shipyard' + elif token == 'admin': + return 'admin' + else: + return None + + # Return the list of roles assigned to the username + # Roles need to be an enum + def role_list(self, username): + if username == 'shipyard': + return ['user'] + elif username == 'admin': + return ['user', 'admin'] + +class ContextMiddleware(object): + + def process_request(self, req, resp): + ctx = req.context + + requested_logging = req.get_header('X-Log-Level') + + if requested_logging == 'DEBUG' and 'admin' in ctx.roles: + ctx.set_log_level('debug') + elif requested_logging == 'INFO': + ctx.set_log_level('info') + +class LoggingMiddleware(object): + + def process_response(self, req, resp, resource, req_succeeded): + ctx = req.context diff --git a/helm_shipyard/control/tasks.py b/helm_shipyard/control/tasks.py new file mode 100644 index 00000000..7831d270 --- /dev/null +++ b/helm_shipyard/control/tasks.py @@ -0,0 +1,20 @@ +# Copyright 2017 AT&T Intellectual Property. All other rights reserved. +# +# 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. +import falcon + +from .base import BaseResource + +class TasksResource(BaseResource): + +class TaskResource(BaseResource):