openapi: 3.0.0
info:
  version: 'v.0.1.22'
  title: 'Luna Serving'
  description: |
     'Luna Serving'

components:
  headers:
    application_json:
      schema:
        type: string
        enum:
        - application/json
      required: true
      description: The content type of the response body.

    luna_request_id:
      schema:
        type: string
        format: timestamp,uuid
        example: 1536751345,8b8b5937-2e9c-4e8b-a7a7-5caf86621b5a
        pattern: ^[0-9]{10},[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$
      description: request id. Helps to uniquely identify messages that correspond to particular requests, in system logs.
      required: true

    docs_content_type:
      schema:
        type: string
        enum:
          - application/x-yaml
          - text/html
      required: true
      description: The content type of the response body.

    text_html:
      schema:
        type: string
        enum:
          - text/html
      required: true
      description: The content type of the response body.

    config_accept_content_type:
      schema:
        type: string
        enum:
          - application/json
          - text/plain
      required: false
      description: The content type of the response body.
  parameters:
    luna_request_id:
      in: header
      schema:
        type: string
        format: timestamp,uuid
        example: 1536751345,8b8b5937-2e9c-4e8b-a7a7-5caf86621b5a
        pattern: ^[0-9]{10},[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$
      description: |
        external request id. Helps to uniquely identify messages that correspond to particular requests, in system logs.
        If it was not set, system will set it in default format ("timestamp,UUID"). It will be returned with response.
      name: Luna-Request-Id

    accept_docs_handler:
      in: header
      name: Accept
      schema:
        $ref: '#/components/schemas/accept_docs_handler'
      required: true
      description: acceptable type of receiving data

    Accept:
      in: header
      name: Accept
      schema:
        type: string
        enum:
          - application/json
      description: Preferred response content type

    accept_config_handler:
      in: header
      name: Accept
      schema:
        type: string
        enum:
          - application/json
          - text/plain
        description: One of application/json, text/plain
      required: false
      description: acceptable type of receiving data

    include_luna_services:
      in: query
      name: include_luna_services
      schema:
        type: integer
        enum: [0, 1]
        default: 0
      description: Whether to perform healthchecks for dependent luna services.

    page:
      in: query
      name: page
      schema:
        type: integer
        minimum: 1
        default: 1
      description: Page number.

    page_size:
      in: query
      name: page_size
      schema:
        type: integer
        minimum: 1
        maximum: 1000
        default: 10
      description: Number of items on page.

    luna_account_id_header_required:
      in: header
      schema:
        $ref: '#/components/schemas/account_id'
      description: Account ID.
      name: Luna-Account-Id
      required: true

    account_id:
      in: query
      schema:
        $ref: '#/components/schemas/account_id'
      name: account_id
      description: Account ID.
      example: '8950722f-3fd4-4223-b48f-03f95f0e8dfb'

    applicationJsonContent:
      in: header
      name: Content-Type
      schema:
        type: string
        enum:
          - application/json
      description: Content type is `application/json`.

    create_time__lt:
      in: query
      name: create_time__lt
      schema:
        $ref: '#/components/schemas/time'
      description: Entity create time upper excluding bound filter in RFC 3339 format. Only entities with the creation time lower than the specified boundary will be returned in the response.
      example: "2021-09-21T19:11:41.674Z"

    create_time__gte:
      in: query
      name: create_time__gte
      schema:
        $ref: '#/components/schemas/time'
      description: Entity create time lower including bound filter in RFC 3339 format. Only entities with the creation time greater than or equal to the specified boundary will be returned in the response.
      example: "2021-09-21T11:11:41.674Z"

    service_names:
      in: query
      name: service_names
      schema:
        type: array
        items:
          $ref: '#/components/schemas/service_name'
      explode: false
      description: Service name filter.
      example: 'name1,name2'

    path_service_name:
      in: path
      name: service_name
      schema:
        $ref: '#/components/schemas/service_name'
      required: true
      description: Name of the service.

    targets:
      in: query
      name: targets
      description: |
              Comma-separated list of service target fields. 
              Available targets: account_id, service_name, description, addresses, create_time, shared, healthcheck, health
      schema:
        type: string
        default: "account_id,service_name,description,addresses,create_time,shared,healthcheck,health"
      example: service_name,shared

    shared:
      in: query
      name: shared
      description: Shared service filter. Shared services are available for all users.
      schema:
        type: integer
        minimum: 0
        maximum: 1
        description: Shared service means that any user can access service.
  schemas:
    error:
      type: object
      properties:
        error_code:
          type: integer
          description: Error code.
        desc:
          type: string
          description: Short error description.
        detail:
          type: string
          description: Error details.
        link:
          type: string
          description: Link to the documentation website with the error description.
      required: [error_code, detail, desc, link]
      example:
        error_code: 1
        detail: internal server error
        desc: internal server error
        link: "https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-1"

    int_version:
      type: integer
      minimum: 0

    accept_docs_handler:
      type: string
      enum:
        - application/x-yaml
        - text/html
      description: One of application/x-yaml, text/html.

    version:
      type: object
      properties:
        Version:
          type: object
          properties:
            api:
              allOf:
                - $ref: '#/components/schemas/int_version'
              description: An api version of service.
            major:
              allOf:
                - $ref: '#/components/schemas/int_version'
              description: A major version of service.
            minor:
              allOf:
                - $ref: '#/components/schemas/int_version'
              description: A minor version of service.
            patch:
              allOf:
                - $ref: '#/components/schemas/int_version'
              description: A patch version of service.
          required: [ api, major, minor, patch ]
      required: [ Version ]

      example:
        Version:
          api: 1
          major: 0
          minor: 0
          patch: 0

    plugin_status:
      type: object
      properties:
        name:
          type: string
          description: Plugin name
        running:
          allOf:
            - $ref: '#/components/schemas/int01'
            - description: Whether plugin is running or not.
      required: [name, running]

    plugins:
      type: object
      properties:
        plugins:
          description: List of imported plugins.
          type: array
          items:
            $ref: '#/components/schemas/plugin_status'
      required: [plugins]
      example:
        plugins:
          - name: foo
            running: 1

    health_ok:
      description: Successful healthcheck execution info.
      type: object
      properties:
        execution_time:
          type: number
          example: 0.123
          description: Request execution time in seconds.
      required: [ execution_time ]

    health_errors:
      type: object
      properties:
        errors:
          description: Failed healthcheck execution info.
          type: array
          items:
            type: object
            properties:
              component:
                description: Component name.
                type: string
              error:
                allOf:
                  - description: Healthcheck error.
                  - $ref: '#/components/schemas/error'
              status:
                description: Component health status.
                type: integer
                enum: [ 0, 1 ]
            required: [ component, error, status ]
      required: [ errors ]
      example:
        errors:
          - component: licenses
            error:
              error_code: 38001
              desc: Health check error
              detail: License error
              link: https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-38001
            status: 0

    int01:
      type: integer
      enum: [0,1]

    number01:
      type: number
      minimum: 0
      maximum: 1

    uuid:
      type: string
      format: uuid
      pattern: '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'
      example: "557d54ec-29ad-4f3c-93b4-c9092ef12515"

    time:
      type: string
      format: date-time
      example: "2018-08-11T09:11:41Z"
      description: Time in format RFC 3339.

    account_id:
      allOf:
        - $ref: '#/components/schemas/uuid'
      description: Account ID for authentication in the product.

    service_id:
      allOf:
        - $ref: '#/components/schemas/uuid'
      description: Service ID.

    service_name:
      type: string
      minLength: 3
      maxLength: 128
      pattern: ^[a-zA-Z0-9_-]*$
      description: Unique user service name.
      example: "sanic_service1"

    label:
      type: string
      maxLength: 36
      example: good_service

    address:
      type: string
      format: uri
      example: http://127.0.0.1:8000
      description: Service origin.

    service_labels:
      type: array
      items:
        $ref: '#/components/schemas/label'
      description: List of service labels.

    service_description:
      type: string
      maxLength: 512
      default: ""
      description: Service description.
      example: Greate service.

    service_shared:
      type: integer
      minimum: 0
      maximum: 1
      default: 0
      description: Shared service means that any user can access service.

    service_labels_nullable:
      allOf:
        - $ref: '#/components/schemas/service_labels'
        - nullable: true

    service_addresses:
      type: array
      items:
        $ref: '#/components/schemas/address'
      minItems: 1
      description: lists of urls for service
    
    healthcheck:
      type: object
      description: |
        Service healthcheck parameters. 

        For a service to be considered alive, a request to `route` must return a response with status code `2xx` or `3xx`
      properties:
        healthcheck:
          allOf:
            - $ref: '#/components/schemas/int01'
            - default: 0
            - description: Whether to enable or disable service healthcheck 
        route:
          type: string
          maxLength: 256
          description: Path to healthcheck handler
          default: /healthcheck
        interval:
          type: integer
          minimum: 1
          description: Healthcheck interval
          default: 10
        timeout:
          type: integer
          minimum: 1
          description: Healthcheck timeout
          default: 3

    service_create:
      type: object
      properties:
        service_name:
          $ref: '#/components/schemas/service_name'
        addresses:
          $ref: '#/components/schemas/service_addresses'
        description:
          $ref: '#/components/schemas/service_description'
        shared:
          $ref: '#/components/schemas/service_shared'
        healthcheck:
          $ref: '#/components/schemas/healthcheck'
      required: [ service_name, addresses ]

    create_time:
      allOf:
        - $ref: '#/components/schemas/time'
      description: Stream create time.

    service_create_response:
      type: object
      properties:
        service_id:
          $ref: '#/components/schemas/service_id'
        service_name:
          $ref: '#/components/schemas/service_name'
      required: [ service_id, service_name ]
    
    health:
      type: object
      description: Health statuts for each instance of a service
      additionalProperties:
        type: string
        description: |
          `up` - service instance is healthy 

          `down` - service instance is down

          `unavailable` - service status is currently not available

          `disabled` - service health checks is disabled
        enum: 
          - "up"
          - "down"
          - "unavaliable"
          - "disabled"

    service_response:
      type: object
      properties:
        service_name:
          $ref: '#/components/schemas/service_name'
        description:
          $ref: '#/components/schemas/service_description'
        account_id:
          $ref: '#/components/schemas/account_id'
        create_time:
          $ref: '#/components/schemas/create_time'
        addresses:
          $ref: '#/components/schemas/service_addresses'
        shared:
          $ref: '#/components/schemas/service_shared'
        healthcheck:
          allOf:
            - $ref: '#/components/schemas/healthcheck'
            - required: [ healthcheck, interval, route, timeout ]
        health:
          $ref: '#/components/schemas/health'

    service_response_required:
      allOf:
        - $ref: '#/components/schemas/service_response'
        - required: [service_name, description, account_id, create_time, addresses, shared, healthcheck, health]

    services_list_response:
        type: array
        items:
          $ref: '#/components/schemas/service_response'
        description: List of services
        minItems: 0

    traefik_config_response:
      type: object
      properties:
        http:
          type: object
          required: [ routers, services, middlewares ]
          properties:
            routers:
              type: object
              additionalProperties: true
            services:
              type: object
              additionalProperties: true
            middlewares:
              type: object
              additionalProperties: true
      required: [ http ]
      example:
        http:
          routers:
            service1:
              rule: PathPrefix(`/service1`)
              entryPoints:
                - web
              service: service1
              middlewares:
                - stripFirstSegment
          services:
            service1:
              loadBalancer:
                servers:
                  - url: http://127.0.0.1:8000
          middlewares:
            stripFirstSegment:
              replacePathRegex:
                regex: ^/[^/]+/(.*)
                replacement: /$1
  responses:
    internal_server_error:
      description: internal server error.
      headers:
        Content-Type:
          $ref: '#/components/headers/application_json'
        Luna-Request-Id:
          $ref: '#/components/headers/luna_request_id'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error'

    service_already_exists_by_name:
      description: service with specified name already exists.
      headers:
        Content-Type:
          $ref: '#/components/headers/application_json'
        Luna-Request-Id:
          $ref: '#/components/headers/luna_request_id'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error'
          example:
            error_code: 52002
            desc: Unique constraint error
            detail: 'Serive with name good_service already exists'
            link: "https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-52002"
paths:
  /version:
    get:
      tags:
      - version

      summary: get version
      description: get service version
      operationId: getVersion

      parameters:
      - $ref: '#/components/parameters/luna_request_id'
      responses:
        200:
          description: OK
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/version'
        500:
          $ref: '#/components/responses/internal_server_error'
  /1/docs/spec:
    get:
      tags:
        - documents
      summary: get openapi documentation
      description: |
        Get service OpenApi documentation. If *Accept* request header is of type `application/x-yaml`,
        returns documentation in `yaml` format or returns `html` documentation, if *Accept-Type* is `text/html`
      operationId: getSpec

      parameters:
        - $ref: '#/components/parameters/luna_request_id'
        - $ref: '#/components/parameters/accept_docs_handler'
      responses:
        200:
          description: OK
          headers:
            Content-Type:
              $ref: '#/components/headers/docs_content_type'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/x-yaml:
              schema:
                type: string
                description: yaml format documentation
            text/html:
              schema:
                type: string
                description: html format documentation
        415:
          description: Unsupported Media Type
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error'
              examples:
                unsupported_media_type:
                  value:
                    error_code: 12024
                    detail: 'Bad/incomplete input data'
                    desc: "Unsupported media type"
                    link: "https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-12024"
        500:
          $ref: '#/components/responses/internal_server_error'
  /1/docs/dev:
    parameters:
      - $ref: '#/components/parameters/Accept'
    get:
      tags:
        - documents
      summary: get development manual
      description: |
        Get sphinx documentation - *Development Manual*. After the request you will be redirected to the page `/docs/dev/index.html`
      operationId: getDevManual

      parameters:
        - $ref: '#/components/parameters/luna_request_id'
      responses:
        200:
          description: OK
          headers:
            Content-Type:
              $ref: '#/components/headers/text_html'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            text/html:
              schema:
                type: string
                description: html format documentation
        500:
          $ref: '#/components/responses/internal_server_error'
  /1/config:
    get:
      tags:
        - config
      summary: get service configuration
      description: Get service configuration. Passwords and tokens will be hidden in the response.
      operationId: getConfig

      parameters:
        - $ref: '#/components/parameters/luna_request_id'
        - $ref: '#/components/parameters/accept_config_handler'
      responses:
        200:
          description: OK
          headers:
            Content-Type:
              $ref: '#/components/headers/config_accept_content_type'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                type: object
                description: json format configuration
              example:
                INFLUX_MONITORING:
                  SEND_DATA_FOR_MONITORING: 0
                  ORGANIZATION: ORGANIZATION_NAME
                  TOKEN: '********'
                  BUCKET: luna_monitoring
                  HOST: 127.0.0.1
                  PORT: 8086
                  USE_SSL: 0
                  FLUSHING_PERIOD: 1.0
            text/plain:
              schema:
                type: string
                description: text format configuration
              example: |
                [INFLUX_MONITORING]
                SEND_DATA_FOR_MONITORING = 0
                ORGANIZATION = ORGANIZATION_NAME
                TOKEN = ********
                BUCKET = luna_monitoring
                HOST = 127.0.0.1
                PORT = 8086
                USE_SSL = 0
                FLUSHING_PERIOD = 1.0
        415:
          description: Unsupported Media Type
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error'
              examples:
                unsupported_media_type:
                  value:
                    error_code: 12024
                    detail: 'Bad/incomplete input data'
                    desc: "Unsupported media type"
                    link: "https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-12024"
        500:
          $ref: '#/components/responses/internal_server_error'
  /1/service:
    parameters:
      - $ref: '#/components/parameters/luna_request_id'

    post:
      tags:
        - service
      summary: create service
      description: Create service.
      operationId: createService
      parameters:
        - $ref: '#/components/parameters/applicationJsonContent'
        - $ref: '#/components/parameters/luna_account_id_header_required'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/service_create'
        required: true
      responses:
        201:
          description: Create success.
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'

          content:
            application/json:
              schema:
                $ref: '#/components/schemas/service_create_response'
        400:
          description: Bad request.
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error'
              examples:
                bad_json:
                  value:
                    error_code: 12022
                    desc: Bad/incomplete input data
                    detail: |
                      Failed to validate input json. Path: 'extra',  message: 'Extra inputs are not permitted'
                    link: https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-12022
        409:
          $ref: '#/components/responses/service_already_exists_by_name'
        500:
          $ref: '#/components/responses/internal_server_error'

    get:
      tags:
        - service
      summary: get services
      description: Get service list.
      operationId: getServices
      parameters:
        - $ref: '#/components/parameters/account_id'
        - $ref: '#/components/parameters/service_names'
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/page_size'
        - $ref: '#/components/parameters/create_time__gte'
        - $ref: '#/components/parameters/create_time__lt'
        - $ref: '#/components/parameters/targets'
        - $ref: '#/components/parameters/shared'
      responses:
        200:
          description: OK.
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                type: object
                properties:
                  services:
                    $ref: '#/components/schemas/services_list_response'
                required: [ services ]
        400:
          description: Bad request.
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error'
              examples:
                bad_query:
                  value:
                    error_code: 12012
                    desc: Bad/incomplete input data
                    detail: Bad query parameters 'page_size'
                    link: https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-12012
        500:
          $ref: '#/components/responses/internal_server_error'





  /1/service/{service_name}:
    parameters:
      - $ref: '#/components/parameters/luna_request_id'
      - $ref: '#/components/parameters/path_service_name'

    get:
      tags:
        - service
      summary: get service
      description: Get service by name.
      operationId: getService
      parameters:
        - $ref: '#/components/parameters/account_id'
      responses:
        200:
          description: OK.
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/service_response_required'
        404:
          description: Service not found.
          headers:
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
            Content-Type:
              $ref: '#/components/headers/application_json'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error'
              example:
                error_code: 52001
                desc: Object not found
                detail: Service with name `nonexists` not found
                link: https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-52001
        500:
          $ref: '#/components/responses/internal_server_error'

    delete:
      tags:
        - service
      summary: delete service
      description: delete service.
      operationId: deleteService
      responses:
        204:
          description: Delete success.
          headers:
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
        404:
          description: Service not found.
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error'
              example:
                error_code: 52001
                desc: Object not found
                detail: Service with name `nonexists` not found
                link: "https://127.0.0.1:5320/info/luna/troubleshooting/errors-description/code-52001"
        500:
          $ref: '#/components/responses/internal_server_error'
  /traefik_config:
    get:
      x-badges:
        - name: 'Internal'
          color: '#c40404'
      tags:
        - traefik
      summary: get Traefik config
      description: |
        **Warning: only for Traefik use**
        
        Get JSON Traefik configuration
      operationId: getTraefikConfig
      responses:
        200:
          description: Ok.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/traefik_config_response'
        500:
          $ref: '#/components/responses/internal_server_error'
  /1/plugins:
    get:
      tags:
        - plugins
      summary: get list of plugins
      description: |
        Get list of service plugins
      operationId: getPlugins
      parameters:
        - $ref: '#/components/parameters/luna_request_id'
      responses:
        200:
          description: OK.
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/plugins'
        500:
          $ref: '#/components/responses/internal_server_error'
  /healthcheck:
    get:
      tags:
      - health
      summary: get health
      description: get health of service
      operationId: healthcheck
      parameters:
        - $ref: '#/components/parameters/luna_request_id'
        - $ref: '#/components/parameters/include_luna_services'
      responses:
        200:
          description: OK
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/health_ok'
        500:
          $ref: '#/components/responses/internal_server_error'
        502:
          description: Unhealthy
          headers:
            Content-Type:
              $ref: '#/components/headers/application_json'
            Luna-Request-Id:
              $ref: '#/components/headers/luna_request_id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/health_errors'
