$schema: 'http://support.riverbed.com/apis/service_def/2.2'
id: 'http://support.riverbed.com/apis/sh.appflow/2.0'
provider: 'riverbed'
name: sh.appflow
version: "2.0"
title: "REST API for the AppFlow service. Includes Applications, Profiles, Rules, Topology"
defaultAuthorization: "required"

###############################################################################
#
# Types
#
###############################################################################

types:
    identifier:
        description: "Generic numeric identifier"
        type: integer
        # 64-bit unsigned integer, starting at 1
        minimum: 1
        maximum: 18446744073709551615
        readOnly: true

    application_identifier:
        description: "Application numeric identifier"
        type: integer
        minimum: 1
        maximum: 65535

    empty_collection:
        description: "Empty collection used to partially clear a collection"
        anyOf:
            - type: array
              maxItems: 0
              items:
                  type: 'null'
            # XXX: this is needed as a temporary workaround for a sleepwalker
            #      bug that prevents passing an empty array. So we pass an array with
            #      just an element that is the empty string.
            - type: array
              maxItems: 1
              minItems: 1
              items:
                  type: string
                  maxLength: 0

    name:
        description: "Generic name field, only alphanumeric '-' and '_' allowed"
        type: string
        pattern: '^[a-zA-Z0-9_-]+$'
        minLength: 3
        maxLength: 30

    unrestricted_name:
        description: "Generic name field, all characters allowed except for leading and trailing whitespace"
        type: string
        pattern: '^(\S.*)?\S$'
        minLength: 1
        maxLength: 255

    percentage:
        description: "Percentage type"
        type: number
        minimum: 0
        maximum: 100

    dscp_mark:
        description: "For 6-bit DSCP fields. Used to match the DSCP of packets \
                      coming from the wire, and for path-selection probes DSCP."
        type: integer
        minimum: 0
        maximum: 63

    dscp_ps_special:
        description: "Special values for path-selection DSCP behavior"
        type: integer
        minimum: 255
        maximum: 255

    dscp_class_special:
        description: "Special values for class DSCP behavior"
        type: integer
        minimum: 255
        maximum: 255

    dscp_qos_special:
        description: "Special values for QoS DSCP behavior"
        type: integer
        minimum: 254
        maximum: 255

    dscp_ps_rule:
        description: "For extended DSCP fields. Used for the DSCP passed to    \
                      the data-path. It assumes values from 0 to 63 and      \
                      values to trigger some extra actions on DSCP:             \
                         * 255 to `preserve` the DSCP from innner  \
                           to outer channel and the other way around."
        anyOf:
            - $ref: '#/types/dscp_mark'
            - $ref: '#/types/dscp_ps_special'

    dscp_qos_rule:
        description: "For extended DSCP fields. Used for the DSCP passed to    \
                      the data-path. It assumes values from 0 to 63 and      \
                      values to trigger some extra actions on DSCP:             \
                         * 255 to `preserve` the DSCP from innner  \
                           to outer channel and the other way around."
        anyOf:
            - $ref: '#/types/dscp_mark'
            - $ref: '#/types/dscp_qos_special'

    dscp_class:
        description: "For extended DSCP fields. Used for the DSCP passed to    \
                      the data-path. It assumes values from 0 to 63 and      \
                      values to trigger some extra actions on DSCP:             \
                         * 255 to `preserve` the DSCP from innner  \
                           to outer channel and the other way around."
        anyOf:
            - $ref: '#/types/dscp_mark'
            - $ref: '#/types/dscp_class_special'

    ipv4address:
        description: "IPv4 address (x.y.z.k)"
        type: string
        pattern: '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
        minLength: 7
        maxLength: 15

    ipv4prefix:
        description: "IPv4 prefix (x.y.z.k/mask)"
        type: string
        pattern: '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/(3[012]|[12]?[0-9]))$'
        minLength: 9
        maxLength: 18

    vlan:
        description: "Type for VLAN field in the Ethernet header"
        type: integer
        minimum: 0
        maximum: 4094

    peer_availability:
        description: "Remote peer availability
                        * up - responding to pings
                        * down - Used to be up, now not responding
                        * never - Never responded
                        * unknown - Never tried to ping "
        type: string
        enum: [ 'down', 'up', 'never', 'unknown']

    uplink_status:
        description: "Uplink status based on remote peers availability
                       * healthy - all the remote peer are `up` or `never`
                       * warning - some of the remote peers are `down`
                       * critical - all of the remote peers are `down` or `never`"
        type: string
        enum: [ 'healthy', 'warning', 'critical']

    classes_tree:
        description: "Class hierarchy tree type"
        type: object
        properties:
            id:
               $merge:
                   source: { $ref: '#/types/identifier' }
                   with: { description: "Class ID" }
            name:
               $merge:
                   source: { $ref: '#/types/unrestricted_name' }
                   with: { description: "Class Name" }
            is_default_class:
               type: boolean
               description: >
                   Is this class the default class in the tree?
            children:
               type: array
               items:
                   $ref: "#/types/classes_tree"
        additionalProperties: false

###############################################################################
#
# Define the REST API
#
###############################################################################

resources:
###############################################################################
# /reset resource
###############################################################################
    reset:
        description: >
            Reset all appflow configuration back to the factory 
            default
        type: 'null'

        links:
            self:
                path: '$/reset'
            set:
                method: POST

###############################################################################
# /dpi_info resource
###############################################################################
    dpi_info:
        description: >
            Holds information about the DPI library that identifies 
            Layer 7 protocols and built-in Applications in this version of the 
            API.
        type: object
        readOnly: true
        additionalProperties: false
        properties:
            version:
                description: >
                    The DPI version number. Incremented every time 
                    the DPI library is updated.
                type: string
                readOnly: true
        
        links:
            self:
                path: '$/dpi_info'
            get:
                method: GET
                response:
                    $ref: '#/resources/dpi_info'

###############################################################################
# /business_criticalities resource
###############################################################################
    business_criticalities:
        description: "List of Business Criticalities. Business Criticality is \
                      one of the required properties of an Application and \
                      represents the business importance of an Application. \
                      This is a static list that cannot be modified."
        type: array
        items:
            type: object
            readOnly: true
            additionalProperties: false
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with:
                            description: "Business Criticality ID"
                            readOnly: true
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with:
                            description: "Business Criticality"
                            readOnly: true

        links:
            self:
                path: "$/business_criticalities"

                #Allow filtering by name
                params:
                    name:
                        $ref: '#/types/unrestricted_name'

            get:
                method: GET
                response:
                    $ref: '#/resources/business_criticalities'


###############################################################################
# /categories resource
###############################################################################
    categories:
        description: "List of Categories. Category is one of the required \
                      properties of an Application and represents the general \
                      function of an Application. This is a static list that \
                      cannot be modified."
        type: array
        items:
            type: object
            readOnly: true
            additionalProperties: false
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with:
                            description: "Category ID"
                            readOnly: true
                name:
                    $merge:
                        source: { $ref: '#/types/name' }
                        with:
                            description: "Category"
                            readOnly: true

        links:
            self:
                path: "$/categories"

                #Allow filtering by name
                params:
                    name:
                        $ref: '#/types/unrestricted_name'

            get:
                method: GET
                response:
                    $ref: '#/resources/categories'


###############################################################################
# /traffic_types resource
###############################################################################
    traffic_types:
        description: "List of Traffic Types"
        type: array
        items:
            type: object
            additionalProperties: false
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { description: "Traffic Type ID" }
                name:
                    $merge:
                        source: { $ref: '#/types/name' }
                        with: { description: "Traffic Type" }

        links:
            self:
                path: "$/traffic_types"

                #Allow filtering by name
                params:
                    name:
                        $ref: '#/types/name'

            get:
                method: GET
                response:
                    $ref: '#/resources/traffic_types'


###############################################################################
# /securitylevels resource
###############################################################################
    securitylevels:
        description: "List of Security Levels"
        type: array
        items:
            type: object
            additionalProperties: false
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { description: "Security Level ID" }
                name:
                    $merge:
                        source: { $ref: '#/types/name' }
                        with: { description: "Security Level Name" }

        links:
            self:
                path: "$/securitylevels"
                params:
                    name:
                        $ref: '#/types/name'

            get:
                method: GET
                response:
                    $ref: '#/resources/securitylevels'

###############################################################################
# /networks and /networks/items/{id} resources
###############################################################################
    networks:
        description: "List of Networks"
        type: array
        items:
            $ref: '#/resources/network'

        links:
            self:
                path: "$/networks"
                params:
                    name:
                        $ref: '#/types/unrestricted_name'
                    parent_id:
                        $ref: '#/types/identifier'
                    virtual:
                        type: boolean
                    is_default:
                        type: boolean

            create:
                method: POST
                request:
                    $ref: '#/resources/network'
                response:
                    $ref: '#/resources/network'

            set:
                method: PUT
                request:
                    $ref: '#/types/empty_collection'

            get:
                method: GET
                response:
                    $ref: '#/resources/networks'

    network:
        description: "Network object"
        type: object
        additionalProperties: false
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Network ID" }
            name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { description: "Network Name" }
            seclevel_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Network Security Level ID" }
            seclevel_name:
                $merge:
                    source: { $ref: '#/types/name' }
                    with:
                        description: "Network Security Level Name"
                        readOnly: true
            parent_id:
                description: "The parent physical network for a virtual network. A virtual network uses a higher security level than the associated physical network"
                anyOf:
                    - $ref: '#/types/identifier'
                    - type: "null"
                readOnly: true
            is_public:
                description: "Is the network public or private?"
                type: boolean
            is_default:
                description: "Is this the default network?"
                type: boolean
                readOnly: true
        required: [name, seclevel_id]
        relations:
            instances:
                resource: '#/resources/networks'
            uplinks:
                resource: '#/resources/uplinks'
                vars:
                    network_id: "0/id"
            parent:
                resource: '#/resources/network'
                vars:
                    id: '0/parent_id'
            child:
                resource: '#/resources/networks'
                vars:
                    parent_id: '0/id'
            seclevel:
                resource: '#/resources/securitylevels'
                vars:
                    id: '0/seclevel_id'
            # TODO: move this back to networks items when Bug 161666 is fixed
            full:
                resource: '#/resources/network'
                vars:
                    id: "0/id"

        links:
            self:
                path: "$/networks/items/{id}"

            get:
                method: GET
                response:
                    $ref: '#/resources/network'

            set:
                method: PUT
                request:
                    $ref: '#/resources/network'
                response:
                    $ref: '#/resources/network'

            delete:
                method: DELETE


###############################################################################
# /sitetags and /sitetags/items/{id} resources
###############################################################################
    sitetags:
        description: "List of Site Tags"
        type: array
        items:
            $ref: '#/resources/sitetag'

        links:
            self:
                path: "$/sitetags"
                params:
                    name:
                        $ref: '#/types/name'
                    is_built_in:
                        type: boolean

            get:
                method: GET
                response:
                    $ref: '#/resources/sitetags'
            create:
                method: POST
                request:
                    $ref: '#/resources/sitetag'
                response:
                    $ref: '#/resources/sitetag'
            set:
                method: PUT
                request:
                    $ref: '#/types/empty_collection'

    sitetag:
        description: "A Site Tag Resource"
        type: object
        properties:
            id:
                $ref: '#/types/identifier'
            name:
                $ref: '#/types/name'
            is_built_in:
                description: >
                             A flag that specifies whether the tag is built in
                             and therefore cannot be deleted.
                type: boolean
                readOnly: true
            sites:
                description: "List of sites tagged with this tag"
                type: array
                items:
                    type: object
                    properties:
                        id:
                            $ref: '#/types/identifier'
                        name:
                            $ref: '#/types/name'
                    additionalProperties: false
                    relations:
                        full:
                            resource: '#/resources/site'
                            vars:
                                id: "0/id"
                readOnly: true
        additionalProperties: false
        required: [name]

        relations:
            instances:
                resource: '#/resources/sitetags'
            # TODO: move this back to sitetags items when Bug 161666 is fixed
            full:
                resource: '#/resources/sitetag'
                vars:
                    id: "0/id"

        links:
            self:
                path: '$/sitetags/items/{id}'

            get:
                method: GET
                response:
                    $ref: '#/resources/sitetag'

            set:
                method: PUT
                request:
                    $ref: '#/resources/sitetag'
                response:
                    $ref: '#/resources/sitetag'

            delete:
                method: DELETE

###############################################################################
# /sites and /sites/items/{id} resources
###############################################################################
    sites:
        description: "List of Sites"
        type: array
        items:
            $ref: '#/resources/site'

        links:
            self:
                path: "$/sites"
                params:
                    name:
                        $ref: '#/types/unrestricted_name'
                    is_local:
                        type: boolean
                        readOnly: true
                    is_default:
                        type: boolean
                        readOnly: true
                    ob_qos_profile_id:
                        $ref: '#/types/identifier'
                    ib_qos_profile_id:
                        $ref: '#/types/identifier'

            create:
                method: POST
                request:
                    $ref: '#/resources/site'
                response:
                    $ref: '#/resources/site'

            set:
                method: PUT
                request:
                    $ref: '#/types/empty_collection'

            get:
                method: GET
                response:
                    $ref: '#/resources/sites'

    site:
        description: "Site object"
        type: object
        additionalProperties: false
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Site ID" }
            name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { description: "Site Name" }
            is_local:
                description: "Is the site local or remote?"
                type: boolean
            is_default:
                description: "Is this the default site?"
                type: boolean
                readOnly: true
            tags:
                type: array
                items:
                    type: object
                    properties:
                        id:
                            $ref: '#/types/identifier'
                        name:
                            $merge:
                                source: { $ref: '#/types/unrestricted_name' }
                                with: { readOnly: true }
                        is_built_in:
                            type: boolean
                            readOnly: true
                    additionalProperties: false
                    required: [id]
                    relations:
                        full:
                            resource: '#/resources/sitetag'
                            vars:
                                id: "0/id"
            ob_qos_profile_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Outbound QoS profile ID" }
            ob_qos_profile:
                description: "Outbound QoS profile name"
                type: string
                readOnly: true
            ib_qos_profile_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Inbound QoS profile ID" }
            ib_qos_profile:
                description: "Inbound QoS profile name"
                type: string
                readOnly: true

        required: [name, is_local]
        relations:
            instances:
                resource: '#/resources/sites'
            areas:
                resource: '#/resources/areas'
                vars:
                    site_id: "0/id"
            uplinks:
                resource: '#/resources/uplinks'
                vars:
                    site_id: "0/id"
            ob_qos_profile:
                resource: '#/resources/qos_profile'
                vars:
                    id: '0/ob_qos_profile_id'
            ib_qos_profile:
                resource: '#/resources/qos_profile'
                vars:
                    id: '0/ib_qos_profile_id'
            # TODO: move this back to sites items when Bug 161666 is fixed
            full:
                resource: '#/resources/site'
                vars:
                    id: "0/id"

        links:
            self:
                path: "$/sites/items/{id}"

            get:
                method: GET
                response:
                    $ref: '#/resources/site'

            set:
                method: PUT
                request:
                    $ref: '#/resources/site'
                response:
                    $ref: '#/resources/site'

            delete:
                method: DELETE



###############################################################################
# /areas and /areas/items/{id} resources
###############################################################################
    areas:
        description: "List of Areas"
        type: array
        items:
            $ref: '#/resources/area'

        links:
            self:
                path: "$/areas"
                params:
                    site_id:
                        $ref: '#/types/identifier'
                    display_id:
                        $ref: '#/types/identifier'
                    is_default:
                        type: boolean
                        readOnly: true
            create:
                method: POST
                request:
                    $ref: '#/resources/area'
                response:
                    $ref: '#/resources/area'
            get:
                method: GET
                response:
                    $ref: '#/resources/areas'
            set:
                method: PUT
                request:
                    $ref: '#/types/empty_collection'

    area:
        description: "Area Object, i.e., subnets rechability for peers."
        type: object
        additionalProperties: false
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Area ID" }
            site_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Reference to the Site" }
            site_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "Site Name"
                        readOnly: true
            display_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Display ID. Auto-incrementing, and unique within the site" }
            is_default:
                description: "Is the default area ?"
                type: boolean
                readOnly: true
            peers:
                description: "List of Peers"
                type: array
                items:
                    $ref: '#/types/ipv4address'
            subnets:
                description: "List of Subnets"
                type: array
                items:
                    $ref: '#/types/ipv4prefix'
        required: [site_id, peers, subnets]
        relations:
            site:
                resource: '#/resources/site'
                vars:
                    id: "0/site_id"
            # TODO: move this back to areas items when Bug 161666 is fixed
            full:
                resource: '#/resources/area'
                vars:
                    id: "0/id"

        links:
            self:
                path: "$/areas/items/{id}"
                params:
                    is_default:
                        type: boolean
            get:
                method: GET
                response:
                    $ref: '#/resources/area'
            set:
                method: PUT
                request:
                    $ref: '#/resources/area'
                response:
                    $ref: '#/resources/area'
            delete:
                method: DELETE


###############################################################################
# /uplinks and /uplinks/items/{id} resources
###############################################################################
    uplinks:
        description: "List of Uplinks"
        type: array
        items:
            type: object
            additionalProperties: false
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { description: "Uplink ID" }
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { description: "Uplink Name" }
                site_id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { description: "Reference to the Site" }
                network_id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { description: "Reference to the Network" }
                parent_id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with:
                            description: "The parent physical uplink for a virtual uplink"
                            readOnly: true
                is_default:
                    description: "Is this a default uplink?"
                    type: boolean
                    readOnly: true
                is_ps_capable:
                    description: "Is this a path-selection capable uplink?"
                    type: boolean
                    readOnly: true
                interface:
                    description: "Steelhead Interface identifier"
                    type: string
            relations:
                full:
                    resource: '#/resources/uplink'
                    vars:
                        id: "0/id"
                child:
                    resource: '#/resources/uplinks'
                    vars:
                        parent_id: '0/id'
                path_rules:
                    resource: '#/resources/path_rules'
                    vars:
                        uplink_id: '0/id'

        links:
            self:
                path: "$/uplinks"
                params:
                    name:
                        $ref: '#/types/unrestricted_name'
                    network_id:
                        $ref: '#/types/identifier'
                    site_id:
                        $ref: '#/types/identifier'
                    parent_id:
                        $ref: '#/types/identifier'
                    virtual:
                        type: boolean
                    is_default:
                        type: boolean
                    is_ps_capable:
                        type: boolean

            create:
                method: POST
                request:
                    $ref: '#/resources/uplink'
                response:
                    $ref: '#/resources/uplink'

            set:
                method: PUT
                request:
                    $ref: '#/types/empty_collection'

            get:
                method: GET
                response:
                    $ref: '#/resources/uplinks'

    uplink:
        description: "Uplink object"
        type: object
        additionalProperties: false
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Uplink ID" }
            name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { description: "Uplink Name" }
            site_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Reference to the Site" }
            site_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "Site Name"
                        readOnly: true
            network_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Reference to the Network" }
            network_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "Network Name"
                        readOnly: true
            gateway_ip:
                $merge:
                    source: { $ref: '#/types/ipv4address' }
                    with: { description: "IP address of the Gateway" }
            interface:
                description: "Steelhead Interface identifier"
                type: string
            bandwidth_up:
                description: "Upload Bandwidth, in kbps"
                type: integer
                minimum: 1
                maximum: 4294967295
            bandwidth_down:
                description: "Download Bandwidth, in kbps"
                type: integer
                minimum: 1
                maximum: 4294967295
            is_firewalled:
                description: "Indicates whether the SteelHead accessing this uplink is behind a firewall."
                type: boolean
            is_public:
                description: "Indicates whether the uplink network is using public addressing."
                type: boolean
                readOnly: true
            parent_id:
                description: "The parent physical uplink for a virtual uplink. A virtual uplink uses a higher security level than the associated physical uplink."
                anyOf:
                    - $ref: '#/types/identifier'
                    - type: "null"
                readOnly: true
            probe_dscp:
                $merge:
                    source: { $ref: '#/types/dscp_mark' }
                    with: { description: "DSCP marking for path probe packets" }
            probe_timeout:
                description: "Timeout in seconds, for path probe packets"
                type: integer
                minimum: 1
                maximum: 65535
            probe_threshold:
                description: "Number of probes to detect a path as UP/DOWN"
                type: integer
                minimum: 1
                maximum: 65535
            seclevel_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Uplink Security level. Inherited from Network." }
            is_default:
                description: "Is this a default uplink?"
                type: boolean
                readOnly: true
            is_ps_capable:
                description: "Is this a path-selection capable uplink?"
                type: boolean
                readOnly: true

        required: [name, site_id, network_id, bandwidth_up, bandwidth_down]

        relations:
            instances:
                resource: '#/resources/uplinks'
            network:
                resource: '#/resources/network'
                vars:
                    id: '0/network_id'
            site:
                resource: '#/resources/site'
                vars:
                    id: '0/site_id'
            parent:
                resource: '#/resources/uplink'
                vars:
                    id: '0/parent_id'
            child:
                resource: '#/resources/uplinks'
                vars:
                    parent_id: '0/id'
            seclevel:
                resource: '#/resources/securitylevels'
                vars:
                    id: '0/seclevel_id'
            path_rules:
                resource: '#/resources/path_rules'
                vars:
                    uplink_id: '0/id'

        links:
            self:
                path: "$/uplinks/items/{id}"

            get:
                method: GET
                response:
                    $ref: '#/resources/uplink'

            set:
                method: PUT
                request:
                    $ref: '#/resources/uplink'
                response:
                    $ref: '#/resources/uplink'

            delete:
                method: DELETE


#-------------------------------------------------------------------------------
# REST API for Path-selection (PS) Rule
#-------------------------------------------------------------------------------

    path_rules:
        description: "List of Path-Selection Rules"
        type: array
        items:
            type: object
            additionalProperties: false
            properties:
                id:
                    $ref: '#/types/identifier'
                site_name:
                    $ref: '#/types/unrestricted_name'
                app_name:
                    $ref: '#/types/unrestricted_name'
                position:
                    type: integer
            required: [id, position]
            relations:
                full:
                    resource: '#/resources/path_rule'
                    vars: {id: "0/id"}

        links:
            self:
                path: "$/path_rules"
                params:
                    # allow filering by the following fields
                    site_id:
                        type: integer
                    app_id:
                        $ref: '#/types/application_identifier'
                    apptag_id:
                        type: integer
                    uplink_id:
                        type: integer
                    is_default:
                        type: boolean

            create:
                method: POST
                request:
                    $ref: '#/resources/path_rule'
                response:
                    $ref: '#/resources/path_rule'

            get:
                method: GET
                response:
                    $ref: '#/resources/path_rules'

            set:
                description: "Updates the positions of the path-selection rules."
                method: PUT
                request:
                    $ref: '#/resources/path_rules'
                response:
                    $ref: '#/resources/path_rules'

            clear:
                description: "Deletes all the path-selection rule instances."
                path: "$/path_rules/clear"
                method: POST

    path_rule:
        description: "Path-Selection Rule Object"
        type: object
        additionalProperties: false
        properties:
            id:
                $ref: '#/types/identifier'
            site_id:
                description: "Site ID. Either Site ID or SiteTag ID can be specified, but not both."
                anyOf:
                    - type: integer
                    - type: "null"
            site_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "Site Name"
                        readOnly: true
            sitetag_id:
                description: "SiteTag ID. Either Site ID or SiteTag ID can be specified, but not both."
                anyOf:
                    - type: integer
                    - type: "null"
            app_id:
                description: "Application ID. Either Application ID or ApplicationTag ID can be specified, but not both."
                anyOf:
                    - $ref: '#/types/application_identifier'
                    - type: "null"
            app_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "Application Name"
                        readOnly: true
            apptag_id:
                description: "ApplicationTag ID. Either Application ID or ApplicationTag ID can be specified, but not both."
                anyOf:
                    - type: integer
                    - type: "null"
            apptag_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "ApplicationTag Name"
                        readOnly: true
            uplinks:
                description: "Uplinks specified for the rule"
                type: array
                items:
                    type: object
                    properties:
                        uplink_id:
                            anyOf:
                                - type: integer
                                - type: "null"
                        uplink_dscp:
                            anyOf:
                                - $ref: '#/types/dscp_ps_rule'
                                - type: "null"

            default_action_id:
                type: integer
            is_default:
                description: "Is the path-selection rule a default rule?"
                type: boolean
                readOnly: true
            position:
                description: "Position of the path-selection rule"
                type: integer
                readOnly: true

        relations:
            instances:
                resource: '#/resources/path_rules'
            # To be included:
            #   references to application, apptag, site, sitetag defined
            #   in other yaml files.
            #
            uplink_1:
                resource: '#/resources/uplink'
                vars:
                    id: '0/uplinks/0/uplink_id'
            uplink_2:
                resource: '#/resources/uplink'
                vars:
                    id: '0/uplinks/1/uplink_id'
            uplink_3:
                resource: '#/resources/uplink'
                vars:
                    id: '0/uplinks/2/uplink_id'
            default_action:
                resource: '#/resources/default_action'
                vars:
                    id: '0/default_action_id'
        links:
            self:
                path: "$/path_rules/items/{id}"

            get:
                method: GET
                response:
                    $ref: '#/resources/path_rule'

            set:
                method: PUT
                request:
                    $ref: '#/resources/path_rule'
                response:
                    $ref: '#/resources/path_rule'

            delete:
                method: DELETE

    default_actions:
       description: "Collection for Path Selection Default Actions [RELAY | DROP]"
       type: array
       items: { $ref: '#/resources/default_action' }
       links:
          self: { path: "$/default_actions" }
          get:
             method: GET
             response: { $ref: '#/resources/default_actions'}

    default_action:
       description: "Path Selection Default Action [RELAY | DROP]"
       type: object
       properties:
          id: { $ref: '#/types/identifier' }
          name: { type: string }
       additionalProperties: false
       required: [ name ]
       links:
          self: { path: "$/default_actions/items/{id}" }
          get:
            method: GET
            response: { $ref: '#/resources/default_action'}

#-------------------------------------------------------------------------------
# REST API for QoS Rules
#-------------------------------------------------------------------------------

    qos_rules:
        description: "List of QoS Rules"
        type: array
        items:
           type: object
           additionalProperties: false
           properties:
                id:
                    $ref: '#/types/identifier'
                app_name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                class_name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                dscp:
                    $merge:
                        source: { $ref: '#/types/dscp_qos_rule' }
                        with: { readOnly: true }
                position:
                    type: integer
                is_default:
                    type: boolean
                    readOnly: true
           required: [id, position]
           relations:
                full:
                    resource: '#/resources/qos_rule'
                    vars: {id: "0/id"}
        links:
            self:
                path: "$/qos_rules"
                params:
                    # allow filering by the following fields
                    qos_profile_id:
                        $ref: '#/types/identifier'
                    app_id:
                        $ref: '#/types/application_identifier'
                    apptag_id:
                        $ref: '#/types/identifier'
                    is_default:
                        type: boolean
            create:
                method: POST
                request:
                    $ref: '#/resources/qos_rule'
                response:
                    $ref: '#/resources/qos_rule'

            get:
                method: GET
                response:
                    $ref: '#/resources/qos_rules'

            set:
                description: "Deletes all QoS rules that are default."
                method: PUT
                request:
                    $ref: '#/types/empty_collection'

            move:
                description: "Updates the positions of the QoS rules."
                path: "$/qos_rules/move"
                method: PUT
                request:
                    $ref: '#/resources/qos_rules'
                response:
                    $ref: '#/resources/qos_rules'

    qos_rule:
        description: "Quality of Service (QoS) Rule Object"
        type: object
        additionalProperties: false
        properties:
            id:
                $ref: '#/types/identifier'
            qos_profile_id:
                description: "ID of associated class set"
                type: integer
            app_id:
                description: "Application ID. Either Application ID or ApplicationTag ID can be specified, but not both."
                anyOf:
                    - $ref: '#/types/application_identifier'
                    - type: "null"

            app_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "Application Name"
                        readOnly: true
            apptag_id:
                description: "ApplicationTag ID. Either Application ID or ApplicationTag ID can be specified, but not both."
                anyOf:
                    - type: integer
                    - type: "null"
            apptag_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "ApplicationTag Name"
                        readOnly: true
            dscp:
                $merge:
                    source: { $ref: '#/types/dscp_qos_rule' }
                    with: { description: "DSCP value to be set for QoS marking." }
            class_id:
                description: "Class ID for shaping purposes."
                anyOf:
                    - type: integer
                    - type: "null"
            class_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name'}
                    with: { readOnly: true }
            is_default:
                description: "Is the QoS rule a default rule?"
                type: boolean
                readOnly: true
            position:
                description: "Position of the QoS rule in its profile."
                type: integer
                readOnly: true

        relations:
            instances:
                resource: '#/resources/qos_rules'
            qos_profile:
                resource: '#/resources/qos_profile'
                vars:
                    id: '0/qos_profile_id'
            class:
                resource: '#/resources/class'
                vars:
                    id: '0/class_id'

        links:
            self:
                path: "$/qos_rules/items/{id}"

            get:
                method: GET
                response:
                    $ref: '#/resources/qos_rule'

            set:
                method: PUT
                request:
                    $ref: '#/resources/qos_rule'
                response:
                    $ref: '#/resources/qos_rule'

            delete:
                method: DELETE

#-------------------------------------------------------------------------------
# REST API for Applications
#-------------------------------------------------------------------------------
    groups:
        description: "List of Application Groups. Group is one of the \
                      required properties of an Application. Each Group \
                      represents one of the most common Path-Selection \
                      offload scenarios. This is a static list that cannot be \
                      modified."
        type: array
        items:
            type: object
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { readOnly: true }
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                description:
                    type: string
                    readOnly: true
            readOnly: true
            additionalProperties: false

        links:
            self:
                path: "$/groups"

                #Allow filtering by name
                params:
                    name:
                        $ref: '#/types/unrestricted_name'

            get:
                method: GET
                response:
                    $ref: '#/resources/groups'

    l4protocols:
        description: "List of Layer 4 Protocols. This is a static list that \
                      cannot be modified."
        type: array
        items:
            type: object
            properties:
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                number:
                    description: "Layer 4 protocol number"
                    type: integer
                    readOnly: true
            readOnly: true
            additionalProperties: false

        links:
            self:
                path: "$/l4protocols"

                #Allow filtering by name
                params:
                    name:
                        $ref: '#/types/name'

            get:
                method: GET
                response:
                    $ref: '#/resources/l4protocols'

    l7protocol:
        description: "Layer 7 Protocol"
        type: object
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { readOnly: true }
            name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { readOnly: true }
            description:
                type: string
                readOnly: true
            metadata_keys:
                description: >
                    List of keys associated with this Layer 7 protocol
                readOnly: true
                type: array
                items:
                    description: >
                        Name of a metadata key associated with this Layer 7 protocol
                    type: string
            priority_fields:
                description: >
                    List of priority fields associated with this Layer 7 protocol.
                    Tuples of (priority value, priority name).
                type: array
                items:
                    type: object
                    readOnly: true
                    additionalProperties: false
                    properties:
                        name:
                            $merge:
                                source: { $ref: '#/types/unrestricted_name' }
                                with: { readOnly: true }
                        priority:
                            type: integer
                            readOnly: true
        additionalProperties: false

        relations:
            instances:
                resource: '#/resources/l7protocols'

        links:
            self:
                path: "$/l7protocols/items/{id}"

            get:
                method: GET
                response:
                    $ref: '#/resources/l7protocol'

    l7protocols:
        description: "A snapshot of all the Layer 7 protocols in the system. \
                      This is a static list that cannot be modified. To get \
                      the full details of a particular Layer 7 protocol use \
                      the 'l7protocol' resource."
        type: array
        items:
            type: object
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { readOnly: true }
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                description:
                    type: string
                    readOnly: true
            readOnly: true
            additionalProperties: false

            relations:
                full:
                    resource: '#/resources/l7protocol'
                    vars:
                        id: "0/id"

        links:
            self:
                path: "$/l7protocols"
                # Allow filtering by name
                params:
                    name:
                        $ref: '#/types/name'

            get:
                method: GET
                response:
                    $ref: '#/resources/l7protocols'

    apptag:
        description: "Tag for an Application"
        type: object
        properties:
            id:
                $ref: '#/types/identifier'
            name:
                $ref: '#/types/unrestricted_name'
            is_built_in:
                description: "Flag that specifies whether this tag \
                              is built_in and cannot be deleted. True \
                              indicates that it is built_in and cannot be \
                              deleted, False indicates that it is not built_in \
                              and can be deleted."
                type: boolean
                readOnly: true
            applications:
                description: "Array of applications that have this tag \
                              associated with them. Array of tuples of \
                              (Application ID, Application Name)"
                type: array
                items:
                    type: object
                    properties:
                        id:
                            $ref: '#/types/identifier'
                        name:
                            $merge:
                                source: { $ref: '#/types/unrestricted_name' }
                                with: { readOnly: true }
                    additionalProperties: false

                    relations:
                        full:
                            resource: '#/resources/application'
                            vars:
                                id: "0/id"

        additionalProperties: false
        required: [name]

        relations:
            instances:
                resource: '#/resources/apptags'

        links:
            self:
                path: "$/app_tags/items/{id}"

            get:
                method: GET
                response:
                    $ref: '#/resources/apptag'


    apptags:
        description: "A snapshot of all the Application Tags in the system. \
                      For full details of a particular Application Tag \
                      use the 'apptag' resource. An Application Tag cannot be \
                      modified through this resource. To modify an \
                      Application Tag use the 'apptag' resource instead."
        type: array
        items:
            type: object
            properties:
                is_built_in:
                    description: "Flag that specifies whether this tag \
                                is built_in and cannot be deleted. True \
                                indicates that it is built_in and cannot be \
                                deleted, False indicates that it is not built_in \
                                and can be deleted."
                    type: boolean
                    readOnly: true
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { readOnly: true }
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
            readOnly: true
            additionalProperties: false

            relations:
                full:
                    resource: '#/resources/apptag'
                    vars:
                        id: "0/id"

        links:
            self:
                path: "$/app_tags"
                # Allow filtering by name
                params:
                    name:
                        $ref: '#/types/unrestricted_name'

            get:
                method: GET
                response:
                    $ref: '#/resources/apptags'

    application:
        description: "Definition of a QoS Application"

        type: object
        properties:
            id:
                $ref: '#/types/application_identifier'
            name:
                $ref: '#/types/unrestricted_name'
            description:
                description: "Description of the Application"
                anyOf:
                    - type: string
                    - type: "null"
            traffic_type_id:
                description: "ID of the traffic type that this Application \
                              applies to. A value of 'null' catches \
                              both Optimized and Passthrough traffic."
                anyOf:
                    - type: integer
                    - type: "null"
            traffic_type_name:
                description: "Traffic type (Optimized, Passthrough or both)
                              that this application applies to."
                anyOf:
                    - $ref: '#/types/name'
                    - type: "null"
                readOnly: true
            l4_protocol_id:
                description: "ID of Layer 4 protocol of traffic that this \
                              Application applies to. Foreign Key into the \
                              Layer 4 protocols table."
                anyOf:
                    - type: integer
                    - type: "null"
            l4_protocol_name:
                description: "Name of Layer 4 protocol of traffic that this \
                              Application applies to."
                readOnly: true
                anyOf:
                    - $ref: '#/types/unrestricted_name'
                    - type: "null"
            dscp:
                description: "DSCP of traffic that this Application applies \
                              to. A value of 'null' here catches all DSCP \
                              values."
                anyOf:
                    - $ref: '#/types/dscp_mark'
                    - type: "null"
            vlan:
                description: "VLAN of traffic that this Application applies \
                              to. A value of 'null' here catches all VLANs."
                anyOf:
                    - $ref: '#/types/vlan'
                    - type: "null"
            local_port:
                description: "Local port of traffic that this Application \
                              applies to. Only one of local_port and \
                              local_portlabel can be specified."
                anyOf:
                    - type: integer
                      minimum: 1
                      maximum: 65535
                    - type: "null"
            local_portlabel:
                description: "Name of Port Label, an alternate way of \
                              specifying the local ports of traffic that this \
                              Application applies to. Only one of local_port \
                              and local_portlabel can be specified."
                anyOf:
                    - type: string
                    - type: "null"
            remote_port:
                description: "Remote port of traffic that this Application \
                              applies to. Only one of remote_port and \
                              remote_portlabel can be specified."
                anyOf:
                    - type: integer
                      minimum: 1
                      maximum: 65535
                    - type: "null"
            remote_portlabel:
                description: "Name of Port Label, an alternate way of \
                              specifying the remote ports of traffic that this\
                              Application applies to. Only one of remote_port \
                              and remote_portlabel can be specified."
                anyOf:
                    - type: string
                    - type: "null"
            local_net:
                description: "Local subnet of traffic that this Application \
                              applies to. Only one of local_net and \
                              local_hostlabel can be specified."
                anyOf:
                    - $ref: '#/types/ipv4prefix'
                    - type: "null"
            local_hostlabel:
                description: "Name of Host Label, an alternate way of \
                              specifying the local IP addresses of traffic that this \
                              Application applies to. Only one of local_net \
                              and local_hostlabel can be specified."
                anyOf:
                    - type: string
                    - type: "null"
            remote_net:
                description: "Remote subnet of traffic that this Application \
                              applies to. Only one of remote_net and \
                              remote_hostlabel can be specified."
                anyOf:
                    - $ref: '#/types/ipv4prefix'
                    - type: "null"
            remote_hostlabel:
                description: "Name of Host Label, an alternate way of \
                              specifying the remote IP addresses of traffic that this \
                              Application applies to. Only one of remote_net \
                              and remote_hostlabel can be specified."
                anyOf:
                    - type: string
                    - type: "null"
            l7_protocol_id:
                description: "ID of Layer 7 protocol of traffic that this \
                              Application applies to. Foreign Key into the \
                              Layer 7 protocols table"
                anyOf:
                    - type: integer
                    - type: "null"
            l7_protocol_name:
                description: "Name of Layer 7 protocol of traffic that this \
                              Application applies to."
                readOnly: true
                anyOf:
                    - $ref: '#/types/unrestricted_name'
                    - type: "null"
            l7_protocol_params:
                description: "List of parameters specific to the Layer 7 \
                              protocol of this Application"
                type: array
                items:
                    type: object
                    properties:
                        name:
                            description: "Name of the Layer 7 protocol-metadata field"
                            type: string
                        value:
                            description: "Value of the Layer 7 protocol-metadata field"
                            type: string
                    additionalProperties: false
            tags:
                $merge:
                    source: { $ref: '#/resources/apptags' }
                    with: { readOnly: true }
            group_id:
                type: integer
            group_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { readOnly: true }
            business_criticality_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with:
                        description: "ID of the Business Criticality property of this \
                                      Application. Foreign Key into the \
                                      Business_criticalities resource."
            business_criticality_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "Name of the Business Criticality property of \
                                      this Application. Represents the Application's \
                                      business importance."
                        readOnly: true
            category_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with:
                        description: "ID of the Category property of this \
                                      Application. Foreign Key into the \
                                      Categories resource."
            category_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with:
                        description: "Name of the Category property of this \
                                      Application. Represents the general function \
                                      of this Application."
                        readOnly: true
            is_built_in:
                description: "Specifies whether the Application is built_in"
                type: boolean
                readOnly: true
        required: [business_criticality_id, category_id, group_id, name]
        additionalProperties: false

        # Additional validation criteria
        allOf:
            - not:
                type: object
                required: [local_port, local_portlabel]
                properties:
                    local_port:
                        type: integer
                    local_portlabel:
                        type: string
            - not:
                type: object
                required: [remote_port, remote_portlabel]
                properties:
                    remote_port:
                        type: integer
                    remote_portlabel:
                        type: string
            - not:
                type: object
                required: [local_net, local_hostlabel]
                properties:
                    local_net:
                        $ref: '#/types/ipv4prefix'
                    local_hostlabel:
                        type: string
            - not:
                type: object
                required: [remote_net, remote_hostlabel]
                properties:
                    remote_net:
                        $ref: '#/types/ipv4prefix'
                    remote_hostlabel:
                        type: string

        relations:
            instances:
                resource: '#/resources/applications'

        links:
            self:
                path: "$/applications/items/{id}"

            get:
                method: GET
                response:
                    $ref: '#/resources/application'

            set:
                method: PUT
                request:
                    $ref: '#/resources/application'
                response:
                    $ref: '#/resources/application'

            delete:
                method: DELETE

    applications:
        description: "A snapshot of all the Applications in the system. To \
                      get the full details of a particular Application use \
                      the 'application' resource. An Application cannot be \
                      modified through this resource. To modify an \
                      Application use the 'application' resource."
        type: array
        items:
            type: object
            properties:
                business_criticality_name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                category_name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                id:
                    $merge:
                        source: { $ref: '#/types/application_identifier' }
                        with: { readOnly: true }
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                tags:
                    $merge:
                        source: { $ref: '#/resources/apptags' }
                        with: { readOnly: true }
                description:
                    type: string
                    readOnly: true
                group_name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { readOnly: true }
                is_built_in:
                    description: "Specifies whether the application is built_in."
                    type: boolean
                    readOnly: true
            readOnly: true
            additionalProperties: false

            relations:
                full:
                    resource: '#/resources/application'
                    vars:
                        id: "0/id"

        links:
            self:
                path: "$/applications"
                params:
                    # Filters
                    name:
                        $ref: '#/types/unrestricted_name'
                    is_built_in:
                        type: boolean
                    business_criticality_id:
                        $ref: '#/types/identifier'
                    category_id:
                        $ref: '#/types/identifier'
                    group_id:
                        $ref: '#/types/identifier'
                    uses_portlabel:
                        type: string
                    uses_hostlabel:
                        type: string

            get:
                method: GET
                response:
                    $ref: '#/resources/applications'

            create:
                method: POST
                request:
                    $ref: '#/resources/application'
                response:
                    $ref: '#/resources/application'

            set:
                method: PUT
                request:
                    $ref: '#/types/empty_collection'

            reset:
                path: "$/applications/reset"
                description: "Resets the list of applications back to the factory default."
                method: POST

            dump:
                method: GET
                path: "$/applications/dump"
                description: > 
                    Get the list of applications with the full details of each 
                    application specified.
                response:
                    type: array
                    items:
                        $ref: '#/resources/application'


###############################################################################
# Resources for QoS and Path Profiles
###############################################################################
    class:
        type: object
        description: "QoS Class"
        additionalProperties: false
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Class ID" }
            qos_profile_id:
                type: number
                description: "Reference to the QoS Profile"
            name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { description: "Class Name" }
            parent_id:
                type: number
                description: "Reference to the Parent Class ID"
            is_leaf:
                type: boolean
                description: "Is this class a leaf class or inner class?"
                readOnly: true
            is_default_class:
                type: boolean
                description: >
                    Is this class the default class in the QoS Profile?
                readOnly: true
        required: [ name, qos_profile_id, parent_id ]
        links:
            self:
                path: "$/classes/items/{id}"
            get:
                method: GET
                response:
                    $ref: '#/resources/class'
            set:
                method: PUT
                request:
                    $ref: '#/resources/class'
                response:
                    $ref: '#/resources/class'
            delete:
                method: DELETE

        relations:
            # The list of all classes
            instances:
                resource: '#/resources/classes'
            # Link to the class set of this class
            qos_profile:
                resource: '#/resources/qos_profile'
                vars:
                    id: "0/qos_profile_id"
            # Link to the parent-class of this class
            parent:
                resource: '#/resources/class'
                vars:
                    id: "0/parent_id"
            #
            full:
                resource: '#/resources/class'
                vars:
                    id: "0/id"


    classes:
        type: array
        description: "List of QoS Class IDs and names"
        items:
            $ref: "#/resources/class"
        links:
            self:
                path: "$/classes"
                params:
                    # Allow filtering by class name
                    name:
                        $ref: '#/types/unrestricted_name'
                    # Allow filtering by class set id
                    qos_profile_id:
                        type: number
                    is_leaf:
                        type: boolean
            set:
                description: >
                    Delete all the Class instances (except for default
                    root class in default class set).
                method: PUT
                request:
                    $ref: '#/types/empty_collection'
            get:
                method: GET
                response:
                    $ref: '#/resources/classes'
            create:
                method: POST
                request:
                    $ref: '#/resources/class'
                response:
                    $ref: '#/resources/class'

    queue_type:
        type: object
        description: "QoS Queue"
        additionalProperties: false
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Queue Type ID" }
            name:
                $merge:
                    source: { $ref: '#/types/name' }
                    with: { description: "Queue Type Name" }
        required: [ name ]
        links:
            self:
                path: "$/queue_types/items/{id}"
            get:
                method: GET
                response:
                    $ref: '#/resources/queue_type'
        relations:
            # The list of all queue_types
            instances:
                resource: '#/resources/queue_types'

    queue_types:
        type: array
        description: "List of QoS Queues"
        items:
            type: object
            additionalProperties: false
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { description: "Queue Type ID" }
                name:
                    $merge:
                        source: { $ref: '#/types/name' }
                        with: { description: "Queue Type Name" }
                shaper_name:
                    $merge:
                        source: { $ref: '#/types/name' }
                        with: { description: "Qdisc in Shaper" }
            relations:
                full:
                    resource: '#/resources/queue_type'
                    vars: { id: "0/id" }
        links:
            self:
                path: "$/queue_types"
                params:
                    # Allow filtering by queue_type name
                    name:
                        $ref: '#/types/name'
            get:
                method: GET
                response:
                    $ref: '#/resources/queue_types'
    qos_profile:
        type: object
        description: "QoS Profile"
        additionalProperties: false
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "QoS Profile ID" }
            name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { description: "QoS Profile Name" }
            classes_tree:
                $merge:
                    source: { $ref: '#/types/classes_tree' }
                    with: { readOnly: true }
            is_default:
                type: boolean
                description: >
                    Is this default QoS Profile ?
                readOnly: true
        required: [ name ]
        links:
            self:
                path: "$/qos_profiles/items/{id}"
            get:
                method: GET
                response:
                    $ref: '#/resources/qos_profile'
            set:
                method: PUT
                request:
                    $ref: '#/resources/qos_profile'
                response:
                    $ref: '#/resources/qos_profile'
            delete:
                method: DELETE
        relations:
            # The list of all class sets
            instances:
                resource: '#/resources/qos_profiles'
            full:
                resource: '#/resources/qos_profile'
                vars:
                    id: "0/id"

    qos_profiles:
        type: array
        description: "List of QoS Profile IDs and names"
        items:
            type: object
            additionalProperties: false
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { description: "QoS Profile ID" }
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { description: "QoS Profile Name" }
                is_default:
                    type: boolean
                    description: >
                        Is this default QoS Profile ?
                    readOnly: true
            relations:
                full:
                    resource: '#/resources/qos_profile'
                    vars: { id: "0/id" }
        links:
            self:
                path: "$/qos_profiles"
                params:
                    # Allow filtering by profile name
                    name:
                        $ref: '#/types/unrestricted_name'
                    is_default:
                        type: boolean

            get:
                method: GET
                response:
                    $ref: '#/resources/qos_profiles'
            set:
                description: >
                    Delete all the QoS Profile instances (except
                    for default class set)
                method: PUT
                request:
                    $ref: '#/types/empty_collection'
            create:
                method: POST
                request:
                    $ref: '#/resources/qos_profile'
                response:
                    $ref: '#/resources/qos_profile'
            reset:
                path: "$/qos_profiles/reset" 
                description: "Resets the QoS Default-Profile back to factory-default."
                method: POST

    uplink_variation:
        type: object
        description: "Uplink Variation"
        additionalProperties: false
        properties:
            id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Uplink Variation ID" }
            name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { description: "Uplink Variation Name" }
            uplink_id:
                anyOf:
                    - $ref: '#/types/identifier'
                    - type: 'null'
                description: "Reference to the Uplink"
            qos_profile_id:
                type: number
                description: "Reference to QoS Profile ID"
            class_params:
                type: array
                description: >
                    List of all QoS Class Parameters associated
                    to this Uplink Variation
                items:
                    type: object
                    description: "QoS Class Params"
                    additionalProperties: false
                    properties:
                        class_id:
                            type: number
                            description: "Reference to the QoS Class"
                        ob_queue_type_id:
                            type: number
                            description: >
                                Reference to the Queue Type of
                                an Outbound Class
                        ob_queue_length:
                            type: number
                            description: "Length of the Outbound QoS Queue"
                        ib_queue_length:
                            type: number
                            description: "Length of the Inbound QoS Queue"
                        min_bw:
                            $merge:
                                source: { $ref: '#/types/percentage' }
                                with: { description: "Minimum Bandwidth" }
                        max_bw:
                            $merge:
                                source: { $ref: '#/types/percentage' }
                                with: { description: "Maximum Bandwidth" }
                        ls_weight:
                            $merge:
                                source: { $ref: '#/types/percentage' }
                                with: { description: "HFSC link share weight" }
                        dscp:
                            $merge:
                                source: { $ref: '#/types/dscp_class' }
                                with: { description: "Default DSCP" }
                        priority:
                            type: number
                            minimum: 1
                            maximum: 6
                            description: "Latency Priority"
                        connection_limit:
                            type: number
                            description: "Maximum number of connections"
                        ib_flow_padding_enable:
                            type: boolean
                            description: >
                                Enable/disable inbound QoS Flow Padding
                                feature, default is enabled.
                        ib_flow_padding_override:
                            type: boolean
                            description: >
                                Whether or not to override the global
                                Inbound QoS Flow Padding configuration.
                        ib_flow_padding_timeout:
                            $merge:
                                source: { $ref: '#/types/percentage' }
                                with:
                                    description: >
                                        Timeout for Deque/Link-Sharing Phantoms
                                        as a percentage fraction of average TCP
                                        round-trip time.
                        ib_tcp_control_enable:
                            type: boolean
                            description: >
                                Enable/disable inbound QoS TCP Control
                                feature, default is enabled.
                        ib_tcp_control_override:
                            type: boolean
                            description: >
                                Whether or not to override the global Inbound
                                QoS TCP Control configuration.
                        ib_tcp_control_fssdetect:
                            $merge:
                                source: { $ref: '#/types/percentage' }
                                with: { description: "False slow start detection settings" }
                        ib_tcp_control_idledetect:
                            $merge:
                                source: { $ref: '#/types/percentage' }
                                with: { description: "TCP idle restart detection settings" }
                        ib_tcp_control_weight:
                            $merge:
                                source: { $ref: '#/types/percentage' }
                                with:
                                    description: >
                                        TCP Slow-Start phantom weight as a percentage
                                        fraction of the real packet
                    required: [ class_id ]
                    relations:
                        # Link to the class that this class-profile is about
                        class:
                            resource: '#/resources/class'
                            vars:
                                id: "0/class_id"
                        # Link to the queue_type that should be used by the class
                        queue_type:
                            resource: '#/resources/queue_type'
                            vars:
                                id: "0/queue_type_id"
        required: [ name, qos_profile_id, uplink_id, class_params]
        links:
            self:
                path: "$/uplink_variations/items/{id}"
            get:
                method: GET
                response:
                    $ref: '#/resources/uplink_variation'
            set:
                method: PUT
                request:
                    $ref: '#/resources/uplink_variation'
                response:
                    $ref: '#/resources/uplink_variation'
            delete:
                method: DELETE
        relations:
            # the entire list of qos profiles
            instances:
                resource: '#/resources/uplink_variations'
            qos_profile:
                resource: '#/resources/qos_profile'
                vars:
                    id: "0/qos_profile_id"

    uplink_variations:
        type: array
        description: "List of Uplink Variations"
        items:
            type: object
            additionalProperties: false
            properties:
                id:
                    $merge:
                        source: { $ref: '#/types/identifier' }
                        with: { description: "Uplink Variation ID" }
                name:
                    $merge:
                        source: { $ref: '#/types/unrestricted_name' }
                        with: { description: "Uplink Variation Name" }
            relations:
                full:
                    resource: '#/resources/uplink_variation'
                    vars:
                        id: "0/id"
        links:
            self:
                path: "$/uplink_variations"
                params:
                    # Allow filtering by uplink_variation name
                    name:
                        $ref: '#/types/unrestricted_name'
                    qos_profile_id:
                        $ref: '#/types/identifier'
                    uplink_id:
                        $ref: '#/types/identifier'
            get:
                method: GET
                response:
                    $ref: '#/resources/uplink_variations'
            set:
                method: PUT
                request:
                    $ref: '#/types/empty_collection'

    path:
        type: object
        description: "Site Uplink Combination"
        additionalProperties: false
        properties:
            site_id:
                type: number
                description: "Reference to the Site"
            uplink_id:
                type: number
                description: "Reference to the Uplink"
            estimated_ob_bw:
                type: number
                description: >
                    Estimated outbound bottleneck bandwidth of the
                    site (site_id) over the uplink (uplink_id)
                readOnly: true
            estimated_ib_bw:
                type: number
                description: >
                    Estimated inbound bottleneck bandwidth of the
                    site (site_id) over the uplink (uplink_id)
                readOnly: true
            configured_ob_bw:
                type: number
                description: >
                    Configured outbound bottleneck bandwidth of the
                    site (site_id) over the uplink (uplink_id)
            configured_ib_bw:
                type: number
                description: >
                    Configured inbound bottleneck bandwidth of the
                    site (site_id) over the uplink (uplink_id)
        links:
            self:
                path: "$/paths/items/{site_id}/{uplink_id}"
            get:
                method: GET
                response:
                    $ref: '#/resources/path'
            set:
                method: PUT
                request:
                    $ref: '#/resources/path'
                response:
                    $ref: '#/resources/path'
        relations:
            # the entire list of paths
            instances:
                resource: '#/resources/paths'
            site:
                resource: '#/resources/site'
                vars:
                    id: '0/site_id'
            uplink:
                resource: '#/resources/uplink'
                vars:
                    id: '0/uplink_id'

    paths:
        type: array
        description: "List of Path (Site Uplink Combinations)"
        items:
            $merge:
                source: { $ref: '#/resources/path' }
                with:
                    relations:
                        full:
                            resource: '#/resources/path'
                            vars:
                                site_id: "0/site_id"
                                uplink_id: "0/uplink_id"
        links:
            self:
                path: "$/paths"
                params:
                    # Allow filtering by site_id
                    site_id:
                        type: number
                    # Allow filtering by uplink_id
                    uplink_id:
                        type: number
            get:
                method: GET
                response:
                    $ref: '#/resources/paths'

    shaper_id:
        type: object
        description: "QoS Class ID in Shaper (Linux Kernel) "
        additionalProperties: false
        properties:
            site_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Reference to the Site." }
            site_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { description: "Site name" }
            class_id:
                $merge:
                    source: { $ref: '#/types/identifier' }
                    with: { description: "Reference to the Class." }
            class_name:
                $merge:
                    source: { $ref: '#/types/unrestricted_name' }
                    with: { description: "Class name" }
            direction:
                type: number
                minimum: 0
                maximum: 1
                description: Outbound - 0, Inbound - 1
            class_shaper_id:
                type: number
                minimum: 1
                maximum: 65535
                description: "QoS class ID in shaper (minor ID of a TC class)"
        required: [ site_id, class_id, class_shaper_id ]
        links:
            self:
                path: "$/shaper_ids/items/{class_shaper_id}"
            get:
                description: "Get the data representation of a class shaper ID."
                method: GET
                response:
                    $ref: '#/resources/shaper_id'
        relations:
            # The list of all class shaper ids
            instances:
                resource: '#/resources/shaper_ids'
            full:
                resource: '#/resources/shaper_id'
                vars:
                    class_shaper_id: "0/class_shaper_id"

    shaper_ids:
        type: array
        description: "List of QoS Class Shaper IDs"
        items:
            $ref: '#/resources/shaper_id'

        links:
            self:
                path: "$/shaper_ids"
                params:
                    class_shaper_id:
                        type: number
                        minimum: 1
                        maximum: 65535
                    site_id:
                        $merge:
                            source: { $ref: '#/types/identifier' }
                            with: { description: "Reference to the Site." }
                    class_id:
                        $merge:
                            source: { $ref: '#/types/identifier' }
                            with: { description: "Reference to the Class." }
                    direction:
                        type: number
                        minimum: 0
                        maximum: 1
                        description: Outbound - 0, Inbound - 1

            get:
                method: GET
                response:
                    $ref: '#/resources/shaper_ids'

#-------------------------------------------------------------------------------
# REST API for Global Configurations
#-------------------------------------------------------------------------------

    global_configs:
        description: "Global Configuration Collection"
        type: array
        items:
            $ref: '#/resources/global_config'
        links:
            self:
                path: "$/global_configs"
                params:
                    name:
                        $ref: '#/types/name'
                    value:
                        type: string
                    group:
                        $merge:
                            source: { $ref: '#/types/name' }
                            with: { description: "Global configuration group." }

            get:
                method: GET
                response: { $ref: '#/resources/global_configs'}

    global_config:
        description: "Global Configuration Item"
        type: object
        properties:
            group: { $ref: '#/types/name' }
            name: { $ref: '#/types/name' }
            value: { type: string}
        additionalProperties: false
        required: [group, name, value]
        links:
            self: { path: "$/global_configs/items/{group}/{name}" }
            get:
                method: GET
                response: { $ref: '#/resources/global_config'}
            set:
                method: PUT
                request: { $ref: '#/resources/global_config'}
                response: { $ref: '#/resources/global_config'}
        relations:
            full:
                resource: '#/resources/global_config'
                vars:
                    group: "0/group"
                    name: "0/name"


###############################################################################
# Resources for Path-Selection stats
###############################################################################
    path_stats:
        description: "Read-Only Resource for Path-Selection Statistics"
        type: object
        additionalProperties: false
        properties:
            local_site_id:
                $ref: '#/types/identifier'
            local_site_name:
                $ref: '#/types/unrestricted_name'
            uplinks:
                type: array
                items:
                    type: object
                    additionalProperties: false
                    properties:
                        uplink_id:
                            $ref: '#/types/identifier'
                        uplink_name:
                            $ref: '#/types/unrestricted_name'
                        uplink_status:
                            $ref: '#/types/uplink_status'
                        remote_sites:
                            type: array
                            items:
                                type: object
                                additionalProperties: false
                                properties:
                                    remote_site_id:
                                        $ref: '#/types/identifier'
                                    remote_site_name:
                                        $ref: '#/types/unrestricted_name'
                                    areas:
                                        type: array
                                        items:
                                            type: object
                                            additionalProperties: false
                                            properties:
                                                area_id:
                                                    $ref: '#/types/identifier'
                                                bytes_sent:
                                                    type: integer
                                                peers_availability:
                                                    type: array
                                                    items:
                                                        type: object
                                                        additionalProperties: false
                                                        properties:
                                                            peer_ip:
                                                                $ref: '#/types/ipv4address'
                                                            status:
                                                                $ref: '#/types/peer_availability'
                                                            public_ip:
                                                                $ref: '#/types/ipv4address'
                                                            port:
                                                                type: integer

        links:
            self:
                path: '$/path_stats'

                params:
                    uplink_id:
                        $ref: '#/types/identifier'
                    remote_site_id:
                        $ref: '#/types/identifier'
                    area_id:
                        $ref: '#/types/identifier'
                    peer_ip:
                        $ref: '#/types/ipv4address'

            get:
                method: GET
                response:
                    $ref: '#/resources/path_stats'

    migration_errors:
        description: "List of Errors Encountered During Migration"
        type: array
        items:
            type: string
            readOnly: true
        links:
            self:
                path: "$/migration_errors"

            get:
                method: GET
                response:
                    $ref: '#/resources/migration_errors'
            set:
                method: PUT
                request:
                    $ref: '#/types/empty_collection'
