diff --git a/Dockerfile.dev b/Dockerfile.dev index 3ec83d0eae4d5773ad71e0708f0690d597e2ec28..e98c55558d66478fc09a75b5389bc6b4a12bbeed 100755 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -9,4 +9,5 @@ RUN pip3 install -e ".[dev]" CMD \ RUNNER="coverage run --append --data-file=/mounted/.tmp/.coverage $(which dns-zone-manager-server)" \ RUN_WITH_WSGI="--run-with-wsgi" \ + GENERATE_SWAGGER="--swagger /mounted/.tmp/ZM_swagger.yaml" \ bash -x ./script.sh "${PORT_ENV}" diff --git a/Makefile b/Makefile index 2a06b64cd2f972371e3dd1da6b03b13d06d1ccae..12e74e56e32a58dc5a5d9b0b32fd15d89f90f14e 100644 --- a/Makefile +++ b/Makefile @@ -136,12 +136,22 @@ docker-coverage-html-dns-zone-manager-server-dev: localhost/dns-zone-manager-server-dev \ coverage html --data-file=/mounted/.tmp/.coverage --directory=/mounted/.tmp/htmlcov -docker-swagger: +docker-swagger-old: mkdir -p "$(CURDIR)/.tmp" docker run -it \ -v "$(CURDIR)/.tmp:/mounted/.tmp" \ + -v "$(CURDIR)/zonedb:/usr/lib/zonemgr/zonedb" \ -v "$(CURDIR)/tests:/mounted/tests" \ -e DNS_ZONE_MANAGER_SERVER_AUTH_CONF_PATH='auth.conf' \ --network=host \ localhost/dns-zone-manager-server-dev \ - dns-zone-manager-server --database sqlite:////var/lib/zonemgr/zones.db swagger --path /mounted/.tmp/swagger.yaml + dns-zone-manager-server --database sqlite:////var/lib/zonemgr/zones.db swagger \ + --no-run-with-wsgi --path /mounted/.tmp/swagger.yaml + +docker-swagger: + mkdir -p "$(CURDIR)/.tmp" + docker run -it \ + -p 16001:16001 -p 53:53 -p 53:53/udp \ + -v "$(CURDIR)/.tmp:/mounted/.tmp" \ + -v "$(CURDIR)/zonedb:/usr/lib/zonemgr/zonedb" \ + localhost/dns-zone-manager-server-dev diff --git a/README.md b/README.md index 170d7dfb83ad82dea74633cdfa89e22662588744..74aacafa2e6e0322aff789e07945f61e0841cbc8 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,9 @@ The implementation was done based on [LIGHTest zone manager](https://github.com/ ``` + See the [openapi specification](/docs/ZM_swagger.yaml). + + 4. Optionally, run tests once the zone manager server is up See the [tests](/tests) for details. The tests include getting a valid token from the configured identity provider. diff --git a/docs/ZM_swagger.yaml b/docs/ZM_swagger.yaml new file mode 100644 index 0000000000000000000000000000000000000000..381dc5e5c60f3131511a19e54c19023ac29398fa --- /dev/null +++ b/docs/ZM_swagger.yaml @@ -0,0 +1,200 @@ +description: A tool to handle zones in DNS +securityDefinitions: + jwt_auth: + type: apiKey + name: Authorization + in: header + description: 'JWT Authorization header using the Bearer scheme. Example: "Authorization: + Bearer {token}"' +paths: + /status: + get: + description: Get zone manager service status + tags: + - Health Check + responses: + '200': + description: Status and healthcheck + schema: + $ref: '#/definitions/StatusResponse' + '401': + description: Unauthorized, not valid token + /names/{scheme_name}/trust-list: + delete: + description: Delete trust list pointer + tags: + - Trust Lists (DIDs) + security: + - jwt_auth: [] + responses: + '204': + description: Pointer to trust list removed + '401': + description: Unauthorized, not valid token + '404': + description: Not found + get: + description: Get trust list pointer + security: + - jwt_auth: [] + tags: + - Trust Lists (DIDs) + responses: + '200': + description: Trust list pointer + '401': + description: Unauthorized, not valid token + '404': + description: Not found. Non existing trust list framework + put: + description: Publish trust list pointer + tags: + - Trust Lists (DIDs) + security: + - jwt_auth: [] + responses: + '200': + description: Publish trust list pointer + schema: + $ref: '#/definitions/TrustListResponse' + '401': + description: Unauthorized, not valid token + /names/{scheme_name}/schemes: + delete: + description: Delete trust list framework + tags: + - Schemes (Trust Frameworks) + security: + - jwt_auth: [] + responses: + '204': + description: Pointer to trust framework removed + '401': + description: Unauthorized, not valid token + '404': + description: Not found. Non-existing framework + get: + description: Get trust Framework pointer + tags: + - Schemes (Trust Frameworks) + security: + - jwt_auth: [] + responses: + '200': + description: Trust Framework pointer + schema: + $ref: '#/definitions/SchemesResponse' + '401': + description: Unauthorized, not valid token + '404': + description: Not found. Non existing trust Framework + put: + description: Publish trust Framework pointer + tags: + - Schemes (Trust Frameworks) + security: + - jwt_auth: [] + responses: + '200': + description: Trust Framework pointer publication + schema: + $ref: '#/definitions/SchemesResponse' + '401': + description: Unauthorized, not valid token + /view-zone: + get: + description: Visualization of zone + tags: + - View Zone + security: + - jwt_auth: [] + responses: + '200': + description: Zone visualization + schema: + $ref: '#/definitions/ViewZoneResponse' + '401': + description: Unauthorized, not valid token +info: + title: Eclipse XFSC TRAIN DNS Trustzone Manager + version: 1.0.0 +swagger: '2.0' +definitions: + Dependencies: + type: object + properties: + Zone_Manager_server_status: + type: string + Database_status: + type: string + NSD_server_status: + type: string + StatusResponse: + type: object + properties: + zone: + type: string + status: + type: string + dependencies: + $ref: '#/definitions/Dependencies' + SubScheme: + type: object + properties: + subscheme: + type: string + trustListDid: + type: string + required: + - subscheme + - trustListDid + Scheme: + type: object + properties: + name: + type: string + subSchemes: + type: array + items: + $ref: '#/definitions/SubScheme' + required: + - name + - subSchemes + Zone: + type: object + properties: + id: + type: string + apex: + type: string + schemes: + type: array + items: + $ref: '#/definitions/Scheme' + required: + - apex + - id + - schemes + ViewZoneResponse: + type: object + properties: + zones: + type: array + items: + $ref: '#/definitions/Zone' + required: + - zones + SchemesResponse: + type: object + properties: + schemes: + type: array + items: + type: string + TrustListResponse: + type: object + properties: + did: + type: string + required: + - did diff --git a/docs/zonemanager_api v1.yaml b/docs/zonemanager_api v1.yaml deleted file mode 100644 index 179424ccb33cfbc82afc8aacb522008c164326a4..0000000000000000000000000000000000000000 --- a/docs/zonemanager_api v1.yaml +++ /dev/null @@ -1,208 +0,0 @@ -openapi: 3.0.3 -info: - title: Zone Manager - description: |- - First draft. Includes all endpoints to be implemented. Needs refinement - contact: - email: juan.vargas@iao.fraunhofer.de - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html - version: 0.0.1 - -servers: - - url: http://localhost:8181 -tags: - - name: Status - description: Status - - name: Trust Framework (schemes) - description: CRD operations for schemes - - name: Trust Lists - description: CRUD operations for trust lists - - name: View Zone data - description: Display zone data (for UI) - - -paths: - /status: - get: - tags: - - Status - summary: Check status of Zone Manager server - description: TBD - responses: - '200': - description: Successful operation - '400': - description: Invalid parameters supplied - '401': - description: Unauthorized to create/update trust frameworks - /names/{scheme-name}/schemes: - get: - tags: - - Trust Framework (schemes) - summary: Get Trust Scheme - description: TBD - parameters: - - in: path - name: scheme-name - schema: - type: string - required: true - description: Name of new trust scheme - responses: - '200': - description: Successful operation - '400': - description: Invalid parameters supplied - '401': - description: Unauthorized to create/update trust frameworks - put: - tags: - - Trust Framework (schemes) - summary: Create a new Trust Scheme - description: TBD - operationId: put Trust Framework - parameters: - - in: path - name: scheme-name - schema: - type: string - required: true - description: Name of new trust scheme - requestBody: - description: Create a trust scheme - content: - application/json: - schema: - $ref: '#/components/schemas/trust-scheme' - application/xml: - schema: - $ref: '#/components/schemas/trust-scheme' - responses: - '200': - description: Successful operation - '400': - description: Invalid parameters supplied - '401': - description: Unauthorized to create/update trust frameworks - delete: - tags: - - Trust Framework (schemes) - summary: Delete a new Trust scheme - description: TBD. With this route you can delete a trust scheme. Removes the PTR Resource Record in the DNS Zone File - operationId: delete Trust scheme - parameters: - - in: path - name: scheme-name - schema: - type: string - required: true - description: Name of trust scheme to be deleted - responses: - '200': - description: Successful removal - '400': - description: Invalid parameters supplied - '401': - description: Unauthorized to delete trust schemes - - /names/{scheme-name}/trust-list: - get: - tags: - - Trust Lists - summary: Get Trust List - description: TBD - parameters: - - in: path - name: scheme-name - schema: - type: string - required: true - description: Name of new trust List - responses: - '200': - description: Successful operation - '400': - description: Invalid parameters supplied - '401': - description: Unauthorized to create/update trust frameworks - put: - tags: - - Trust Lists - summary: Create a new Trust List - description: TBD - parameters: - - in: path - name: scheme-name - schema: - type: string - required: true - description: Name of new trust List - requestBody: - description: Create a trust List - content: - application/json: - schema: - $ref: '#/components/schemas/trust-list' - application/xml: - schema: - $ref: '#/components/schemas/trust-list' - responses: - '200': - description: Successful operation - '400': - description: Invalid parameters supplied - '401': - description: Unauthorized to create/update trust frameworks - delete: - tags: - - Trust Lists - summary: Delete a new Trust Framework - description: TBD. With this route you can delete a trust framework. Removes the PTR Resource Record in the DNS Zone File - operationId: delete Trust Framework - parameters: - - in: path - name: framework-name - schema: - type: string - required: true - description: Name of trust framework to be deleted - responses: - '200': - description: Successful removal - '400': - description: Invalid parameters supplied - '401': - description: Unauthorized to delete trust frameworks - - /view-zone: - get: - tags: - - View Zone data - summary: Display Zone Manager data. This includes trust frameworks and trust lists associated with each trust framework - description: TBD - responses: - '200': - description: Successful operation - '400': - description: Invalid parameters supplied - '401': - description: Unauthorized to create/update trust frameworks - -components: - schemas: - trust-scheme: - type: object - properties: - schemes: - type: array - items: - type: string - trust-list: - type: object - properties: - did: - type: array - items: - type: string diff --git a/docs/zonemanager_swagger.json b/docs/zonemanager_swagger.json deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/script.sh b/script.sh index c5bbca71661cb0dbf12f88c073721060b2be43cb..ae1e9b6d817913bd5ef6dd00680b67775a9cd851 100755 --- a/script.sh +++ b/script.sh @@ -155,4 +155,4 @@ service nsd status echo echo "[INFO] Starting the Zone Manager service in port ${SERVER_PORT} ..." -${RUNNER} --database $SQLITE_DB server -e network "0.0.0.0:${SERVER_PORT}" ${RUN_WITH_WSGI:-} +${RUNNER} --database $SQLITE_DB server -e network "0.0.0.0:${SERVER_PORT}" ${RUN_WITH_WSGI:-} ${GENERATE_SWAGGER:-} diff --git a/zonedb/__init__.py b/zonedb/__init__.py old mode 100644 new mode 100755 diff --git a/zonedb/api.py b/zonedb/api.py index 74a73702f895dcac3e948260c83aa70eb27c934f..bc10e9713761af922cf13e6a5078aa57dc5ecc32 100755 --- a/zonedb/api.py +++ b/zonedb/api.py @@ -17,6 +17,8 @@ from sqlalchemy.orm.exc import NoResultFound from zonedb.master import refresh_zonefile, reload_master from zonedb.models import SchemeClaim, TrustList, TrustListCert, Zone +from zonedb.schemas import (SchemeResponseSchema, StatusSchema, + TrustListResponseSchema, ViewZoneResponseSchema) LOG = logging.getLogger(__name__) @@ -177,6 +179,8 @@ class TrustListResource: """Get a trust list pointer (did) --- description: Get trust list pointer + security: + - jwt_auth: [] tags: - Trust Lists (DIDs) responses: @@ -204,6 +208,8 @@ class TrustListResource: description: Publish trust list pointer tags: - Trust Lists (DIDs) + security: + - jwt_auth: [] responses: 200: description: Publish trust list pointer @@ -250,6 +256,8 @@ class TrustListResource: description: Delete trust list pointer tags: - Trust Lists (DIDs) + security: + - jwt_auth: [] responses: 204: description: Pointer to trust list removed @@ -291,6 +299,8 @@ class SchemeClaimResource: description: Get trust Framework pointer tags: - Schemes (Trust Frameworks) + security: + - jwt_auth: [] responses: 200: description: Trust Framework pointer @@ -322,6 +332,8 @@ class SchemeClaimResource: description: Publish trust Framework pointer tags: - Schemes (Trust Frameworks) + security: + - jwt_auth: [] responses: 200: description: Trust Framework pointer publication @@ -383,6 +395,8 @@ class SchemeClaimResource: description: Delete trust list framework tags: - Schemes (Trust Frameworks) + security: + - jwt_auth: [] responses: 204: description: Pointer to trust framework removed @@ -420,6 +434,8 @@ class ViewZone: description: Visualization of zone tags: - View Zone + security: + - jwt_auth: [] responses: 200: description: Zone visualization @@ -468,15 +484,61 @@ class ApiApplication(gunicorn.app.base.BaseApplication): "Request", (falcon.Request,), dict(context_type=lambda rq: self.options) ) ) + routes = { + "status" : Status(), + "trust_list" : TrustListResource( + list_type="scheme", + run_with_wsgi=self.options.run_with_wsgi + ), + "scheme_claim" : SchemeClaimResource( + run_with_wsgi=self.options.run_with_wsgi + ), + "view_zone" : ViewZone() + } + + api.add_route("/status", routes["status"]) + api.add_route("/names/{scheme_name}/trust-list", routes["trust_list"]) + api.add_route("/names/{scheme_name}/schemes", routes["scheme_claim"]) + api.add_route("/view-zone", routes["view_zone"]) - api.add_route("/status", Status()) - api.add_route("/names/{scheme_name}/trust-list", TrustListResource( - list_type="scheme", - run_with_wsgi=self.options.run_with_wsgi - )) - api.add_route("/names/{scheme_name}/schemes", SchemeClaimResource( - run_with_wsgi=self.options.run_with_wsgi - )) - api.add_route("/view-zone", ViewZone()) + if self.options.swagger: + self.swagger(api,routes) return api + + def swagger(self,api,routes): + from apispec import APISpec + from apispec.ext.marshmallow import MarshmallowPlugin + from falcon_apispec import FalconPlugin + + spec = APISpec( + title='Eclipse XFSC TRAIN DNS Trustzone Manager', + version='1.0.0', + openapi_version='2.0', + plugins=[ + FalconPlugin(api), + MarshmallowPlugin(), + ], + securityDefinitions={ + 'jwt_auth': { + 'type': 'apiKey', + 'name': 'Authorization', + 'in': 'header', + 'description': 'JWT Authorization header using the Bearer scheme. Example: "Authorization: Bearer {token}"', + } + } + ) + + spec.components.schema('StatusResponse', schema=StatusSchema) + spec.components.schema('ViewZoneResponse', schema=ViewZoneResponseSchema) + spec.components.schema('SchemesResponse', schema=SchemeResponseSchema) + spec.components.schema('TrustListResponse', schema=TrustListResponseSchema) + spec.path(resource=routes["status"]) + spec.path(resource=routes["trust_list"]) + spec.path(resource=routes["scheme_claim"]) + spec.path(resource=routes["view_zone"]) + + spec_yaml = spec.to_yaml() + LOG.debug("writing yaml swagger spec into " + self.options.swagger) + with open(self.options.swagger, 'w') as file: + file.write(spec_yaml) diff --git a/zonedb/cli.py b/zonedb/cli.py index 597e9e90f937a0694e8928bcf218b2e7e0df6322..bd01cc94e04e58f55cb0520ecce153a9b9e70ca2 100755 --- a/zonedb/cli.py +++ b/zonedb/cli.py @@ -1,5 +1,4 @@ import argparse -import json import logging from os import path @@ -7,11 +6,8 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from zonedb import master -from zonedb.api import (ApiApplication, SchemeClaimResource, Status, - TrustListResource, ViewZone) +from zonedb.api import (ApiApplication) from zonedb.models import AuthToken, Base, Environment, Record, Zone -from zonedb.schemas import (SchemeResponseSchema, StatusSchema, - TrustListResponseSchema, ViewZoneResponseSchema) LOG = logging.getLogger(__name__) @@ -33,7 +29,6 @@ def get_config(): AddRecord.args(subparsers) AddToken.args(subparsers) Server.args(subparsers) - Swagger.args(subparsers) return parser.parse_args() @@ -219,6 +214,9 @@ class Server: sub.add_argument("--run-with-wsgi", action=argparse.BooleanOptionalAction, help="Run with wsgi mode, use for dev coverage mode") + sub.add_argument("--swagger", "-s", action="store", + help="If passed, specify the path to store Swagger documentation") + sub.set_defaults(func=cls.run) @classmethod @@ -243,61 +241,6 @@ class Server: httpd.serve_forever() -class Swagger: - """Creates a Swagger specification.""" - - @classmethod - def args(cls, subparsers): - sub = subparsers.add_parser("swagger", help=Swagger.__doc__) - sub.set_defaults(func=cls.run) - - @classmethod - def run(cls, config): - # keep imports here since all of them need to be invoked into dev setup and not prod - # pylint: disable=import-outside-toplevel - from apispec import APISpec - from apispec.ext.marshmallow import MarshmallowPlugin - from falcon_apispec import FalconPlugin - - status = Status() - trust_list = TrustListResource("scheme", config.run_with_wsgi) - scheme_claim = SchemeClaimResource(config.run_with_wsgi) - view_zone = ViewZone() - - api = ApiApplication(config) - - spec = APISpec( - title='Zone Manager swagger', - version='1.0.0', - openapi_version='2.0', - plugins=[ - FalconPlugin(api), - MarshmallowPlugin(), - ], - ) - - spec.components.schema('StatusResponse', schema=StatusSchema) - spec.components.schema('ViewZoneResponse', schema=ViewZoneResponseSchema) - spec.components.schema('SchemesResponse', schema=SchemeResponseSchema) - spec.components.schema('TrustListResponse', schema=TrustListResponseSchema) - spec.path(resource=status) - spec.path(resource=trust_list) - spec.path(resource=scheme_claim) - spec.path(resource=view_zone) - - spec_dict = spec.to_dict() - - spec_json = json.dumps(spec_dict, indent=4) - # file_path = 'openapispec.json' - - # print("printing spec...") - LOG.debug("printing spec...") - LOG.debug(spec_json) - # print(spec_json) - # print(spec_dict) - - return spec_json - def entry_point(): LOG.debug("------- ZONE MANAGER SERVICE STARTED --------")