# Path: lighthouse/haproxy/stanzas/section.py
# class Section(object):
#     """
#     Represents a section of HAProxy config file stanzas.
# 
#     This is used to organize generated config file content and provide header
#     comments for sections describing nature of the grouped-together stanzas.
#     """
# 
#     def __init__(self, heading, *stanzas):
#         self.heading = heading
#         self.stanzas = stanzas
#         if not self.stanzas:
#             self.stanzas = []
# 
#     @property
#     def header(self):
#         return "\n".join([
#             "#",
#             "# %s" % self.heading,
#             "#"
#         ])
# 
#     def __str__(self):
#         """
#         Joins together the section header and stanza strings with space
#         inbetween.
#         """
#         stanzas = list(self.stanzas)
#         if not stanzas:
#             stanzas = ["# No stanzas defined for this section."]
# 
#         return "\n\n".join(map(str, [self.header] + stanzas))
# 
# Path: lighthouse/haproxy/stanzas/meta.py
# class MetaFrontendStanza(Stanza):
#     """
#     Stanza subclass representing a shared "meta" cluster frontend.
# 
#     These frontends just contain ACL directives for routing requests to
#     separate cluster backends.  If a member cluster does not have an ACL rule
#     defined in its haproxy config an error is logged and the member cluster
#     is skipped.
#     """
# 
#     def __init__(self, name, port, lines, members, bind_address=None):
#         super(MetaFrontendStanza, self).__init__("frontend")
#         self.header = "frontend %s" % name
# 
#         if not bind_address:
#             bind_address = ""
# 
#         self.add_line("bind %s:%s" % (bind_address, port))
#         self.add_lines(lines)
# 
#         for cluster in members:
#             if "acl" not in cluster.haproxy:
#                 logger.error(
#                     "Cluster %s is part of meta-cluster %s," +
#                     " but no acl rule defined.",
#                     cluster.name, name
#                 )
#                 continue
#             self.add_lines([
#                 "acl is_%s %s" % (cluster.name, cluster.haproxy["acl"]),
#                 "use_backend %s if is_%s" % (cluster.name, cluster.name)
#             ])
# 
# Path: lighthouse/haproxy/stanzas/frontend.py
# class FrontendStanza(Stanza):
#     """
#     Stanza subclass representing a "frontend" stanza.
# 
#     A frontend stanza defines an address to bind to an a backend to route
#     traffic to.  A cluster can defined custom lines via a "frontend" entry
#     in their haproxy config dictionary.
#     """
# 
#     def __init__(self, cluster, bind_address=None):
#         super(FrontendStanza, self).__init__("frontend")
#         self.header = "frontend %s" % cluster.name
# 
#         if not bind_address:
#             bind_address = ""
# 
#         self.add_lines(cluster.haproxy.get("frontend", []))
#         self.add_line("bind %s:%s" % (bind_address, cluster.haproxy["port"]))
#         self.add_line("default_backend %s" % cluster.name)
# 
# Path: lighthouse/haproxy/stanzas/backend.py
# class BackendStanza(Stanza):
#     """
#     Stanza subclass representing a "backend" stanza.
# 
#     A backend stanza defines the nodes (or "servers") belonging to a given
#     cluster as well as how routing/load balancing between those nodes happens.
# 
#     A given cluster can define custom directives via a list of lines in their
#     haproxy config with the key "backend".
#     """
# 
#     def __init__(self, cluster):
#         super(BackendStanza, self).__init__("backend")
#         self.header = "backend %s" % cluster.name
# 
#         if not cluster.nodes:
#             logger.warning(
#                 "Cluster %s has no nodes, backend stanza may be blank.",
#                 cluster.name
#             )
# 
#         backend_lines = cluster.haproxy.get("backend", [])
#         self.add_lines(backend_lines)
#         for node in cluster.nodes:
#             http_mode = bool("mode http" in backend_lines)
#             self.add_line(
#                 "server %(name)s %(host)s:%(port)s %(cookie)s %(options)s" % {
#                     "name": node.name,
#                     "host": node.ip,
#                     "port": node.port,
#                     "cookie": "cookie " + node.name if http_mode else "",
#                     "options": cluster.haproxy.get("server_options", "")
#                 }
#             )
# 
# Path: lighthouse/haproxy/stanzas/peers.py
# class PeersStanza(Stanza):
#     """
#     Stanza subclass representing a "peers" stanza.
# 
#     This stanza lists "peer" haproxy instances in a cluster, so that each
#     instance can coordinate and share stick-table information.  Useful for
#     tracking cluster-wide stats.
#     """
# 
#     def __init__(self, cluster):
#         super(PeersStanza, self).__init__("peers")
#         self.header = "peers " + cluster.name
# 
#         self.add_lines([
#             "peer %s %s:%s" % (peer.name, peer.ip, peer.port)
#             for peer in set([node.peer for node in cluster.nodes if node.peer])
#         ])


import collections
import datetime
import logging
import six
from .stanzas.section import Section
from .stanzas.meta import MetaFrontendStanza
from .stanzas.frontend import FrontendStanza
from .stanzas.backend import BackendStanza
from .stanzas.peers import PeersStanza

    def generate(self, clusters, version=None):
        """
        Generates HAProxy config file content based on a given list of
        clusters.
        """
        now = datetime.datetime.now()

        sections = [
            Section(
                "Auto-generated by Lighthouse (%s)" % now.strftime("%c"),
                self.global_stanza,
                self.defaults_stanza
            )
        ]

        meta_stanzas = [
            MetaFrontendStanza(
                name, self.meta_clusters[name]["port"],
                self.meta_clusters[name].get("frontend", []), members,
                self.bind_address
            )
            for name, members
            in six.iteritems(self.get_meta_clusters(clusters))
        ]
        frontend_stanzas = [
            FrontendStanza(cluster, self.bind_address)
            for cluster in clusters
            if "port" in cluster.haproxy
        ]

# Path: lighthouse/haproxy/stanzas/section.py
# class Section(object):
#     """
#     Represents a section of HAProxy config file stanzas.
# 
#     This is used to organize generated config file content and provide header
#     comments for sections describing nature of the grouped-together stanzas.
#     """
# 
#     def __init__(self, heading, *stanzas):
#         self.heading = heading
#         self.stanzas = stanzas
#         if not self.stanzas:
#             self.stanzas = []
# 
#     @property
#     def header(self):
#         return "\n".join([
#             "#",
#             "# %s" % self.heading,
#             "#"
#         ])
# 
#     def __str__(self):
#         """
#         Joins together the section header and stanza strings with space
#         inbetween.
#         """
#         stanzas = list(self.stanzas)
#         if not stanzas:
#             stanzas = ["# No stanzas defined for this section."]
# 
#         return "\n\n".join(map(str, [self.header] + stanzas))
# 
# Path: lighthouse/haproxy/stanzas/meta.py
# class MetaFrontendStanza(Stanza):
#     """
#     Stanza subclass representing a shared "meta" cluster frontend.
# 
#     These frontends just contain ACL directives for routing requests to
#     separate cluster backends.  If a member cluster does not have an ACL rule
#     defined in its haproxy config an error is logged and the member cluster
#     is skipped.
#     """
# 
#     def __init__(self, name, port, lines, members, bind_address=None):
#         super(MetaFrontendStanza, self).__init__("frontend")
#         self.header = "frontend %s" % name
# 
#         if not bind_address:
#             bind_address = ""
# 
#         self.add_line("bind %s:%s" % (bind_address, port))
#         self.add_lines(lines)
# 
#         for cluster in members:
#             if "acl" not in cluster.haproxy:
#                 logger.error(
#                     "Cluster %s is part of meta-cluster %s," +
#                     " but no acl rule defined.",
#                     cluster.name, name
#                 )
#                 continue
#             self.add_lines([
#                 "acl is_%s %s" % (cluster.name, cluster.haproxy["acl"]),
#                 "use_backend %s if is_%s" % (cluster.name, cluster.name)
#             ])
# 
# Path: lighthouse/haproxy/stanzas/frontend.py
# class FrontendStanza(Stanza):
#     """
#     Stanza subclass representing a "frontend" stanza.
# 
#     A frontend stanza defines an address to bind to an a backend to route
#     traffic to.  A cluster can defined custom lines via a "frontend" entry
#     in their haproxy config dictionary.
#     """
# 
#     def __init__(self, cluster, bind_address=None):
#         super(FrontendStanza, self).__init__("frontend")
#         self.header = "frontend %s" % cluster.name
# 
#         if not bind_address:
#             bind_address = ""
# 
#         self.add_lines(cluster.haproxy.get("frontend", []))
#         self.add_line("bind %s:%s" % (bind_address, cluster.haproxy["port"]))
#         self.add_line("default_backend %s" % cluster.name)
# 
# Path: lighthouse/haproxy/stanzas/backend.py
# class BackendStanza(Stanza):
#     """
#     Stanza subclass representing a "backend" stanza.
# 
#     A backend stanza defines the nodes (or "servers") belonging to a given
#     cluster as well as how routing/load balancing between those nodes happens.
# 
#     A given cluster can define custom directives via a list of lines in their
#     haproxy config with the key "backend".
#     """
# 
#     def __init__(self, cluster):
#         super(BackendStanza, self).__init__("backend")
#         self.header = "backend %s" % cluster.name
# 
#         if not cluster.nodes:
#             logger.warning(
#                 "Cluster %s has no nodes, backend stanza may be blank.",
#                 cluster.name
#             )
# 
#         backend_lines = cluster.haproxy.get("backend", [])
#         self.add_lines(backend_lines)
#         for node in cluster.nodes:
#             http_mode = bool("mode http" in backend_lines)
#             self.add_line(
#                 "server %(name)s %(host)s:%(port)s %(cookie)s %(options)s" % {
#                     "name": node.name,
#                     "host": node.ip,
#                     "port": node.port,
#                     "cookie": "cookie " + node.name if http_mode else "",
#                     "options": cluster.haproxy.get("server_options", "")
#                 }
#             )
# 
# Path: lighthouse/haproxy/stanzas/peers.py
# class PeersStanza(Stanza):
#     """
#     Stanza subclass representing a "peers" stanza.
# 
#     This stanza lists "peer" haproxy instances in a cluster, so that each
#     instance can coordinate and share stick-table information.  Useful for
#     tracking cluster-wide stats.
#     """
# 
#     def __init__(self, cluster):
#         super(PeersStanza, self).__init__("peers")
#         self.header = "peers " + cluster.name
# 
#         self.add_lines([
#             "peer %s %s:%s" % (peer.name, peer.ip, peer.port)
#             for peer in set([node.peer for node in cluster.nodes if node.peer])
#         ])


# Path: lighthouse/haproxy/config.py
import collections
import datetime
import logging
import six
from .stanzas.section import Section
from .stanzas.meta import MetaFrontendStanza
from .stanzas.frontend import FrontendStanza
from .stanzas.backend import BackendStanza
from .stanzas.peers import PeersStanza


    def generate(self, clusters, version=None):
        """
        Generates HAProxy config file content based on a given list of
        clusters.
        """
        now = datetime.datetime.now()

        sections = [
            Section(
                "Auto-generated by Lighthouse (%s)" % now.strftime("%c"),
                self.global_stanza,
                self.defaults_stanza
            )
        ]

        meta_stanzas = [
            MetaFrontendStanza(
                name, self.meta_clusters[name]["port"],
                self.meta_clusters[name].get("frontend", []), members,
                self.bind_address
            )
            for name, members
            in six.iteritems(self.get_meta_clusters(clusters))
        ]
        frontend_stanzas = [
            FrontendStanza(cluster, self.bind_address)
            for cluster in clusters
            if "port" in cluster.haproxy
        ]

        backend_stanzas = [BackendStanza(cluster) for cluster in clusters]