MACFILE_ON_FAILURE_DESTROY_OTHERS = "destroy_others" MACFILE_ON_FAILURE_DESTROY_ALL = "destroy_all" BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
def show(string=""):
def showc(string, colour=WHITE):
def show_error(string):
def clear():
def general_help():
def header(text, char=None):
def cmd_error(command, rc, stdout, stderr):
def _has_colours(stream):
def show_provider_help(): def is_ip_private(ip):
    # https://en.wikipedia.org/wiki/Private_network

    priv_lo = re.compile("^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
    priv_24 = re.compile("^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
    priv_20 = re.compile("^192\.168\.\d{1,3}.\d{1,3}$")
    priv_16 = re.compile("^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$")

    return priv_lo.match(ip) or priv_24.match(ip) or priv_20.match(ip) or priv_16.match(ip) def is_local(ip):
    # https://en.wikipedia.org/wiki/Private_network

    priv_lo = re.compile("^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$")

    return priv_lo.match(ip) class MacParseEnvException(Exception):
    """Error while parsing variables in a macfile"""
    pass class FactError(Exception):
    """ Error in the Fact  """
    pass class MacApiError(Exception):
    """An error status code was returned when querying the HTTP API"""
    pass class BashException(Exception):
    """Bash command failed running"""
    pass class MacResourceException(Exception):
    """Error while creating a resource"""
    pass
import time
import maccli
import pprint
import maccli.service.instance
import maccli.view.view_generic
import maccli.view.view_instance
import maccli.view.view_infrastructure
import maccli.helper.macfile
import maccli.helper.cmd
import maccli.service.resource
from maccli.config import MACFILE_ON_FAILURE_DESTROY_OTHERS, MACFILE_ON_FAILURE_DESTROY_ALL
from maccli.view.view_generic import GREEN, RED
from maccli.helper.network import is_ip_private, is_local
from maccli.helper.exception import MacParseEnvException, FactError, MacApiError, BashException, \
    MacResourceException

    return envs_clean, all_processed


def apply_instance_infrastructure_changes(instances, infrastructure_name, version, quiet, infrastructures, infrastructure_resources_processed):
    """
    Make sure that all instances in a infrastructure are processed
    :param instances:
    :return:
    """
    configuration_pending = []
    other_instances = []
    for instance in instances:

        if instance['status'] == "Instance completed":
            infrastructure_key = instance['metadata']['infrastructure']['macfile_infrastructure_name']
            infrastructure = infrastructures[infrastructure_key]
            dependencies_ready = maccli.helper.macfile.is_role_dependencies_ready(infrastructure, instances, infrastructure_key)
            if dependencies_ready:
                configuration_pending.append(instance)
            else:
                maccli.logger.debug("[%s] instance discarded as 'ready' dependencies are not met" % instance['servername'])

        if instance['ipv4'] is not None:
            other_instances.append(instance)

    action = False
    for instance in configuration_pending:
        maccli.logger.debug("[%s] Checking instance " % instance['servername'])

        #
        #    This cookbook tag must change to implement the configurations async.
        #
        cookbook_tag = ""
        if 'cookbook_tag' in instance['metadata']['system']['role']:
            cookbook_tag = instance['metadata']['system']['role']['cookbook_tag']

        bootstrap = ""
        if 'bootstrap' in instance['metadata']['system']['role']:
            bootstrap = instance['metadata']['system']['role']['bootstrap']

        instance_id = instance['id']

        # if there are dynamic variables
        if 'environment_raw' in instance['metadata']['infrastructure']:
            environment_raws = instance['metadata']['infrastructure']['environment_raw']
            maccli.logger.debug("[%s] Environment raw: %s" % (instance['servername'], environment_raws))
            maccli.logger.debug("[%s] Instances: %s" % (instance['servername'], other_instances))
            environment_clean, processed = parse_instance_envs(environment_raws, other_instances)
            maccli.logger.debug("[%s] Environment clean: %s" % (instance['servername'], environment_clean))
            metadata_new = {'system': {'role': {'environment': environment_clean}}}
            maccli.logger.debug("[%s] Process %s" % (instance['servername'], processed))
            if processed:
                action = True
                maccli.service.instance.update_configuration(cookbook_tag, bootstrap, instance_id, metadata_new)
                processing_instances = maccli.service.instance.list_by_infrastructure(infrastructure_name, version)
                if quiet:
                    maccli.view.view_generic.show("Applying configuration to %s" % instance['servername'])
                else:
                    maccli.view.view_generic.clear()
                    maccli.view.view_instance.show_instances(processing_instances)
                    maccli.view.view_infrastructure.show_infrastructure_resources(infrastructures, infrastructure_resources_processed)

        # there are not dynamic variables, it can start straight away
        else:
            action = True
            maccli.logger.debug("[%s] Processing ")
            maccli.service.instance.update_configuration(cookbook_tag, bootstrap, instance_id)
            processing_instances = maccli.service.instance.list_by_infrastructure(infrastructure_name, version)
            if quiet:
                maccli.view.view_generic.show("Applying configuration to %s" % instance['servername'])
            else:
                maccli.view.view_generic.clear()
                maccli.view.view_instance.show_instances(processing_instances)
                maccli.view.view_infrastructure.show_infrastructure_resources(infrastructures, infrastructure_resources_processed)

    if action:
        """ Allow all tasks to start """
        time.sleep(3)


def clean_up(instances, on_failure):
    failed = False
    for instance in instances:
        if instance['status'] == "Creation failed" or instance['status'] == "Configuration Error":
            failed = True

    if failed and on_failure is not None:
        maccli.view.view_generic.show_error("Cleaning up")
        for instance in instances:
            if on_failure == MACFILE_ON_FAILURE_DESTROY_OTHERS:
                if not (instance['status'] == "Creation failed" or instance['status'] == "Configuration Error"):
                    maccli.view.view_generic.show_error("Destroying instance %s " % instance['id'])
                    maccli.service.instance.destroy_instance(instance['id'])
            elif on_failure == MACFILE_ON_FAILURE_DESTROY_ALL:
                maccli.view.view_generic.show_error("Destroying instance %s " % instance['id'])
                maccli.service.instance.destroy_instance(instance['id'])
            else:
                maccli.view.view_generic.show_error("ERROR: clean up %s not implemented" % on_failure)

    return failed


def apply_resources(processed_instances, processed_resources, instances, roles, infrastructures, actions, resources, root, quiet):
    """ Apply all the resources that are not instances """
    # If event cannot happen, wait to the next loop
    resources_processed_part = []
    finish = True
    for infrastructure_key in infrastructures:
        infrastructure = infrastructures[infrastructure_key]

        if not any(infrastructure_key in d for d in processed_resources):
            maccli.logger.debug("%s does not exist in processed resources %s" % (infrastructure_key, processed_resources))
            if 'resource' in infrastructure:
                maccli.logger.debug("Type resource")
                log_type = "resource"
                key = infrastructure['resource']
                try:
                    command_raw = resources[key]['create bash']
                except KeyError:

                    raise MacResourceException("Resource %s not found" % key, "Resource %s not found" % key)