예제 #1
0
def remove_stack_set_instances(args):
    client = AWS.current_session().client('cloudformation')
    client.delete_stack_instances(StackSetName=args.stack_set,
                                  Accounts=args.accounts,
                                  Regions=args.regions,
                                  RetainStacks=args.retain)
    logger.info('Removed StackSet Instances for StackSet {}'.format(args.stack_set))
예제 #2
0
def aws_regions():
    from formica.aws import AWS
    current_session = AWS.current_session()
    ec2 = current_session.client('ec2')
    regions = ec2.describe_regions()
    regions = [r['RegionName'] for r in regions['Regions']]
    return {'AWSRegions': regions}
예제 #3
0
def __manage_stack_set(args, create):
    client = AWS.current_session().client('cloudformation')
    params = parameters(parameters=args.parameters,
                        tags=args.tags,
                        capabilities=args.capabilities,
                        accounts=vars(args).get('accounts'),
                        regions=vars(args).get('regions'),
                        execution_role_name=args.execution_role_name,
                        administration_role_arn=args.administration_role_arn)
    loader = Loader(variables=args.vars)
    loader.load()
    if create:
        result = client.create_stack_set(
            StackSetName=args.stack_set,
            TemplateBody=loader.template(),
            ** params
        )
        logger.info('StackSet {} created'.format(args.stack_set))
    else:
        result = client.update_stack_set(
            StackSetName=args.stack_set,
            TemplateBody=loader.template(),
            ** params
        )
        logger.info('StackSet {} updated in Operation {}'.format(args.stack_set, result['OperationId']))
예제 #4
0
파일: cli.py 프로젝트: ryansb/formica
def deploy(args):
    client = AWS.current_session().client('cloudformation')
    last_event = client.describe_stack_events(
        StackName=args.stack)['StackEvents'][0]['EventId']
    client.execute_change_set(
        ChangeSetName=(CHANGE_SET_FORMAT.format(stack=args.stack)),
        StackName=args.stack)
    StackWaiter(args.stack, client).wait(last_event)
예제 #5
0
파일: cli.py 프로젝트: ryansb/formica
def remove(args):
    client = AWS.current_session().client('cloudformation')
    stack_id = client.describe_stacks(
        StackName=args.stack)['Stacks'][0]['StackId']
    logger.info('Removing Stack and waiting for it to be removed, ...')
    last_event = client.describe_stack_events(
        StackName=args.stack)['StackEvents'][0]['EventId']
    client.delete_stack(StackName=args.stack)
    StackWaiter(stack_id, client).wait(last_event)
예제 #6
0
def compare_stack_set(stack,
                      vars=None,
                      parameters={},
                      tags={},
                      main_account_parameter=False):
    client = AWS.current_session().client('cloudformation')

    stack_set = client.describe_stack_set(StackSetName=stack, )['StackSet']
    __compare(stack_set['TemplateBody'], stack_set, vars, parameters, tags,
              main_account_parameter)
예제 #7
0
파일: cli.py 프로젝트: ryansb/formica
def change(args):
    client = AWS.current_session().client('cloudformation')
    loader = Loader()
    loader.load()

    change_set = ChangeSet(stack=args.stack, client=client)
    change_set.create(template=loader.template(),
                      change_set_type='UPDATE',
                      parameters=args.parameters,
                      tags=args.tags,
                      capabilities=args.capabilities)
    change_set.describe()
예제 #8
0
파일: cli.py 프로젝트: ryansb/formica
def new(args):
    client = AWS.current_session().client('cloudformation')
    loader = Loader()
    loader.load()
    logger.info('Creating change set for new stack, ...')
    change_set = ChangeSet(stack=args.stack, client=client)
    change_set.create(template=loader.template(),
                      change_set_type='CREATE',
                      parameters=args.parameters,
                      tags=args.tags,
                      capabilities=args.capabilities)
    change_set.describe()
    logger.info('Change set created, please deploy')
예제 #9
0
파일: cli.py 프로젝트: ryansb/formica
def stacks(args):
    client = AWS.current_session().client('cloudformation')
    stacks = client.describe_stacks()
    table = Texttable(max_width=150)
    table.add_rows([STACK_HEADERS])

    for stack in stacks['Stacks']:
        table.add_row([
            stack['StackName'], stack['CreationTime'],
            stack.get('LastUpdatedTime', ''), stack['StackStatus']
        ])

    logger.info("Current Stacks:\n" + table.draw() + "\n")
예제 #10
0
파일: cli.py 프로젝트: ryansb/formica
def resources(args):
    client = AWS.current_session().client('cloudformation')
    paginator = client.get_paginator('list_stack_resources').paginate(
        StackName=args.stack)

    table = Texttable(max_width=150)
    table.add_rows([RESOURCE_HEADERS])

    for page in paginator:
        for resource in page['StackResourceSummaries']:
            table.add_row([
                resource['LogicalResourceId'], resource['PhysicalResourceId'],
                resource['ResourceType'], resource['ResourceStatus']
            ])

    logger.info(table.draw() + "\n")
예제 #11
0
def aws_accounts():
    from formica.aws import AWS
    current_session = AWS.current_session()
    organizations = current_session.client('organizations')
    sts = current_session.client('sts')
    orgs = organizations.list_accounts()
    accounts = [{
        'Id': a['Id'],
        'Name': a['Name'],
        'Email': a['Email']
    } for a in orgs['Accounts'] if a['Status'] == 'ACTIVE']
    account_id = sts.get_caller_identity()['Account']
    return {
        'AWSAccounts': accounts,
        'AWSSubAccounts': [a for a in accounts if a['Id'] != account_id]
    }
예제 #12
0
def test_session_needs_to_be_set(session):
    AWS._AWS__session = None
    with pytest.raises(AttributeError):
        AWS.current_session()
예제 #13
0
def test_init_with_profile_and_region(session, botocore_session):
    AWS.initialize(profile=PROFILE, region=REGION)
    botocore_session.assert_called_with(profile=PROFILE)
    session.assert_called_with(botocore_session=botocore_session(),
                               region_name=REGION)
예제 #14
0
def test_init_with_profile(session, botocore_session):
    AWS.initialize(profile=PROFILE)
    botocore_session.assert_called_with(profile=PROFILE)
    session.assert_called_with(botocore_session=botocore_session())
예제 #15
0
def test_init_with_region(session, botocore_session):
    AWS.initialize(region=REGION)
    session.assert_called_with(botocore_session=botocore_session(),
                               region_name=REGION)
예제 #16
0
def test_init_without_parameters(session, botocore_session):
    AWS.initialize()
    session.assert_called_with(botocore_session=botocore_session())
예제 #17
0
파일: cli.py 프로젝트: ryansb/formica
def describe(args):
    client = AWS.current_session().client('cloudformation')
    change_set = ChangeSet(stack=args.stack, client=client)
    change_set.describe()
예제 #18
0
파일: change_set.py 프로젝트: muja/formica
    def create(self,
               template,
               change_set_type,
               parameters=[],
               tags=[],
               capabilities=[],
               role_arn=None,
               s3=False):
        optional_arguments = {}
        if parameters:
            optional_arguments['Parameters'] = [{
                'ParameterKey': key,
                'ParameterValue': value,
                'UsePreviousValue': False
            } for (key, value) in parameters.items()]
        if tags:
            optional_arguments['Tags'] = [{
                'Key': key,
                'Value': value,
            } for (key, value) in tags.items()]
        if role_arn:
            optional_arguments['RoleARN'] = role_arn
        if capabilities:
            optional_arguments['Capabilities'] = capabilities
        if change_set_type == 'UPDATE':
            self.remove_existing_changeset()

        try:
            if s3:
                session = AWS.current_session()
                s3_client = session.client('s3')
                bucket_name = 'formica-deploy-{}'.format(
                    str(uuid.uuid4()).lower())
                bucket_path = '{}-template.json'.format(self.stack)
                logger.info('Creating Bucket: {}'.format(bucket_name))

                s3_client.create_bucket(
                    Bucket=bucket_name,
                    CreateBucketConfiguration=dict(
                        LocationConstraint=session.region_name))

                logger.info('Uploading to bucket: {}/{}'.format(
                    bucket_name, bucket_path))
                s3_client.put_object(Bucket=bucket_name,
                                     Key=bucket_path,
                                     Body=template)
                template_url = 'https://{}.s3.amazonaws.com/{}'.format(
                    bucket_name, bucket_path)
                optional_arguments['TemplateURL'] = template_url
            else:
                optional_arguments['TemplateBody'] = template

            self.client.create_change_set(StackName=self.stack,
                                          ChangeSetName=self.name,
                                          ChangeSetType=change_set_type,
                                          **optional_arguments)
            logger.info(
                'Change set submitted, waiting for CloudFormation to calculate changes ...'
            )
            waiter = self.client.get_waiter('change_set_create_complete')
            waiter.wait(ChangeSetName=self.name, StackName=self.stack)
            logger.info('Change set created successfully')
        except WaiterError as e:
            status_reason = e.last_response.get('StatusReason', '')
            logger.info(status_reason)
            if "didn't contain changes" not in status_reason:
                sys.exit(1)
        finally:
            if s3:
                logger.info('Deleting Object and Bucket: {}/{}'.format(
                    bucket_name, bucket_path))
                s3_client.delete_object(Bucket=bucket_name, Key=bucket_path)
                s3_client.delete_bucket(Bucket=bucket_name)
예제 #19
0
def test_init_with_profile(session):
    AWS.initialize(profile=PROFILE)
    session.assert_called_with(profile_name=PROFILE)
예제 #20
0
def test_init_with_region(session):
    AWS.initialize(region=REGION)
    session.assert_called_with(region_name=REGION)
예제 #21
0
파일: cli.py 프로젝트: ryansb/formica
def diff(args):
    Diff(AWS.current_session()).run(args.stack)
예제 #22
0
def compare_stack(stack, vars=None, parameters={}, tags={}):
    client = AWS.current_session().client('cloudformation')
    template = client.get_template(StackName=stack, )['TemplateBody']

    stack = client.describe_stacks(StackName=stack, )['Stacks'][0]
    __compare(template, stack, vars, parameters, tags)
예제 #23
0
def main_account_id():
    from formica.aws import AWS
    sts = AWS.current_session().client('sts')
    identity = sts.get_caller_identity()
    return identity['Account']
예제 #24
0
def remove_stack_set(args):
    client = AWS.current_session().client('cloudformation')
    client.delete_stack_set(StackSetName=args.stack_set)
    logger.info('Removed StackSet with name {}'.format(args.stack_set))
예제 #25
0
def test_AWS_constructor_cant_be_called(session):
    with pytest.raises(Exception):
        AWS()
예제 #26
0
def add_stack_set_instances(args):
    client = AWS.current_session().client('cloudformation')
    client.create_stack_instances(StackSetName=args.stack_set,
                                  Accounts=args.accounts,
                                  Regions=args.regions)
    logger.info('Added StackSet Instances for StackSet {}'.format(args.stack_set))
예제 #27
0
def test_AWS_is_singleton(session):
    AWS.initialize()
    AWS.current_session()
    AWS.current_session()
    session.assert_called_once()
예제 #28
0
def test_init_without_parameters(session):
    AWS.initialize()
    session.assert_called_with()
예제 #29
0
파일: cli.py 프로젝트: ryansb/formica
def main(cli_args):
    parser = argparse.ArgumentParser()
    parser.add_argument('--version',
                        action='version',
                        version='{}'.format(__version__))
    subparsers = parser.add_subparsers(title='commands',
                                       help='Command to use',
                                       dest='command')
    subparsers.required = True

    # Template Command Arguments
    template_parser = subparsers.add_parser(
        'template', description='Print the current template')
    template_parser.add_argument('-y',
                                 '--yaml',
                                 help="print output as yaml",
                                 action="store_true")
    template_parser.set_defaults(func=template)

    # Stacks Command Arguments
    stacks_parser = subparsers.add_parser('stacks',
                                          description='List all stacks')
    add_aws_arguments(stacks_parser)
    add_config_file_argument(stacks_parser)
    stacks_parser.set_defaults(func=stacks)

    # New Command Arguments
    new_parser = subparsers.add_parser(
        'new', description='Create a change set for a new stack')
    add_aws_arguments(new_parser)
    add_stack_argument(new_parser)
    add_stack_parameters_argument(new_parser)
    add_stack_tags_argument(new_parser)
    add_capabilities_argument(new_parser)
    add_config_file_argument(new_parser)
    new_parser.set_defaults(func=new)

    # Change Command Arguments
    change_parser = subparsers.add_parser(
        'change', description='Create a change set for an existing stack')
    add_aws_arguments(change_parser)
    add_stack_argument(change_parser)
    add_stack_parameters_argument(change_parser)
    add_stack_tags_argument(change_parser)
    add_capabilities_argument(change_parser)
    add_config_file_argument(change_parser)
    change_parser.set_defaults(func=change)

    # Deploy Command Arguments
    deploy_parser = subparsers.add_parser(
        'deploy', description='Deploy the latest change set for a stack')
    add_aws_arguments(deploy_parser)
    add_stack_argument(deploy_parser)
    add_config_file_argument(deploy_parser)
    deploy_parser.set_defaults(func=deploy)

    # Describe Command Arguments
    describe_parser = subparsers.add_parser(
        'describe', description='Describe the latest change-set of the stack')
    add_aws_arguments(describe_parser)
    add_stack_argument(describe_parser)
    add_config_file_argument(describe_parser)
    describe_parser.set_defaults(func=describe)

    # Diff Command Arguments
    diff_parser = subparsers.add_parser(
        'diff', description='Print a diff between local and deployed stack')
    add_aws_arguments(diff_parser)
    add_stack_argument(diff_parser)
    add_config_file_argument(diff_parser)
    diff_parser.set_defaults(func=diff)

    # Resources Command Arguments
    resources_parser = subparsers.add_parser(
        'resources', description='List all resources of a stack')
    add_aws_arguments(resources_parser)
    add_stack_argument(resources_parser)
    add_config_file_argument(resources_parser)
    resources_parser.set_defaults(func=resources)

    # Remove Command Arguments
    remove_parser = subparsers.add_parser(
        'remove', description='Remove the configured stack')
    add_aws_arguments(remove_parser)
    add_stack_argument(remove_parser)
    add_config_file_argument(remove_parser)
    remove_parser.set_defaults(func=remove)

    # Argument Parsing
    args = parser.parse_args(cli_args)
    args_dict = vars(args)

    if args_dict.get('config_file'):
        load_config_file(args, args.config_file)

    try:
        # Initialise the AWS Profile and Region
        AWS.initialize(args_dict.get('region'), args_dict.get('profile'))

        # Execute Function
        if args_dict.get('func'):
            args.func(args)
        else:
            parser.print_usage()
    except (ProfileNotFound, NoCredentialsError, NoRegionError,
            EndpointConnectionError) as e:
        logger.info(
            'Please make sure your credentials, regions and profiles are properly set:'
        )
        logger.info(e)
        sys.exit(1)
    except ClientError as e:
        if e.response['Error']['Code'] == 'ValidationError':
            logger.info(e.response['Error']['Message'])
            sys.exit(1)
        else:
            logger.info(e)
            sys.exit(2)