<commit_before># Copyright 2015 <NAME> <<EMAIL>>
#
# 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.
"""
Contains classes relevant to the main adaptation function of the Controller
Adaptation Sublayer
"""
import importlib
import weakref

from escape import CONFIG
from escape.adapt import LAYER_NAME
from escape.infr import LAYER_NAME as INFR_LAYER_NAME
from escape.orchest.virtualization_mgmt import AbstractVirtualizer
from escape.adapt.domain_adapters import AbstractDomainAdapter
from escape.adapt import log as log
from escape.util.nffg import NFFG


class ControllerAdapter(object):
  """
  Higher-level class for :any:`NFFG` adaptation
  between multiple domains
  """
  # Default adapters
  _domains = {}

  def __init__ (self, layer_API, lazy_load=True, with_infr=False, remote=True):
    """
    Initialize Controller adapter

    For domain adapters the ControllerAdapter checks the CONFIG first
    If there is no adapter defined explicitly then initialize the default
    Adapter class stored in `_defaults`

    .. warning::
      Adapter classes must be subclass of AbstractDomainAdapter

    .. note::
      Arbitrary domain adapters is searched in
      :mod:`escape.adapt.domain_adapters`

    :param layer_API: layer API instance
    :type layer_API: :any:`ControllerAdaptationAPI`
    :param lazy_load: load adapters only at first reference (default: True)
    :type lazy_load: bool
    :param with_infr: using emulated infrastructure (default: False)
    :type with_infr: bool
    :param remote: use NETCONF RPCs or direct access (default: False)
    :type remote: bool
    """
    log.debug("Init ControllerAdapter")
    super(ControllerAdapter, self).__init__()
    # Set a weak reference to avoid circular dependencies
    self._layer_API = weakref.proxy(layer_API)
    self._lazy_load = lazy_load
    self._with_infr = with_infr
    if not lazy_load:
      # Initiate adapters from CONFIG
      self.__init_defaults()
    elif with_infr:
      # Initiate default internal adapter if needed.
      self.init_internal(remote)
    else:
      # Other adapters will be created right after the first reference to them
      # POX seems to be the only reasonable choice as a default adapter
      self._domains['POX'] = self.__load_adapter("POX")
    # Set virtualizer-related components
    self.domainResManager = DomainResourceManager()

  def __getattr__ (self, item):
    """
    Expose doamin managers with it's names as an attribute of this class

    :param item: name of the manager defined in it's class
    :type item: str
    :return: given domain manager
    :rtype: AbstractDomainAdapter
    """
    try:
      if not item.startswith('__'):
        return self._domains[item]
    except KeyError:
      if self._lazy_load:
        self._domains[item] = self.__load_adapter(item)
        return self._domains[item]
      else:
        raise AttributeError("No adapter is defined with the name: %s" % item)

  def __load_adapter (self, adapter_name, from_config=True, **kwargs):
    """
    Load given adapter.

    :param adapter_name: adapter's name
    :type adapter_name: str
    :param kwargs: adapter's initial parameters
    :type kwargs: dict
    :return: initiated adapter
    :rtype: :any:`AbstractDomainAdapter`
    """
    try:
      if from_config:
        adapter_class = getattr(
          importlib.import_module("escape.adapt.domain_adapters"),
          CONFIG[LAYER_NAME][adapter_name]['class'])
      else:
        adapter_class = getattr(
          importlib.import_module("escape.adapt.domain_adapters"), adapter_name)
      adapter = adapter_class(**kwargs)
      # Set up listeners for e.g. DomainChangedEvents
      adapter.addListeners(self)
      # Set up listeners for DeployNFFGEvent
      adapter.addListeners(self._layer_API)
      return adapter
    except KeyError as e:
      log.error(
        "Configuration of '%s' is missing. Skip initialization!" % e.args[0])
    except AttributeError:
      log.error("%s is not found. Skip adapter initialization!" %
                CONFIG[LAYER_NAME][adapter_name]['class'])

  def __init_defaults (self):
    """
    Init default adapters
    """
    # very dummy initialization
    # TODO - improve
    for name in ('POX', 'INTERNAL'):
      self._domains[name] = self.__load_adapter(name)

  def init_internal (self, remote):
    """
    Init internal domain.

    :param remote: use NETCONF RPCs or direct access (default: False)
    :type remote: bool
    :return: None
    """
    try:
      if CONFIG[INFR_LAYER_NAME]["LOADED"]:
        # Set adapters for InternalDomainManager
        # Set OpenFlow route handler
        controller = self.__load_adapter("POX",
                                         name=CONFIG[LAYER_NAME]['INTERNAL'][
                                           'listener-id'])
        # Set emulated network initiator/handler/manager
        network = self.__load_adapter("MININET")
        # Set NETCONF handling capability if needed
        remote = self.__load_adapter('VNFStarter',
                                     **CONFIG[LAYER_NAME]['VNFStarter'][
                                       'agent']) if remote else None
        # Set internal domain manager
        self._domains['INTERNAL'] = self.__load_adapter("INTERNAL",
                                                        controller=controller,
                                                        network=network,
                                                        remote=remote)
      else:
        log.error("%s layer is not loaded! Abort InternalDomainManager "
                  "initialization!" % INFR_LAYER_NAME)
    except KeyError as e:
      log.error(
        "Got KeyError during initialization of InternalDomainManager: %s", e)

  def install_nffg (self, mapped_nffg):
    """
    Start NF-FG installation

    Process given :any:`NFFG`, slice information based on domains an invoke
    domain adapters to install domain specific parts

    :param mapped_nffg: mapped NF-FG instance which need to be installed
    :type mapped_nffg: NFFG
    :return: None or internal domain NFFG part
    """
    log.debug("Invoke %s to install NF-FG" % self.__class__.__name__)
    # TODO - implement
    # TODO - no NFFG split just very dummy cycle
    if self._with_infr:
      log.debug("Delegate mapped NFFG to Internal domain manager...")
      self.internal_manager.install_nffg(mapped_nffg)
    else:
      for name, adapter in self._domains.iteritems():
        log.debug("Delegate mapped NFFG to %s domain adapter..." % name)
        adapter.install_routes(mapped_nffg)
    log.debug("NF-FG installation is finished by %s" % self.__class__.__name__)

  def _handle_DomainChangedEvent (self, event):
    """
    Handle DomainChangedEvents, process changes and store relevant information
    in DomainResourceManager
    """
    pass

  def _slice_into_domains (self, nffg):
    """
    Slice given :any:`NFFG` into separate parts

    :param nffg: mapped NFFG object
    :type nffg: NFFG
    :return: sliced parts<commit_msg>Fix InternalDomainManager reference in ControllerAdapter<commit_after># Copyright 2015 <NAME> <<EMAIL>>
#
# 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.
"""
Contains classes relevant to the main adaptation function of the Controller
Adaptation Sublayer
"""
import importlib
import weakref

from escape import CONFIG
from escape.adapt import LAYER_NAME
from escape.infr import LAYER_NAME as INFR_LAYER_NAME
from escape.orchest.virtualization_mgmt import AbstractVirtualizer
from escape.adapt.domain_adapters import AbstractDomainAdapter
from escape.adapt import log as log
from escape.util.nffg import NFFG


class ControllerAdapter(object):
  """
  Higher-level class for :any:`NFFG` adaptation
  between multiple domains
  """
  # Default adapters
  _domains = {}

  def __init__ (self, layer_API, lazy_load=True, with_infr=False, remote=True):
    """
    Initialize Controller adapter

    For domain adapters the ControllerAdapter checks the CONFIG first
    If there is no adapter defined explicitly then initialize the default
    Adapter class stored in `_defaults`

    .. warning::
      Adapter classes must be subclass of AbstractDomainAdapter

    .. note::
      Arbitrary domain adapters is searched in
      :mod:`escape.adapt.domain_adapters`

    :param layer_API: layer API instance
    :type layer_API: :any:`ControllerAdaptationAPI`
    :param lazy_load: load adapters only at first reference (default: True)
    :type lazy_load: bool
    :param with_infr: using emulated infrastructure (default: False)
    :type with_infr: bool
    :param remote: use NETCONF RPCs or direct access (default: False)
    :type remote: bool
    """
    log.debug("Init ControllerAdapter")
    super(ControllerAdapter, self).__init__()
    # Set a weak reference to avoid circular dependencies
    self._layer_API = weakref.proxy(layer_API)
    self._lazy_load = lazy_load
    self._with_infr = with_infr
    if not lazy_load:
      # Initiate adapters from CONFIG
      self.__init_defaults()
    elif with_infr:
      # Initiate default internal adapter if needed.
      self.init_internal(remote)
    else:
      # Other adapters will be created right after the first reference to them
      # POX seems to be the only reasonable choice as a default adapter
      self._domains['POX'] = self.__load_adapter("POX")
    # Set virtualizer-related components
    self.domainResManager = DomainResourceManager()

  def __getattr__ (self, item):
    """
    Expose doamin managers with it's names as an attribute of this class

    :param item: name of the manager defined in it's class
    :type item: str
    :return: given domain manager
    :rtype: AbstractDomainAdapter
    """
    try:
      if not item.startswith('__'):
        return self._domains[item]
    except KeyError:
      if self._lazy_load:
        self._domains[item] = self.__load_adapter(item)
        return self._domains[item]
      else:
        raise AttributeError("No adapter is defined with the name: %s" % item)

  def __load_adapter (self, adapter_name, from_config=True, **kwargs):
    """
    Load given adapter.

    :param adapter_name: adapter's name
    :type adapter_name: str
    :param kwargs: adapter's initial parameters
    :type kwargs: dict
    :return: initiated adapter
    :rtype: :any:`AbstractDomainAdapter`
    """
    try:
      if from_config:
        adapter_class = getattr(
          importlib.import_module("escape.adapt.domain_adapters"),
          CONFIG[LAYER_NAME][adapter_name]['class'])
      else:
        adapter_class = getattr(
          importlib.import_module("escape.adapt.domain_adapters"), adapter_name)
      adapter = adapter_class(**kwargs)
      # Set up listeners for e.g. DomainChangedEvents
      adapter.addListeners(self)
      # Set up listeners for DeployNFFGEvent
      adapter.addListeners(self._layer_API)
      return adapter
    except KeyError as e:
      log.error(
        "Configuration of '%s' is missing. Skip initialization!" % e.args[0])
    except AttributeError:
      log.error("%s is not found. Skip adapter initialization!" %
                CONFIG[LAYER_NAME][adapter_name]['class'])

  def __init_defaults (self):
    """
    Init default adapters
    """
    # very dummy initialization
    # TODO - improve
    for name in ('POX', 'INTERNAL'):
      self._domains[name] = self.__load_adapter(name)

  def init_internal (self, remote):
    """
    Init internal domain.

    :param remote: use NETCONF RPCs or direct access (default: False)
    :type remote: bool
    :return: None
    """
    try:
      if CONFIG[INFR_LAYER_NAME]["LOADED"]:
        # Set adapters for InternalDomainManager
        # Set OpenFlow route handler
        controller = self.__load_adapter("POX",
                                         name=CONFIG[LAYER_NAME]['INTERNAL'][
                                           'listener-id'])
        # Set emulated network initiator/handler/manager
        network = self.__load_adapter("MININET")
        # Set NETCONF handling capability if needed
        remote = self.__load_adapter('VNFStarter',
                                     **CONFIG[LAYER_NAME]['VNFStarter'][
                                       'agent']) if remote else None
        # Set internal domain manager
        self._domains['INTERNAL'] = self.__load_adapter("INTERNAL",
                                                        controller=controller,
                                                        network=network,
                                                        remote=remote)
      else:
        log.error("%s layer is not loaded! Abort InternalDomainManager "
                  "initialization!" % INFR_LAYER_NAME)
    except KeyError as e:
      log.error(
        "Got KeyError during initialization of InternalDomainManager: %s", e)

  def install_nffg (self, mapped_nffg):
    """
    Start NF-FG installation

    Process given :any:`NFFG`, slice information based on domains an invoke
    domain adapters to install domain specific parts

    :param mapped_nffg: mapped NF-FG instance which need to be installed
    :type mapped_nffg: NFFG
    :return: None or internal domain NFFG part
    """
    log.debug("Invoke %s to install NF-FG" % self.__class__.__name__)
    # TODO - implement
    # TODO - no NFFG split just very dummy cycle
    if self._with_infr:
      log.debug("Delegate mapped NFFG to Internal domain manager...")
      self.INTERNAL.install_nffg(mapped_nffg)
    else:
      for name, adapter in self._domains.iteritems():
        log.debug("Delegate mapped NFFG to %s domain adapter..." % name)
        adapter.install_routes(mapped_nffg)
    log.debug("NF-FG installation is finished by %s" % self.__class__.__name__)

  def _handle_DomainChangedEvent (self, event):
    """
    Handle DomainChangedEvents, process changes and store relevant information
    in DomainResourceManager
    """
    pass

  def _slice_into_domains (self, nffg):
    """
    Slice given :any:`NFFG` into separate parts

    :param nffg: mapped NFFG object
    :type nffg: NFFG
    :return: sliced parts
{'fraction_non_alphanumeric': 0.08115443172039452, 'fraction_numerical': 0.0011915006288475542, 'mean_word_length': 2.793120763243786, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2868263', 'n_tokens_mistral': 4155, 'n_tokens_neox': 4010, 'n_words': 1369}