Revert "Revert "Removing deprecated/unused/outdated code""
[osm/RO.git] / RO / osm_ro / wim / wan_link_actions.py
diff --git a/RO/osm_ro/wim/wan_link_actions.py b/RO/osm_ro/wim/wan_link_actions.py
deleted file mode 100644 (file)
index febbc31..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-# -*- coding: utf-8 -*-
-##
-# Copyright 2018 University of Bristol - High Performance Networks Research
-# Group
-# All Rights Reserved.
-#
-# Contributors: Anderson Bravalheri, Dimitrios Gkounis, Abubakar Siddique
-# Muqaddas, Navdeep Uniyal, Reza Nejabati and Dimitra Simeonidou
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# For those usages not covered by the Apache License, Version 2.0 please
-# contact with: <highperformance-networks@bristol.ac.uk>
-#
-# Neither the name of the University of Bristol nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# This work has been performed in the context of DCMS UK 5G Testbeds
-# & Trials Programme and in the framework of the Metro-Haul project -
-# funded by the European Commission under Grant number 761727 through the
-# Horizon 2020 and 5G-PPP programmes.
-##
-# pylint: disable=E1101,E0203,W0201
-import json
-from pprint import pformat
-# from sys import exc_info
-from time import time
-
-from ..utils import filter_dict_keys as filter_keys
-from ..utils import merge_dicts, remove_none_items, safe_get, truncate
-from .actions import CreateAction, DeleteAction, FindAction
-from .errors import (
-    InconsistentState,
-    NoRecordFound,
-    NoExternalPortFound
-)
-from osm_ro_plugin.sdnconn import SdnConnectorError
-
-INSTANCE_NET_STATUS_ERROR = ('DOWN', 'ERROR', 'VIM_ERROR',
-                             'DELETED', 'SCHEDULED_DELETION')
-INSTANCE_NET_STATUS_PENDING = ('BUILD', 'INACTIVE', 'SCHEDULED_CREATION')
-INSTANCE_VM_STATUS_ERROR = ('ERROR', 'VIM_ERROR',
-                            'DELETED', 'SCHEDULED_DELETION')
-
-
-class RefreshMixin(object):
-    def refresh(self, connector, persistence):
-        """Ask the external WAN Infrastructure Manager system for updates on
-        the status of the task.
-
-        Arguments:
-            connector: object with API for accessing the WAN
-                Infrastructure Manager system
-            persistence: abstraction layer for the database
-        """
-        fields = ('sdn_status', 'sdn_info', 'error_msg')
-        result = dict.fromkeys(fields)
-
-        try:
-            result.update(
-                connector
-                .get_connectivity_service_status(self.wim_internal_id))
-        except SdnConnectorError as ex:
-            self.logger.exception(ex)
-            result.update(sdn_status='WIM_ERROR', error_msg=truncate(ex))
-
-        result = filter_keys(result, fields)
-
-        action_changes = remove_none_items({
-            'extra': merge_dicts(self.extra, result),
-            'status': 'BUILD' if result['sdn_status'] == 'BUILD' else None,
-            'error_msg': result['error_msg'],
-            'modified_at': time()})
-        link_changes = merge_dicts(result, status=result.pop('sdn_status'))
-        # ^  Rename field: sdn_status => status
-
-        persistence.update_wan_link(self.item_id,
-                                    remove_none_items(link_changes))
-
-        self.save(persistence, **action_changes)
-
-        return result
-
-
-class WanLinkCreate(RefreshMixin, CreateAction):
-    def fail(self, persistence, reason, status='FAILED'):
-        changes = {'status': 'ERROR', 'error_msg': truncate(reason)}
-        persistence.update_wan_link(self.item_id, changes)
-        return super(WanLinkCreate, self).fail(persistence, reason, status)
-
-    def process(self, connector, persistence, ovim):
-        """Process the current task.
-        First we check if all the dependencies are ready,
-        then we call ``execute`` to actually execute the action.
-
-        Arguments:
-            connector: object with API for accessing the WAN
-                Infrastructure Manager system
-            persistence: abstraction layer for the database
-            ovim: instance of openvim, abstraction layer that enable
-                SDN-related operations
-        """
-        wan_link = persistence.get_by_uuid('instance_wim_nets', self.item_id)
-
-        # First we check if all the dependencies are solved
-        instance_nets = persistence.get_instance_nets(
-            wan_link['instance_scenario_id'], wan_link['sce_net_id'])
-
-        try:
-            dependency_statuses = [n['status'] for n in instance_nets]
-        except KeyError:
-            self.logger.debug('`status` not found in\n\n%s\n\n',
-                              json.dumps(instance_nets, indent=4))
-        errored = [instance_nets[i]
-                   for i, status in enumerate(dependency_statuses)
-                   if status in INSTANCE_NET_STATUS_ERROR]
-        if errored:
-            return self.fail(
-                persistence,
-                'Impossible to stablish WAN connectivity due to an issue '
-                'with the local networks:\n\t' +
-                '\n\t'.join('{uuid}: {status}'.format(**n) for n in errored))
-
-        pending = [instance_nets[i]
-                   for i, status in enumerate(dependency_statuses)
-                   if status in INSTANCE_NET_STATUS_PENDING]
-        if pending:
-            return self.defer(
-                persistence,
-                'Still waiting for the local networks to be active:\n\t' +
-                '\n\t'.join('{uuid}: {status}'.format(**n) for n in pending))
-
-        return self.execute(connector, persistence, ovim, instance_nets)
-
-    def _get_connection_point_info(self, persistence, ovim, instance_net):
-        """Retrieve information about the connection PoP <> WAN
-
-        Arguments:
-            persistence: object that encapsulates persistence logic
-                (e.g. db connection)
-            ovim: object that encapsulates network management logic (openvim)
-            instance_net: record with the information about a local network
-                (inside a VIM). This network will be connected via a WAN link
-                to a different network in a distinct VIM.
-                This method is used to trace what would be the way this network
-                can be accessed from the outside world.
-
-        Returns:
-            dict: Record representing the wan_port_mapping associated to the
-                  given instance_net. The expected fields are:
-                  **wim_id**, **datacenter_id**, **device_id** (the local
-                  network is expected to be connected at this switch dpid),
-                  **device_interface_id**, **service_endpoint_id**,
-                  **service_mapping_info**.
-        """
-        # First, we need to find a route from the datacenter to the outside
-        # world. For that, we can use the rules given in the datacenter
-        # configuration:
-        datacenter_id = instance_net['datacenter_id']
-        datacenter = persistence.get_datacenter_by(datacenter_id)
-        rules = safe_get(datacenter, 'config.external_connections', {}) or {}
-        vim_info = instance_net.get('vim_info', {}) or {}
-        # Alternatively, we can look for it, using the SDN assist
-        external_port = (self._evaluate_rules(rules, vim_info) or
-                         self._get_port_sdn(ovim, instance_net))
-
-        if not external_port:
-            raise NoExternalPortFound(instance_net)
-
-        # Then, we find the WAN switch that is connected to this external port
-        try:
-            wim_account = persistence.get_wim_account_by(
-                uuid=self.wim_account_id)
-
-            criteria = {
-                'wim_id': wim_account['wim_id'],
-                'device_id': external_port[0],
-                'device_interface_id': external_port[1],
-                'datacenter_id': datacenter_id}
-
-            wan_port_mapping = persistence.query_one(
-                FROM='wim_port_mappings',
-                WHERE=criteria)
-        except NoRecordFound as e:
-            ex = InconsistentState('No WIM port mapping found:'
-                                   'wim_account: {}\ncriteria:\n{}'.format(
-                                       self.wim_account_id, pformat(criteria)))
-            raise ex from e
-
-        # It is important to return encapsulation information if present
-        mapping = merge_dicts(
-            wan_port_mapping.get('service_mapping_info'),
-            filter_keys(vim_info, ('encapsulation_type', 'encapsulation_id'))
-        )
-
-        return merge_dicts(wan_port_mapping, service_mapping_info=mapping)
-
-    def _get_port_sdn(self, ovim, instance_net):
-        try:
-            local_port_mapping = ovim.get_ports(instance_net['sdn_net_id'])
-
-            if local_port_mapping:
-                return (local_port_mapping[0]['switch_dpid'],
-                        local_port_mapping[0]['switch_port'])
-        except:  # noqa
-            self.logger.exception('Problems when calling OpenVIM')
-
-        self.logger.debug("No ports found for sdn_net_id='{}'", instance_net['sdn_net_id'])
-        return None
-
-    def _evaluate_rules(self, rules, vim_info):
-        """Given a ``vim_info`` dict from a ``instance_net`` record, evaluate
-        the set of rules provided during the VIM/datacenter registration to
-        determine an external port used to connect that VIM/datacenter to
-        other ones where different parts of the NS will be instantiated.
-
-        For example, considering a VIM/datacenter is registered like the
-        following::
-
-            vim_record = {
-              "uuid": ...
-              ...  # Other properties associated with the VIM/datacenter
-              "config": {
-                ...  # Other configuration
-                "external_connections": [
-                  {
-                    "condition": {
-                      "provider:physical_network": "provider_net1",
-                      ...  # This method will look up all the keys listed here
-                           # in the instance_nets.vim_info dict and compare the
-                           # values. When all the values match, the associated
-                           # vim_external_port will be selected.
-                    },
-                    "vim_external_port": {"switch": "switchA", "port": "portB"}
-                  },
-                  ...  # The user can provide as many rules as needed, however
-                       # only the first one to match will be applied.
-                ]
-              }
-            }
-
-        When an ``instance_net`` record is instantiated in that datacenter with
-        the following information::
-
-            instance_net = {
-              "uuid": ...
-              ...
-              "vim_info": {
-                ...
-                "provider_physical_network": "provider_net1",
-              }
-            }
-
-        Then, ``switchA`` and ``portB`` will be used to stablish the WAN
-        connection.
-
-        Arguments:
-            rules (list): Set of dicts containing the keys ``condition`` and
-                ``vim_external_port``. This list should be extracted from
-                ``vim['config']['external_connections']`` (as stored in the
-                database).
-            vim_info (dict): Information given by the VIM Connector, against
-               which the rules will be evaluated.
-
-        Returns:
-            tuple: switch id (local datacenter switch) and port or None if
-                the rule does not match.
-        """
-        rule = next((r for r in rules if self._evaluate_rule(r, vim_info)), {})
-        if 'vim_external_port' not in rule:
-            self.logger.debug('No external port found.\n'
-                              'rules:\n%r\nvim_info:\n%r\n\n', rules, vim_info)
-            return None
-
-        return (rule['vim_external_port']['switch'],
-                rule['vim_external_port']['port'])
-
-    @staticmethod
-    def _evaluate_rule(rule, vim_info):
-        """Evaluate the conditions from a single rule to ``vim_info`` and
-        determine if the rule should be applicable or not.
-
-        Please check :obj:`~._evaluate_rules` for more information.
-
-        Arguments:
-            rule (dict): Data structure containing the keys ``condition`` and
-                ``vim_external_port``. This should be one of the elements in
-                ``vim['config']['external_connections']`` (as stored in the
-                database).
-            vim_info (dict): Information given by the VIM Connector, against
-               which the rules will be evaluated.
-
-        Returns:
-            True or False: If all the conditions are met.
-        """
-        condition = rule.get('condition', {}) or {}
-        return all(safe_get(vim_info, k) == v for k, v in condition.items())
-
-    @staticmethod
-    def _derive_connection_point(wan_info):
-        point = {'service_endpoint_id': wan_info['service_endpoint_id']}
-        # TODO: Cover other scenarios, e.g. VXLAN.
-        details = wan_info.get('service_mapping_info', {})
-        if details.get('encapsulation_type') == 'vlan':
-            point['service_endpoint_encapsulation_type'] = 'dot1q'
-            point['service_endpoint_encapsulation_info'] = {
-                'vlan': details['encapsulation_id'],
-                'switch_dpid': wan_info['switch_dpid'],
-                'switch_port': wan_info['switch_port']
-            }
-        else:
-            point['service_endpoint_encapsulation_type'] = 'none'
-        return point
-
-    @staticmethod
-    def _derive_service_type(connection_points):
-        # TODO: add multipoint and L3 connectivity.
-        if len(connection_points) == 2:
-            return 'ELINE'
-        else:
-            # added to support DPB WIM connector
-            return 'ELAN'
-
-    def _update_persistent_data(self, persistence, service_uuid, conn_info):
-        """Store plugin/connector specific information in the database"""
-        persistence.update_wan_link(self.item_id, {
-            'wim_internal_id': service_uuid,
-            'sdn_info': {'conn_info': conn_info},
-            'status': 'BUILD'})
-
-    def execute(self, connector, persistence, ovim, instance_nets):
-        """Actually execute the action, since now we are sure all the
-        dependencies are solved
-        """
-        try:
-            wan_info = (self._get_connection_point_info(persistence, ovim, net)
-                        for net in instance_nets)
-            connection_points = [self._derive_connection_point(w)
-                                 for w in wan_info]
-
-            uuid, info = connector.create_connectivity_service(
-                self._derive_service_type(connection_points),
-                connection_points
-                # TODO: other properties, e.g. bandwidth
-            )
-        except (SdnConnectorError, InconsistentState,
-                NoExternalPortFound) as ex:
-            self.logger.exception(ex)
-            return self.fail(
-                persistence,
-                'Impossible to stablish WAN connectivity.\n\t{}'.format(ex))
-
-        self.logger.debug('WAN connectivity established %s\n%s\n',
-                          uuid, json.dumps(info, indent=4))
-        self.wim_internal_id = uuid
-        self._update_persistent_data(persistence, uuid, info)
-        self.succeed(persistence)
-        return uuid
-
-
-class WanLinkDelete(DeleteAction):
-    def succeed(self, persistence):
-        try:
-            persistence.update_wan_link(self.item_id, {'status': 'DELETED'})
-        except NoRecordFound:
-            self.logger.debug('%s(%s) record already deleted',
-                              self.item, self.item_id)
-
-        return super(WanLinkDelete, self).succeed(persistence)
-
-    def get_wan_link(self, persistence):
-        """Retrieve information about the wan_link
-
-        It might be cached, or arrive from the database
-        """
-        if self.extra.get('wan_link'):
-            # First try a cached version of the data
-            return self.extra['wan_link']
-
-        return persistence.get_by_uuid(
-            'instance_wim_nets', self.item_id)
-
-    def process(self, connector, persistence, ovim):
-        """Delete a WAN link previously created"""
-        wan_link = self.get_wan_link(persistence)
-        if 'ERROR' in (wan_link.get('status') or ''):
-            return self.fail(
-                persistence,
-                'Impossible to delete WAN connectivity, '
-                'it was never successfully established:'
-                '\n\t{}'.format(wan_link['error_msg']))
-
-        internal_id = wan_link.get('wim_internal_id') or self.internal_id
-
-        if not internal_id:
-            self.logger.debug('No wim_internal_id found in\n%s\n%s\n'
-                              'Assuming no network was created yet, '
-                              'so no network have to be deleted.',
-                              json.dumps(wan_link, indent=4),
-                              json.dumps(self.as_dict(), indent=4))
-            return self.succeed(persistence)
-
-        try:
-            id = self.wim_internal_id
-            conn_info = safe_get(wan_link, 'sdn_info.conn_info')
-            self.logger.debug('Connection Service %s (wan_link: %s):\n%s\n',
-                              id, wan_link['uuid'],
-                              json.dumps(conn_info, indent=4))
-            result = connector.delete_connectivity_service(id, conn_info)
-        except (SdnConnectorError, InconsistentState) as ex:
-            self.logger.exception(ex)
-            return self.fail(
-                persistence,
-                'Impossible to delete WAN connectivity.\n\t{}'.format(ex))
-
-        self.logger.debug('WAN connectivity removed %s', result)
-        self.succeed(persistence)
-
-        return result
-
-
-class WanLinkFind(RefreshMixin, FindAction):
-    pass
-
-
-ACTIONS = {
-    'CREATE': WanLinkCreate,
-    'DELETE': WanLinkDelete,
-    'FIND': WanLinkFind,
-}