From 38657bc1bffd41f4558fd6523b5fb970ffffecd9 Mon Sep 17 00:00:00 2001 From: Ryan Belgrave Date: Mon, 25 Jun 2018 17:47:03 -0500 Subject: [PATCH] update swagger autogen to include field types --- .../mounts/root/routes/compute/v1/images.py | 4 +- .../compute/v1/validation_models/images.py | 3 +- .../http/mounts/root/routes/iam/v1/policy.py | 4 +- .../http/mounts/root/routes/iam/v1/role.py | 8 +-- .../routes/iam/v1/validation_models/policy.py | 2 +- deli/counter/http/spec/plugins/docstring.py | 72 ++++++++++++++++--- 6 files changed, 72 insertions(+), 21 deletions(-) diff --git a/deli/counter/http/mounts/root/routes/compute/v1/images.py b/deli/counter/http/mounts/root/routes/compute/v1/images.py index 2d4ae10..3921fd2 100644 --- a/deli/counter/http/mounts/root/routes/compute/v1/images.py +++ b/deli/counter/http/mounts/root/routes/compute/v1/images.py @@ -10,7 +10,7 @@ from deli.kubernetes.resources.const import REGION_LABEL from deli.kubernetes.resources.model import ResourceState from deli.kubernetes.resources.project import Project -from deli.kubernetes.resources.v1alpha1.image.model import Image, ImageVisibility +from deli.kubernetes.resources.v1alpha1.image.model import Image from deli.kubernetes.resources.v1alpha1.region.model import Region @@ -87,7 +87,7 @@ def get(self, **_): @cherrypy.tools.model_params(cls=ParamsListImage) @cherrypy.tools.model_out_pagination(cls=ResponseImage) @cherrypy.tools.enforce_permission(permission_name="images:list") - def list(self, region_name, visibility: ImageVisibility, limit: int, marker: uuid.UUID): + def list(self, region_name, limit: int, marker: uuid.UUID): """List images --- get: diff --git a/deli/counter/http/mounts/root/routes/compute/v1/validation_models/images.py b/deli/counter/http/mounts/root/routes/compute/v1/validation_models/images.py index 923628d..e15f79f 100644 --- a/deli/counter/http/mounts/root/routes/compute/v1/validation_models/images.py +++ b/deli/counter/http/mounts/root/routes/compute/v1/validation_models/images.py @@ -3,7 +3,7 @@ from schematics.types import UUIDType, StringType, IntType from deli.kubernetes.resources.model import ResourceState -from deli.kubernetes.resources.v1alpha1.image.model import Image, ImageVisibility +from deli.kubernetes.resources.v1alpha1.image.model import Image class ParamsImage(Model): @@ -11,7 +11,6 @@ class ParamsImage(Model): class ParamsListImage(Model): - visibility = EnumType(ImageVisibility, default=ImageVisibility.PRIVATE) region_name = StringType() limit = IntType(default=100, max_value=100, min_value=1) marker = UUIDType() diff --git a/deli/counter/http/mounts/root/routes/iam/v1/policy.py b/deli/counter/http/mounts/root/routes/iam/v1/policy.py index 3a13964..b063e7d 100644 --- a/deli/counter/http/mounts/root/routes/iam/v1/policy.py +++ b/deli/counter/http/mounts/root/routes/iam/v1/policy.py @@ -78,7 +78,7 @@ def set(self): raise cherrypy.HTTPError(404, 'Unknown Group ' + email) if kind == 'serviceAccount': - _, project, *__ = domain.split('.') + project = domain.split('.')[1] if project != 'system': raise cherrypy.HTTPError(400, 'Can only add system service accounts to a system policy.') @@ -163,7 +163,7 @@ def set(self): raise cherrypy.HTTPError(404, 'Unknown Group ' + email) if kind == 'serviceAccount': - _, sa_project_name, *__ = domain.split('.') + sa_project_name = domain.split('.')[1] if sa_project_name == 'system': sa = SystemServiceAccount.get(user) diff --git a/deli/counter/http/mounts/root/routes/iam/v1/role.py b/deli/counter/http/mounts/root/routes/iam/v1/role.py index 7881f45..4e48132 100644 --- a/deli/counter/http/mounts/root/routes/iam/v1/role.py +++ b/deli/counter/http/mounts/root/routes/iam/v1/role.py @@ -142,7 +142,7 @@ def list(self, limit, marker): description: List system roles tags: - iam - - image + - role responses: 200: description: List of system roles @@ -181,7 +181,7 @@ def delete(self, **_): description: Delete a system role tags: - iam - - image + - role responses: 204: description: Role deleted @@ -243,7 +243,7 @@ def list(self, limit, marker): description: List project roles tags: - iam - - image + - role responses: 200: description: List of project roles @@ -282,7 +282,7 @@ def delete(self, **_): description: Delete a project role tags: - iam - - image + - role responses: 204: description: Role deleted diff --git a/deli/counter/http/mounts/root/routes/iam/v1/validation_models/policy.py b/deli/counter/http/mounts/root/routes/iam/v1/validation_models/policy.py index 2d2263e..3b239e3 100644 --- a/deli/counter/http/mounts/root/routes/iam/v1/validation_models/policy.py +++ b/deli/counter/http/mounts/root/routes/iam/v1/validation_models/policy.py @@ -45,7 +45,7 @@ def validate_member(self, value, context=None): if not self.EMAIL_REGEX.match(email): raise ValidationError(self.MESSAGES['email']) - _, domain = email.split('@') + domain = email.split('@')[1] if kind == 'user': if email.endswith('sandwich.local'): diff --git a/deli/counter/http/spec/plugins/docstring.py b/deli/counter/http/spec/plugins/docstring.py index 6d3edb6..24374e0 100644 --- a/deli/counter/http/spec/plugins/docstring.py +++ b/deli/counter/http/spec/plugins/docstring.py @@ -1,7 +1,12 @@ from apispec import Path from apispec.utils import load_operations_from_docstring +from ingredients_http.schematics.types import KubeName, ArrowType, IPv4AddressType, IPv4NetworkType, EnumType, \ + KubeString from schematics.models import FieldDescriptor +from schematics.types import IntType, StringType, BooleanType, UUIDType, EmailType, ListType, DictType, ModelType +from deli.counter.http.mounts.root.routes.iam.v1.validation_models.policy import BindingMemberType +from deli.counter.http.mounts.root.routes.iam.v1.validation_models.projects import ProjectName from deli.counter.http.router import SandwichProjectRouter @@ -20,7 +25,7 @@ def docstring_path_helper(spec, path, router, func, **kwargs): if 'tools.model_in.cls' in cp_config: model_cls = cp_config['tools.model_in.cls'] - spec.definition(model_cls.__name__, **parse_model(model_cls)) + spec.definition(model_cls.__name__, **parse_model(spec, model_cls)) data['requestBody']['required'] = True data['requestBody']['content'] = { @@ -43,14 +48,12 @@ def docstring_path_helper(spec, path, router, func, **kwargs): 'name': key, 'in': inn, 'required': model_cls._fields[key].required, - 'schema': { - 'type': 'string' - } + 'schema': parse_model_type(spec, model_cls._fields[key]) }) if 'tools.model_out.cls' in cp_config: model_cls = cp_config['tools.model_out.cls'] - spec.definition(model_cls.__name__, **parse_model(model_cls)) + spec.definition(model_cls.__name__, **parse_model(spec, model_cls)) data['responses'][200]['content'] = { 'application/json': { 'schema': {'$ref': '#/components/schemas/' + model_cls.__name__} @@ -59,7 +62,7 @@ def docstring_path_helper(spec, path, router, func, **kwargs): if 'tools.model_out_pagination.cls' in cp_config: model_cls = cp_config['tools.model_out_pagination.cls'] - spec.definition(model_cls.__name__, **parse_model(model_cls)) + spec.definition(model_cls.__name__, **parse_model(spec, model_cls)) data['responses'][200]['content'] = { 'application/json': { 'schema': { @@ -90,7 +93,7 @@ def setup(spec): spec.register_path_helper(docstring_path_helper) -def parse_model(model_cls): +def parse_model(spec, model_cls): kwargs = { 'properties': {}, 'extra_fields': { @@ -100,9 +103,7 @@ def parse_model(model_cls): } for key, obj in model_cls.__dict__.items(): if isinstance(obj, FieldDescriptor): - kwargs['properties'][key] = { - "type": "string" - } + kwargs['properties'][key] = parse_model_type(spec, model_cls._fields[key]) if model_cls._fields[key].required: kwargs['extra_fields']['required'].append(key) @@ -110,3 +111,54 @@ def parse_model(model_cls): del kwargs['extra_fields']['required'] return kwargs + + +def parse_model_type(spec, model_type): + swagger_types = { + StringType: 'string', + KubeName: 'string', + KubeString: 'string', + ProjectName: 'string', + UUIDType: 'string', + EmailType: 'string', + EnumType: 'string', + IPv4AddressType: 'string', + IPv4NetworkType: 'string', + ArrowType: 'string', + BindingMemberType: 'string', + IntType: 'integer', + BooleanType: 'boolean', + ListType: 'array', + DictType: 'object', + ModelType: 'object', + } + + data = { + # Find the swagger type, if not found default to string + # It would be nice to have complex types like uuid, emails, ect... + # But swagger doesn't support it + "type": swagger_types.get(model_type.__class__, "string") + } + + if model_type.__class__ == EnumType: + data['enum'] = [x.value for x in model_type.enum_class] + + if model_type.__class__ == ListType: + if model_type.field.__class__ == ModelType: + spec.definition(model_type.field.model_class.__name__, **parse_model(spec, model_type.field.model_class)) + data['items'] = { + '$ref': '#/components/schemas/' + model_type.field.model_class.__name__ + } + else: + data['items'] = parse_model_type(spec, model_type.field) + + if model_type.__class__ == DictType: + data['additionalProperties'] = parse_model_type(spec, model_type.field) + + if model_type.__class__ == ModelType: + spec.definition(model_type.model_class.__name__, **parse_model(spec, model_type.model_class)) + data['additionalProperties'] = { + '$ref': '#/components/schemas/' + model_type.model_class.__name__ + } + + return data