Ejemplo n.º 1
0
def update_template(stackname):
    """Limited update of the Cloudformation template.

    Resources can be added, but existing ones are immutable.

    Moreover, we never add anything related to EC2 instances as they are
    not supported anyway (they will come up as part of the template
    but without any software being on it)

    Moreover, EC2 instances must be running while this is executed or their
    resources like PublicIP will be inaccessible"""

    core_lifecycle.start(stackname)

    (pname, _) = core.parse_stackname(stackname)
    current_template = bootstrap.current_template(stackname)
    cfngen.write_template(stackname, json.dumps(current_template))

    more_context = cfngen.choose_config(stackname)
    delta = cfngen.template_delta(pname, **more_context)
    LOG.info("%s", pformat(delta))
    utils.confirm('Confirming changes to the stack template?')

    new_template = cfngen.merge_delta(stackname, delta)
    bootstrap.update_template(stackname, new_template)

    update(stackname)
 def test_start_rds_idempotence(self, load_context, find_ec2_instances,
                                find_rds_instances,
                                wait_for_ec2_steady_state):
     load_context.return_value = self.contexts[
         'project-with-rds-only--test']
     find_rds_instances.return_value = [self._rds_instance('available')]
     lifecycle.start('project-with-rds-only--test')
Ejemplo n.º 3
0
def _check_want_to_be_running(stackname, autostart=False):
    try:
        context = context_handler.load_context(stackname)
        if not _are_there_existing_servers(context):
            return False

    except context_handler.MissingContextFile as e:
        LOG.warn(e)

    instance_list = core.find_ec2_instances(stackname, allow_empty=True)
    num_instances = len(instance_list)
    if num_instances >= 1:
        return instance_list

    if not autostart:
        should_start = utils._pick(
            'should_start', [True, False],
            message='Stack not running. Should it be started?')
        if not should_start:
            return False

    core_lifecycle.start(stackname)
    # another call to get the ip addresses that are assigned to the now-running
    # instances and that weren't there before
    return core.find_ec2_instances(stackname)
Ejemplo n.º 4
0
def _check_want_to_be_running(stackname, autostart=False):
    try:
        context = context_handler.load_context(stackname)

        if 'ec2' in context:
            # early check can only be made if the instance actually declares
            # ec2 True/False in its context
            # otherwise, don't make assumptions and go ahead
            if not context['ec2']:
                return False

    except context_handler.MissingContextFile as e:
        LOG.warn(e)

    instance_list = core.find_ec2_instances(stackname, allow_empty=True)
    num_instances = len(instance_list)
    if num_instances >= 1:
        return instance_list

    if not autostart:
        should_start = utils._pick(
            'should_start', [True, False],
            message='Stack not running. Should it be started?')
        if not should_start:
            return False

    core_lifecycle.start(stackname)
    # to get the ip addresses that are assigned to the now-running instances
    # and that weren't there before
    return core.find_ec2_instances(stackname)
Ejemplo n.º 5
0
def update_infrastructure(stackname, skip=None, start=['ec2']):
    """Limited update of the Cloudformation template and/or Terraform template.

    Resources can be added, but most of the existing ones are immutable.

    Some resources are updatable in place.

    Moreover, we never add anything related to EC2 instances as they are
    not supported anyway (they will come up as part of the template
    but without any software being on it)

    Moreover, EC2 instances must be running while this is executed or their
    resources like PublicIP will be inaccessible.

    Allows to skip EC2, SQS, S3 updates by passing `skip=ec2\\,sqs\\,s3`

    By default starts EC2 instances but this can be avoid by passing `start=`"""

    skip = skip.split(",") if skip else []
    start = start.split(",") if isinstance(start, str) else start or []

    (pname, _) = core.parse_stackname(stackname)
    more_context = {}
    context, delta, current_context = cfngen.regenerate_stack(
        stackname, **more_context)

    if _are_there_existing_servers(current_context) and 'ec2' in start:
        core_lifecycle.start(stackname)
    LOG.info("Create: %s", pformat(delta.plus))
    LOG.info("Update: %s", pformat(delta.edit))
    LOG.info("Delete: %s", pformat(delta.minus))
    LOG.info("Terraform delta: %s", delta.terraform)

    # see: `buildercore.config.BUILDER_NON_INTERACTIVE` for skipping confirmation prompts
    utils.confirm(
        'Confirming changes to CloudFormation and Terraform templates?')

    context_handler.write_context(stackname, context)

    cloudformation.update_template(stackname, delta.cloudformation)
    terraform.update_template(stackname)

    # TODO: move inside bootstrap.update_stack
    # EC2
    if _are_there_existing_servers(context) and not 'ec2' in skip:
        # the /etc/buildvars.json file may need to be updated
        buildvars.refresh(stackname, context)
        update(stackname)

    # SQS
    if context.get('sqs', {}) and not 'sqs' in skip:
        bootstrap.update_stack(stackname, service_list=['sqs'])

    # S3
    if context.get('s3', {}) and not 's3' in skip:
        bootstrap.update_stack(stackname, service_list=['s3'])
Ejemplo n.º 6
0
def update_infrastructure(stackname, skip=None, start=['ec2']):
    """Limited update of the Cloudformation template and/or Terraform template.

    Resources can be added, but most of the existing ones are immutable.

    Some resources are updatable in place.

    Moreover, we never add anything related to EC2 instances as they are
    not supported anyway (they will come up as part of the template
    but without any software being on it)

    Moreover, EC2 instances must be running while this is executed or their
    resources like PublicIP will be inaccessible.

    Allows to skip EC2, SQS, S3 updates by passing `skip=ec2\\,sqs\\,s3`

    By default starts EC2 instances but this can be avoid by passing `start=`"""

    skip = skip.split(",") if skip else []
    start = start.split(",") if isinstance(start, str) else start or []

    (pname, _) = core.parse_stackname(stackname)
    more_context = {}
    context, delta, current_context = cfngen.regenerate_stack(stackname, **more_context)

    if _are_there_existing_servers(current_context) and 'ec2' in start:
        core_lifecycle.start(stackname)
    LOG.info("Create: %s", pformat(delta.plus))
    LOG.info("Update: %s", pformat(delta.edit))
    LOG.info("Delete: %s", pformat(delta.minus))
    LOG.info("Terraform delta: %s", delta.terraform)
    utils.confirm('Confirming changes to CloudFormation and Terraform templates?')

    context_handler.write_context(stackname, context)

    cloudformation.update_template(stackname, delta.cloudformation)
    terraform.update_template(stackname)

    # TODO: move inside bootstrap.update_stack
    # EC2
    if _are_there_existing_servers(context) and not 'ec2' in skip:
        # the /etc/buildvars.json file may need to be updated
        buildvars.refresh(stackname, context)
        update(stackname)

    # SQS
    if context.get('sqs', {}) and not 'sqs' in skip:
        bootstrap.update_stack(stackname, service_list=['sqs'])

    # S3
    if context.get('s3', {}) and not 's3' in skip:
        bootstrap.update_stack(stackname, service_list=['s3'])
    def test_start_a_not_running_rds_instance(self, load_context, find_ec2_instances, find_rds_instances, rds_connection):
        load_context.return_value = self.contexts['project-with-rds-only--test']
        find_ec2_instances.return_value = []
        find_rds_instances.side_effect = [
            [self._rds_instance('stopped')],
            [self._rds_instance('available')]
        ]

        c = MagicMock()
        c.start_db_instance = MagicMock()
        rds_connection.return_value = c

        lifecycle.start('project-with-rds-only--test')
    def test_start_a_not_running_ec2_instance(self, load_context, find_ec2_instances, find_rds_instances, ec2_connection, some_node_is_not_ready):
        load_context.return_value = self.contexts['dummy1--test']
        find_ec2_instances.side_effect = [
            [self._ec2_instance('stopped')],
            [self._ec2_instance('running')],
            [self._ec2_instance('running')] # update_dns additional call
        ]
        some_node_is_not_ready.return_value = False

        c = MagicMock()
        c.start_instances = MagicMock()
        ec2_connection.return_value = c
        lifecycle.start('dummy1--test')
Ejemplo n.º 9
0
    def set_up_stack(cls, project, explicitly_start=False):
        switch_in_test_settings()

        # to re-use an existing stack, ensure cls.reuse_existing_stack is True
        # this will read the instance name from a temporary file (if it exists) and
        # look for that, creating it if doesn't exist yet
        # also ensure cls.cleanup is False so the instance isn't destroyed after tests complete
        cls.reuse_existing_stack = config.TWI_REUSE_STACK
        cls.cleanup = config.TWI_CLEANUP

        cls.stacknames = []
        cls.environment = generate_environment_name()
        # cls.temp_dir, cls.rm_temp_dir = utils.tempdir()

        # debugging only, where we keep an instance up between processes
        cls.state, cls.statefile = {}, '/tmp/.open-test-instances.txt'

        if cls.reuse_existing_stack and os.path.exists(cls.statefile):
            # evidence of a previous instance and we've been told to re-use old instances
            old_state = json.load(open(cls.statefile, 'r'))
            old_env = old_state.get('environment')

            # test if the old stack still exists ...
            if old_env and core.describe_stack(project + "--" + old_env,
                                               allow_missing=True):
                cls.state = old_state
                cls.environment = old_env
            else:
                # nope. old statefile is bogus, delete it
                os.unlink(cls.statefile)

        cls.state['environment'] = cls.environment  # will be saved later

        with settings(abort_on_prompts=True):
            cls.stackname = '%s--%s' % (project, cls.environment)
            cls.stacknames.append(cls.stackname)

            if cls.cleanup:
                LOG.info("ensure_destroyed %s", cls.stackname)
                cfn.ensure_destroyed(cls.stackname)

            cls.context, cls.cfn_template, _ = cfngen.generate_stack(
                project, stackname=cls.stackname)
            cls.region = cls.context['aws']['region']
            LOG.info("create_stack %s", cls.stackname)
            bootstrap.create_stack(cls.stackname)

            if explicitly_start:
                LOG.info("start %s", cls.stackname)
                lifecycle.start(cls.stackname)
Ejemplo n.º 10
0
    def set_up_stack(cls, project, explicitly_start=False):
        switch_in_test_settings()

        # to re-use an existing stack, ensure cls.reuse_existing_stack is True
        # this will read the instance name from a temporary file (if it exists) and
        # look for that, creating it if doesn't exist yet
        # also ensure cls.cleanup is False so the instance isn't destroyed after tests complete
        cls.reuse_existing_stack = config.TWI_REUSE_STACK
        cls.cleanup = config.TWI_CLEANUP

        cls.stacknames = []
        cls.environment = generate_environment_name()
        # cls.temp_dir, cls.rm_temp_dir = utils.tempdir()

        # debugging only, where we keep an instance up between processes
        cls.state, cls.statefile = {}, '/tmp/.open-test-instances.txt'

        if cls.reuse_existing_stack and os.path.exists(cls.statefile):
            # evidence of a previous instance and we've been told to re-use old instances
            old_state = json.load(open(cls.statefile, 'r'))
            old_env = old_state.get('environment')

            # test if the old stack still exists ...
            if old_env and core.describe_stack(project + "--" + old_env, allow_missing=True):
                cls.state = old_state
                cls.environment = old_env
            else:
                # nope. old statefile is bogus, delete it
                os.unlink(cls.statefile)

        cls.state['environment'] = cls.environment # will be saved later

        with settings(abort_on_prompts=True):
            cls.stackname = '%s--%s' % (project, cls.environment)
            cls.stacknames.append(cls.stackname)

            if cls.cleanup:
                LOG.info("ensure_destroyed %s", cls.stackname)
                cfn.ensure_destroyed(cls.stackname)

            cls.context, cls.cfn_template, _ = cfngen.generate_stack(project, stackname=cls.stackname)
            cls.region = cls.context['aws']['region']
            LOG.info("create_stack %s", cls.stackname)
            bootstrap.create_stack(cls.stackname)

            if explicitly_start:
                LOG.info("start %s", cls.stackname)
                lifecycle.start(cls.stackname)
    def test_start_a_not_running_rds_instance(self, load_context,
                                              find_ec2_instances,
                                              find_rds_instances,
                                              rds_connection,
                                              wait_for_ec2_steady_state):
        load_context.return_value = self.contexts[
            'project-with-rds-only--test']
        find_ec2_instances.return_value = []
        find_rds_instances.side_effect = [[self._rds_instance('stopped')],
                                          [self._rds_instance('available')]]

        c = MagicMock()
        c.start_db_instance = MagicMock()
        rds_connection.return_value = c

        lifecycle.start('project-with-rds-only--test')
    def test_start_a_not_running_ec2_instance(self, load_context,
                                              find_ec2_instances,
                                              find_rds_instances,
                                              ec2_connection,
                                              wait_for_ec2_steady_state):
        load_context.return_value = self.contexts['dummy1--test']
        find_ec2_instances.side_effect = [
            [self._ec2_instance('stopped')],
            [self._ec2_instance('running')],
            [self._ec2_instance('running')]  # update_dns additional call
        ]

        c = MagicMock()
        c.start_instances = MagicMock()
        ec2_connection.return_value = c
        lifecycle.start('dummy1--test')
Ejemplo n.º 13
0
    def test_create(self):
        with settings(abort_on_prompts=True):
            project = 'dummy1'
            stackname = '%s--%s' % (project, self.environment)

            cfn.ensure_destroyed(stackname)
            self.stacknames.append(stackname) # ensures stack is destroyed

            cfngen.generate_stack(project, stackname=stackname)
            bootstrap.create_stack(stackname)

            buildvars.switch_revision(stackname, 'master')
            buildvars.force(stackname, 'answer', 'forty-two')

            lifecycle.stop(stackname)
            lifecycle.start(stackname)
Ejemplo n.º 14
0
def _check_want_to_be_running(stackname):
    instance_list = core.find_ec2_instances(stackname)
    num_instances = len(instance_list)
    if num_instances >= 1:
        return instance_list

    should_start = utils._pick(
        'should_start', [True, False],
        message='Stack not running. Should it be started?')
    if not should_start:
        return False

    core_lifecycle.start(stackname)
    # to get the ip addresses that are assigned to the now-running instances
    # and that weren't there before
    return core.find_ec2_instances(stackname)
Ejemplo n.º 15
0
def update_template(stackname):
    """Limited update of the Cloudformation template.

    Resources can be added, but most of the existing ones are immutable.

    Some resources are updatable in place.

    Moreover, we never add anything related to EC2 instances as they are
    not supported anyway (they will come up as part of the template
    but without any software being on it)

    Moreover, EC2 instances must be running while this is executed or their
    resources like PublicIP will be inaccessible"""

    (pname, _) = core.parse_stackname(stackname)
    more_context = cfngen.choose_config(stackname)

    context, delta_plus, delta_minus = cfngen.regenerate_stack(
        pname, **more_context)

    if context['ec2']:
        core_lifecycle.start(stackname)
    LOG.info("Create/update: %s", pformat(delta_plus))
    LOG.info("Delete: %s", pformat(delta_minus))
    utils.confirm(
        'Confirming changes to the stack template? This will rewrite the context and the CloudFormation template'
    )

    context_handler.write_context(stackname, context)

    if delta_plus['Resources'] or delta_plus['Outputs'] or delta_minus[
            'Resources'] or delta_minus['Outputs']:
        new_template = cfngen.merge_delta(stackname, delta_plus, delta_minus)
        bootstrap.update_template(stackname, new_template)
        # the /etc/buildvars.json file may need to be updated
        buildvars.refresh(stackname, context)
    else:
        # attempting to apply an empty change set would result in an error
        LOG.info("Nothing to update on CloudFormation")

    update(stackname)
Ejemplo n.º 16
0
    def test_create(self):
        with settings(abort_on_prompts=True):
            project = 'dummy1'
            stackname = '%s--%s' % (project, self.environment)

            cfn.ensure_destroyed(stackname)
            self.stacknames.append(stackname)

            cfngen.generate_stack(project, stackname=stackname)
            bootstrap.create_stack(stackname)

            buildvars.switch_revision(stackname, 'master')
            buildvars.force(stackname, 'answer', 'forty-two')

            lifecycle.stop(stackname)
            lifecycle.start(stackname)

            cfn.cmd(stackname,
                    "ls -l /",
                    username=BOOTSTRAP_USER,
                    concurrency='parallel')

            cfn.download_file(stackname,
                              "/bin/ls",
                              "ls",
                              use_bootstrap_user="******")
            self.assertTrue(os.path.isfile("./ls"))

            cfn.download_file(stackname,
                              "/bin/less",
                              "venv/bin/",
                              use_bootstrap_user="******")
            self.assertTrue(os.path.isfile("./venv/bin/less"))

            cfn.download_file(stackname,
                              "/bin/pwd",
                              "subfolder/pwd",
                              use_bootstrap_user="******")
            self.assertTrue(os.path.isfile("./subfolder/pwd"))
Ejemplo n.º 17
0
def _check_want_to_be_running(stackname, autostart=False):
    try:
        context = context_handler.load_context(stackname)
        if not _are_there_existing_servers(context):
            return False

    except context_handler.MissingContextFile as e:
        LOG.warn(e)

    instance_list = core.find_ec2_instances(stackname, allow_empty=True)
    num_instances = len(instance_list)
    if num_instances >= 1:
        return instance_list

    if not autostart:
        should_start = utils._pick('should_start', [True, False], message='Stack not running. Should it be started?')
        if not should_start:
            return False

    core_lifecycle.start(stackname)
    # another call to get the ip addresses that are assigned to the now-running
    # instances and that weren't there before
    return core.find_ec2_instances(stackname)
 def test_start_ec2_idempotence(self, load_context, find_ec2_instances,
                                find_rds_instances,
                                wait_for_ec2_steady_state):
     load_context.return_value = self.contexts['dummy1--test']
     find_ec2_instances.return_value = [self._ec2_instance('running')]
     lifecycle.start('dummy1--test')
Ejemplo n.º 19
0
 def setUp(self):
     lifecycle.start(self.stackname)
Ejemplo n.º 20
0
 def setUp(self):
     lifecycle.start(self.stackname)
Ejemplo n.º 21
0
def start(stackname):
    "Starts the nodes of 'stackname'. Idempotent"
    lifecycle.start(stackname)
 def test_start_ec2_idempotence(self, load_context, find_ec2_instances, find_rds_instances):
     load_context.return_value = self.contexts['dummy1--test']
     find_ec2_instances.return_value = [self._ec2_instance('running')]
     lifecycle.start('dummy1--test')
 def test_start_rds_idempotence(self, load_context, find_ec2_instances, find_rds_instances):
     load_context.return_value = self.contexts['project-with-rds-only--test']
     find_rds_instances.return_value = [self._rds_instance('available')]
     lifecycle.start('project-with-rds-only--test')