コード例 #1
0
def retrieve_latest_base_ami(environment, deployment, play, override,
                             ubuntu_version, out_file, region):
    """
    Method used to retrieve the latest AMI ID from Ubuntu cloud images locator.
    Also adds tags from latest app ami for the pr messenger and wiki page writer to diff releases
    """

    try:
        edp_ami_id = ec2.active_ami_for_edp(environment, deployment, play)
        if override:
            ami_id = override
        else:
            url = ""
            click.secho('Ubuntu version :  {}'.format(ubuntu_version),
                        fg='green')
            if ubuntu_version == "16.04":
                url = "https://cloud-images.ubuntu.com/query/xenial/server/released.current.txt"
                click.secho('Xenial.\n: {}'.format(url), fg='green')
            elif ubuntu_version == "18.04":
                url = "https://cloud-images.ubuntu.com/query/bionic/server/released.current.txt"
                click.secho('Bionic.\n: {}'.format(url), fg='green')
            if url == "":
                url = "https://cloud-images.ubuntu.com/query/xenial/server/released.current.txt"
            data = requests.get(url)
            parse_ami = re.findall(
                'ebs-ssd(.+?)amd64(.+?){}(.+?)hvm'.format(region),
                data.content.decode('utf-8'))
            ami_id = parse_ami[0][2].strip()
            click.secho('AMI ID fetched from Ubuntu Cloud : {}'.format(ami_id),
                        fg='red')

        ami_info = {
            # This is passed directly to an ansible script that expects a base_ami_id variable
            'base_ami_id': ami_id,
            # This matches the key produced by the create_ami.yml ansible play to make
            # generating release pages easier.
            'ami_id': ami_id,
        }
        ami_info.update(ec2.tags_for_ami(edp_ami_id))
        logging.info("Found latest AMI ID : {ami_id}".format(ami_id=ami_id))

        if out_file:
            with io.open(out_file, 'w') as stream:
                yaml.safe_dump(ami_info,
                               stream,
                               default_flow_style=False,
                               explicit_start=True)
        else:
            print(
                yaml.safe_dump(ami_info,
                               default_flow_style=False,
                               explicit_start=True))

    except Exception as err:  # pylint: disable=broad-except
        traceback.print_exc()
        click.secho('Error finding base AMI ID.\nMessage: {}'.format(err),
                    fg='red')
        sys.exit(1)

    sys.exit(0)
コード例 #2
0
def retrieve_base_ami(environment, deployment, play, override, out_file):
    """
    Method used to retrieve the last base AMI ID used for an environment/deployment/play.
    """

    has_edp = environment is not None or deployment is not None or play is not None
    if has_edp and override is not None:
        logging.error(
            "--environment, --deployment and --play are mutually exclusive with --override."
        )
        sys.exit(1)

    if not has_edp and override is None:
        logging.error(
            "Either --environment, --deployment and --play or --override are required."
        )
        sys.exit(1)

    try:
        if override:
            ami_id = override
        else:
            ami_id = ec2.active_ami_for_edp(environment, deployment, play)

        ami_info = {
            # This is passed directly to an ansible script that expects a base_ami_id variable
            'base_ami_id': ami_id,
            # This matches the key produced by the create_ami.yml ansible play to make
            # generating release pages easier.
            'ami_id': ami_id,
        }
        ami_info.update(ec2.tags_for_ami(ami_id))
        logging.info(
            "Found active AMI ID for {env}-{dep}-{play}: {ami_id}".format(
                env=environment, dep=deployment, play=play, ami_id=ami_id))

        if out_file:
            with io.open(out_file, 'w') as stream:
                yaml.safe_dump(ami_info,
                               stream,
                               default_flow_style=False,
                               explicit_start=True)
        else:
            print(
                yaml.safe_dump(ami_info,
                               default_flow_style=False,
                               explicit_start=True))

    except Exception as err:  # pylint: disable=broad-except
        traceback.print_exc()
        click.secho('Error finding base AMI ID.\nMessage: {}'.format(err),
                    fg='red')
        sys.exit(1)

    sys.exit(0)
コード例 #3
0
ファイル: test_ec2.py プロジェクト: eol-uchile/tubular
 def test_ami_for_edp_multiple_amis(self):
     fake_ami_id1 = self._make_fake_ami()
     fake_ami_id2 = self._make_fake_ami()
     fake_elb_name = "healthy-lb-1"
     fake_elb = create_elb(fake_elb_name)
     fake_asg_name1 = "fully_tagged_asg1"
     fake_asg_name2 = "fully_tagged_asg2"
     fake_asg_tags = {
         "environment": "foo",
         "deployment": "bar",
         "play": "baz"
     }
     create_asg_with_tags(fake_asg_name1,
                          fake_asg_tags,
                          ami_id=fake_ami_id1,
                          elbs=[fake_elb])
     create_asg_with_tags(fake_asg_name2,
                          fake_asg_tags,
                          ami_id=fake_ami_id2,
                          elbs=[fake_elb])
     with self.assertRaises(MultipleImagesFoundException):
         ec2.active_ami_for_edp('foo', 'bar', 'baz')
コード例 #4
0
ファイル: test_ec2.py プロジェクト: eol-uchile/tubular
 def test_ami_for_edp_success(self):
     fake_ami_id = self._make_fake_ami()
     fake_elb_name = "healthy-lb-1"
     fake_elb = create_elb(fake_elb_name)
     fake_asg_name = "fully_tagged_asg"
     fake_asg_tags = {
         "environment": "foo",
         "deployment": "bar",
         "play": "baz"
     }
     create_asg_with_tags(fake_asg_name,
                          fake_asg_tags,
                          ami_id=fake_ami_id,
                          elbs=[fake_elb])
     self.assertEqual(ec2.active_ami_for_edp('foo', 'bar', 'baz'),
                      fake_ami_id)
コード例 #5
0
ファイル: asgard.py プロジェクト: eltoncarr/tubular
def deploy(ami_id):
    """
    Deploys an AMI as an auto-scaling group (ASG) to AWS.

    Arguments:
        ami_id(str): AWS AMI ID

    Returns:
        dict(str, str, dict): Returns a dictionary with the keys:
            'ami_id' - AMI id used to deploy the AMI.
            'current_ami_id' - AMI_ID of the current ASG.
            'current_asgs' - Lists of current active ASGs, keyed by cluster.
            'disabled_ami_id' - AMI_ID of the disabled ASG.
            'disabled_asgs' - Lists of current inactive ASGs, keyed by cluster.

    Raises:
        TimeoutException: When the task to bring up the new instance times out.
        BackendError: When the task to bring up the new instance fails.
        ASGDoesNotExistException: If the ASG being queried does not exist.
    """
    LOG.info("Processing request to deploy {}.".format(ami_id))

    # Pull the EDP from the AMI ID
    edp = ec2.edp_for_ami(ami_id)

    # fetch the active AMI_ID
    try:
        disabled_ami_id = ec2.active_ami_for_edp(edp.environment, edp.deployment, edp.play)
    except (ImageNotFoundException, MultipleImagesFoundException):
        # don't want to fail on this info not being available, we'll assign UNKNOWN and
        # continue with the rollback
        disabled_ami_id = 'UNKNOWN'

    # These are all autoscaling groups that match the tags we care about.
    existing_edp_asgs = ec2.asgs_for_edp(edp, filter_asgs_pending_delete=False)

    # Find the clusters for all the existing ASGs.
    existing_clustered_asgs = clusters_for_asgs(existing_edp_asgs)
    LOG.info("Deploying to cluster(s) {}".format(existing_clustered_asgs.keys()))

    # Create a new ASG in each cluster.
    new_clustered_asgs = defaultdict(list)
    for cluster in existing_clustered_asgs:
        try:
            newest_asg = new_asg(cluster, ami_id)
            new_clustered_asgs[cluster].append(newest_asg)
        except:
            msg = "ASG creation failed for cluster '{}' but succeeded for cluster(s) {}."
            msg = msg.format(cluster, new_clustered_asgs.keys())
            LOG.exception(msg)
            raise

    new_asgs = [asgs[0] for asgs in new_clustered_asgs.values()]
    LOG.info("New ASGs created: {}".format(new_asgs))
    ec2.wait_for_in_service(new_asgs, 300)
    LOG.info("New ASGs healthy: {}".format(new_asgs))

    LOG.info("Enabling traffic to new ASGs for the {} cluster(s).".format(existing_clustered_asgs.keys()))
    success, enabled_asgs, disabled_asgs = _red_black_deploy(dict(new_clustered_asgs), existing_clustered_asgs)
    if not success:
        raise BackendError("Error performing red/black deploy - deploy was unsuccessful. "
                           "enabled_asgs: {} - disabled_asgs: {}".format(enabled_asgs, disabled_asgs))

    LOG.info("Woot! Deploy Done!")
    return {
        'ami_id': ami_id,
        'current_ami_id': ami_id,
        'current_asgs': enabled_asgs,
        'disabled_asgs': disabled_asgs,
        'disabled_ami_id': disabled_ami_id,
    }
コード例 #6
0
ファイル: asgard.py プロジェクト: eltoncarr/tubular
def rollback(current_clustered_asgs, rollback_to_clustered_asgs, ami_id=None):
    """
    Rollback to a particular list of ASGs for one or more clusters.
    If rollback does not succeed, create new ASGs based on the AMI ID and deploy those ASGs.

    Arguments:
        current_clustered_asgs(dict): ASGs currently enabled, grouped by cluster.
        rollback_to_clustered_asgs(dict): ASGs to rollback to, grouped by cluster.
        ami_id(str): AWS AMI ID to which to rollback to.

    Returns:
        dict(str, str, dict): Returns a dictionary with the keys:
            'ami_id' - AMI id used to deploy the AMI, None if unspecified.
            'current_ami_id' -  The AMI that is running in an environment after a rollback.
            'current_asgs' - Lists of current active ASGs, keyed by cluster.
            'disabled_ami_id' - The AMI that was running in an environment before the rollback.
            'disabled_asgs' - Lists of current inactive ASGs, keyed by cluster.

    Raises:
        TimeoutException: When the task to bring up the new instance times out.
        BackendError: When the task to bring up the new instance fails.
        ASGDoesNotExistException: If the ASG being queried does not exist.
    """
    # First, ensure that the ASGs to which we'll rollback are not tagged for deletion.
    # Also, ensure that those same ASGs are not in the process of deletion.
    rollback_ready = True
    asgs_tagged_for_deletion = [asg.name for asg in ec2.get_asgs_pending_delete()]
    for asgs in rollback_to_clustered_asgs.values():
        for asg in asgs:
            try:
                if asg in asgs_tagged_for_deletion:
                    # ASG is tagged for deletion. Remove the deletion tag.
                    ec2.remove_asg_deletion_tag(asg)
                if is_asg_pending_delete(asg):
                    # Too late for rollback - this ASG is already pending delete.
                    LOG.info("Rollback ASG '{}' is pending delete. Aborting rollback to ASGs.".format(asg))
                    rollback_ready = False
                    break
            except ASGDoesNotExistException:
                LOG.info("Rollback ASG '{}' has been removed. Aborting rollback to ASGs.".format(asg))
                rollback_ready = False
                break
    disabled_ami_id = None
    try:
        # fetch the currently deployed AMI_ID for the clusters for logging
        if ami_id:
            edp = ec2.edp_for_ami(ami_id)
            disabled_ami_id = ec2.active_ami_for_edp(edp.environment, edp.deployment, edp.play)
    except (MissingTagException, ImageNotFoundException, MultipleImagesFoundException):
        # don't want to fail on this info not being available, we'll assign UNKNOWN and
        # continue with the rollback
        disabled_ami_id = 'UNKNOWN'

    if rollback_ready:
        # Perform the rollback.
        success, enabled_asgs, disabled_asgs = _red_black_deploy(rollback_to_clustered_asgs, current_clustered_asgs)
        if not success:
            LOG.info("Rollback failed for cluster(s) {}.".format(current_clustered_asgs.keys()))
        else:
            LOG.info("Woot! Rollback Done!")
            return {
                'ami_id': ami_id,
                'current_ami_id': ami_id,
                'current_asgs': enabled_asgs,
                'disabled_ami_id': disabled_ami_id,
                'disabled_asgs': disabled_asgs
            }

    # Rollback failed -or- wasn't attempted. Attempt a deploy.
    if ami_id:
        LOG.info("Attempting rollback via deploy of AMI {}.".format(ami_id))
        return deploy(ami_id)
    else:
        LOG.info("No AMI id specified - so no deploy occurred during rollback.")
        return {
            'ami_id': None,
            'current_ami_id': ami_id,
            'current_asgs': current_clustered_asgs,
            'disabled_ami_id': disabled_ami_id,
            'disabled_asgs': rollback_to_clustered_asgs
        }
コード例 #7
0
ファイル: test_ec2.py プロジェクト: eol-uchile/tubular
 def test_ami_for_edp_missing_edp(self):
     # Non-existent EDP
     with self.assertRaises(ImageNotFoundException):
         ec2.active_ami_for_edp('One', 'Two', 'Three')