# Path: lighthouse/configurable.py
# class Configurable(object):
#     """
#     Base class for targets configured by the config file watching system.
# 
#     Each subclass is expected to be able to validate and apply configuration
#     dictionaries that come from config file content.
#     """
# 
#     name = None
# 
#     # This attribute denotes that the config watching system should check
#     # a subdirectory for this configurable's files.
#     config_subdirectory = None
# 
#     @classmethod
#     def validate_config(cls, config):
#         """
#         Validates a given config, returns the validated config dictionary
#         if valid, raises a ValueError for any invalid values.
# 
#         Subclasses are expected to define this method.
#         """
#         raise NotImplementedError
# 
#     def apply_config(self, config):
#         """
#         Applies a given config to the subclass.
# 
#         Setting instance attributes, for example.  Subclasses are expected
#         to define this method.
# 
#         NOTE: It is *incredibly important* that this method be idempotent with
#         regards to the instance.
#         """
#         raise NotImplementedError
# 
#     @classmethod
#     def from_config(cls, name, config):
#         """
#         Returns a Configurable instance with the given name and config.
# 
#         By default this is a simple matter of calling the constructor, but
#         subclasses that are also `Pluggable` instances override this in order
#         to check that the plugin is installed correctly first.
#         """
# 
#         cls.validate_config(config)
# 
#         instance = cls()
#         if not instance.name:
#             instance.name = config.get("name", name)
#         instance.apply_config(config)
# 
#         return instance
# 
# Path: lighthouse/balancer.py
# class Balancer(Pluggable):
#     """
#     Base class for load balancer definitions.
# 
#     The complexity of generating valid configuration content and updating
#     the proper file(s) is left as details for subclasses so this base class
#     remains incredibly simple.
# 
#     All subclasses are expected to implement a `sync_file` method that is
#     called whenever an update to the topography of nodes happens.
#     """
# 
#     config_subdirectory = "balancers"
#     entry_point = "lighthouse.balancers"
# 
#     def sync_file(self, clusters):
#         """
#         This method must take a list of clusters and update any and all
#         relevant configuration files with valid config content for balancing
#         requests for the given clusters.
#         """
#         raise NotImplementedError


import logging
from .configurable import Configurable
from .balancer import Balancer

logger = logging.getLogger(__name__)


class Cluster(Configurable):
    """
    The class representing a cluster of member nodes in a service.

    A simple class that merely keeps a list of nodes and defines which
    discovery method is used to track said nodes.
    """

    config_subdirectory = "clusters"

    def __init__(self):
        self.discovery = None
        self.meta_cluster = None
        self.nodes = []

    @classmethod
    def validate_config(cls, config):
        """
        Validates a config dictionary parsed from a cluster config file.

        Checks that a discovery method is defined and that at least one of
        the balancers in the config are installed and available.
        """
        if "discovery" not in config:
            raise ValueError("No discovery method defined.")


# Path: lighthouse/configurable.py
# class Configurable(object):
#     """
#     Base class for targets configured by the config file watching system.
# 
#     Each subclass is expected to be able to validate and apply configuration
#     dictionaries that come from config file content.
#     """
# 
#     name = None
# 
#     # This attribute denotes that the config watching system should check
#     # a subdirectory for this configurable's files.
#     config_subdirectory = None
# 
#     @classmethod
#     def validate_config(cls, config):
#         """
#         Validates a given config, returns the validated config dictionary
#         if valid, raises a ValueError for any invalid values.
# 
#         Subclasses are expected to define this method.
#         """
#         raise NotImplementedError
# 
#     def apply_config(self, config):
#         """
#         Applies a given config to the subclass.
# 
#         Setting instance attributes, for example.  Subclasses are expected
#         to define this method.
# 
#         NOTE: It is *incredibly important* that this method be idempotent with
#         regards to the instance.
#         """
#         raise NotImplementedError
# 
#     @classmethod
#     def from_config(cls, name, config):
#         """
#         Returns a Configurable instance with the given name and config.
# 
#         By default this is a simple matter of calling the constructor, but
#         subclasses that are also `Pluggable` instances override this in order
#         to check that the plugin is installed correctly first.
#         """
# 
#         cls.validate_config(config)
# 
#         instance = cls()
#         if not instance.name:
#             instance.name = config.get("name", name)
#         instance.apply_config(config)
# 
#         return instance
# 
# Path: lighthouse/balancer.py
# class Balancer(Pluggable):
#     """
#     Base class for load balancer definitions.
# 
#     The complexity of generating valid configuration content and updating
#     the proper file(s) is left as details for subclasses so this base class
#     remains incredibly simple.
# 
#     All subclasses are expected to implement a `sync_file` method that is
#     called whenever an update to the topography of nodes happens.
#     """
# 
#     config_subdirectory = "balancers"
#     entry_point = "lighthouse.balancers"
# 
#     def sync_file(self, clusters):
#         """
#         This method must take a list of clusters and update any and all
#         relevant configuration files with valid config content for balancing
#         requests for the given clusters.
#         """
#         raise NotImplementedError


# Path: lighthouse/cluster.py
import logging
from .configurable import Configurable
from .balancer import Balancer


logger = logging.getLogger(__name__)


class Cluster(Configurable):
    """
    The class representing a cluster of member nodes in a service.

    A simple class that merely keeps a list of nodes and defines which
    discovery method is used to track said nodes.
    """

    config_subdirectory = "clusters"

    def __init__(self):
        self.discovery = None
        self.meta_cluster = None
        self.nodes = []

    @classmethod
    def validate_config(cls, config):
        """
        Validates a config dictionary parsed from a cluster config file.

        Checks that a discovery method is defined and that at least one of
        the balancers in the config are installed and available.
        """
        if "discovery" not in config:
            raise ValueError("No discovery method defined.")


        installed_balancers = Balancer.get_installed_classes().keys()