:EP: 37
:Title: Interruption Management
:Authors:
    - David Ramirez <davramir@fiu.edu>;
    - Vinicius Arcanjo <vindasil@fiu.edu>;
    - Jeronimo Bezerra jbezerra@fiu.edu;
:Issued Date: to be defined
:Status: Accepted
:Type: Standards Track

*******************************
EP037 - Interruption Management
*******************************

########
Abstract
########

This blueprint details a mechanism for NApps providing services
to receive information on interruptions,
and provide information on the affected services back
to the source of the interruption.
Additionally, this blueprint details how NApps which produce
interruptions should signal them in order to take advantage
of this new mechanism.

##########
Motivation
##########

In order for NApps which produce service interruptions
to receive information on what services they are affecting,
there needs to be a two way communication channel between
the service provider and the interruption source.
The kytos event bus provides only one way communication,
making it unsuitable for this task.

#############
Specification
#############

The following is a set of proposed changes for
how to handle interruptions in the future,
in order to have visibility on there causes and effects.

Kytos Core Changes
##################

In order for services to identify which interruptions are affecting the devices
they use, a mechanism needs to be added to the device representation for
identify interruption causes.


Extend ``status_funcs`` to produce a ``status_reason``
======================================================

Currently, when an object is queried about its ``status``,
the reason for that status is unknown.
What we propose here is adding a new property to
``GenericEntity`` called ``status_reason``,
and adding in ``status_reason_func``
to produce values for ``status_reason``.
The produced ``status_reason`` will be a set of strings,
so all possible reasons a device might be disable
can be easily represented.

Example usage:

.. code-block:: python3

    # Adding in status_func and status_reason_func
    from kytos.core.switch import Switch
    maintenance_switches = {'Switch-B'}

    def switch_maintenance_status(switch):
        if switch.id in maintenance_switches:
            return EntityStatus.DOWN
        return EntityStatus.UP

    Switch.register_status_func('maintenance', switch_maintenance_status)

    def switch_maintenance_reason(switch):
        if switch.id in maintenance_switches:
            return {'maintenance'}
        return set()

    Switch.register_status_reason_func('maintenance', switch_maintenance_reason)

    # Checking the status through status_reason

    switch_a = Switch('Switch-A')
    switch_b = Switch('Switch-B')

    if switch_a.status_reason:
        assert(False)

    if not switch_b.status_reason:
        assert(False)

    # Filtering out specific status reasons

    if switch_a.status_reason - {'maintenance'}:
        assert(False)

    if switch_b.status_reason - {'maintenance'}:
        assert(False)


New Kytos Events
################

The following set of event listeners are intended to be used to notify
other NApps once a change to the status of a set of devices occurs.

KytosEvent ``topology.interruptions.start``
===========================================

Notify services of an interruption starting,
after the interruption provider has already updated the status.

Expected Input:

.. code-block:: python3

    {
        "type": <interruption type str>,
        "switches": [<switch id>],
        "interfaces": [<interface id>],
        "links": [<link id>],
    }

Example Usage:

.. code-block:: python3

    # Creating events when updating status

    def start_switch_maintenance(switches: set[str]):
        affected_switches = switches - maintenance_switches
        maintenance_switches += switches
        controller.buffers.app.put(
            KytosEvent(
                name='topology.interruptions.start'
                content={
                    'type': 'maintenance',
                    'switches': affected_switches,
                }
            )
        )



KytosEvent ``topology.interruptions.end``
=========================================

Notify services of an interruption ending,
after the interruption provider has already updated the status.

.. code-block:: python3

    {
        "type": <interruption type str>,
        "switches": [<switch id>],
        "interfaces": [<interface id>],
        "links": [<link id>],
    }

Example Usage:

.. code-block:: python3

    # Creating events when updating status

    def end_switch_maintenance(switches: set[str]):
        affected_switches = switches & maintenance_switches
        maintenance_switches -= switches
        controller.buffers.app.put(
            KytosEvent(
                name='topology.interruptions.end'
                content={
                    'type': 'maintenance',
                    'switches': affected_switches,
                }
            )
        )

Notes:

- Upon the end of an interruption, services which had there best available paths interrupted should make an effort to reclaim interrupted paths.


New Topology REST Endpoints
###########################

The following set of new endpoints are intended to allow
for previewing the affects of adding in interruptions.

REST Endpoint: ``GET <url for previewing>``
======================================

Query the given service provider to
preview services affected if the specified interruption were to occur now.

Expected Input:

.. code-block:: json

    {
        "type": <interruption type str>,
        "switches": [<switch id>],
        "interfaces": [<interface id>],
        "links": [<link id>],
    }

Expected Output:

.. code-block:: json

    [
        {
            'id': <id>,
            'name': <service_name | null>,
            'owner': <str | null>,
        },
    ]

REST Endpoint ``GET /topology/v3/preview_interruption``
=======================================================

Asynchronously queries all known service providers to
preview services affected if the specified interruption were to occur now.

Expected Input:

.. code-block:: json

    {
        "type": <interruption type str>,
        "switches": [<switch id>],
        "interfaces": [<interface id>],
        "links": [<link id>],
    }


Expected Response:

.. code-block:: json

    {
        <provider name str>: [
            {
                'id': <id>,
                'name': <service_name>,
                'owner': <str | null>,
            },
        ],
    }

REST Endpoint ``GET /topology/v3/preview_interruption/<provider name str>``
======================================

Query the given service provider to
preview services affected if the specified interruption were to occur now.

Expected Input:

.. code-block:: json

    {
        "type": <interruption type str>,
        "switches": [<switch id>],
        "interfaces": [<interface id>],
        "links": [<link id>],
    }

Expected Output:

.. code-block:: json

    [
        {
            'id': <id>,
            'name': <service_name | null>,
            'owner': <str | null>,
        },
    ]

Specifying Service Providers
############################

In order to specify service providers,
a new variable will be added into ``kytos/topology``
settings called ``SERVICE_PROVIDERS``.

.. code-block:: python

    SERVICE_PROVIDERS = {
        '<service provider name>': '<url for previewing>'
    }

##############
Rejected Ideas
##############

Several different approaches had been considered during the creation of this blueprint.
Originally it was intended that a REST API would be developed for controlling
the state of interruptions in addition to querying there effects.
That version of this proposal would have also required
extending topology to manage the state of interruptions.
