diff --git a/cloudbender/__init__.py b/cloudbender/__init__.py index fd1a756..d339915 100644 --- a/cloudbender/__init__.py +++ b/cloudbender/__init__.py @@ -2,7 +2,7 @@ import logging __author__ = 'Stefan Reimer' __email__ = 'stefan@zero-downtimet.net' -__version__ = '1.1.1' +__version__ = '1.2.0' # Set up logging to ``/dev/null`` like a library is supposed to. diff --git a/cloudbender/cli.py b/cloudbender/cli.py index 7b4539b..f038da7 100644 --- a/cloudbender/cli.py +++ b/cloudbender/cli.py @@ -28,13 +28,13 @@ def cli(ctx, debug, directory): @click.command() -@click.argument("stack_name") +@click.argument("stack_names", nargs=-1) @click.option("--multi", is_flag=True, help="Allow more than one stack to match") @click.pass_context -def render(ctx, stack_name, multi): +def render(ctx, stack_names, multi): """ Renders template and its parameters """ - stacks = _find_stacks(ctx, stack_name, multi) + stacks = _find_stacks(ctx, stack_names, multi) for s in stacks: s.render() @@ -42,12 +42,12 @@ def render(ctx, stack_name, multi): @click.command() -@click.argument("stack_name") +@click.argument("stack_names", nargs=-1) @click.option("--multi", is_flag=True, help="Allow more than one stack to match") @click.pass_context -def validate(ctx, stack_name, multi): +def validate(ctx, stack_names, multi): """ Validates already rendered templates using cfn-lint """ - stacks = _find_stacks(ctx, stack_name, multi) + stacks = _find_stacks(ctx, stack_names, multi) for s in stacks: s.validate() @@ -59,19 +59,20 @@ def validate(ctx, stack_name, multi): @click.pass_context def create_change_set(ctx, stack_name, change_set_name): """ Creates a change set for an existing stack """ - stacks = _find_stacks(ctx, stack_name) + stacks = _find_stacks(ctx, [stack_name]) for s in stacks: s.create_change_set(change_set_name) @click.command() -@click.argument("stack_name") +@click.argument("stack_names", nargs=-1) @click.option("--multi", is_flag=True, help="Allow more than one stack to match") @click.pass_context -def provision(ctx, stack_name, multi): +def provision(ctx, stack_names, multi): """ Creates or updates stacks or stack groups """ - stacks = _find_stacks(ctx, stack_name, multi) + + stacks = _find_stacks(ctx, stack_names, multi) for step in sort_stacks(ctx, stacks): if step: @@ -89,12 +90,12 @@ def provision(ctx, stack_name, multi): @click.command() -@click.argument("stack_name") +@click.argument("stack_names", nargs=-1) @click.option("--multi", is_flag=True, help="Allow more than one stack to match") @click.pass_context -def delete(ctx, stack_name, multi): +def delete(ctx, stack_names, multi): """ Deletes stacks or stack groups """ - stacks = _find_stacks(ctx, stack_name, multi) + stacks = _find_stacks(ctx, stack_names, multi) # Reverse steps steps = [s for s in sort_stacks(ctx, stacks)] @@ -156,22 +157,19 @@ def sort_stacks(ctx, stacks): assert not data, "A cyclic dependency exists amongst %r" % data -def _find_stacks(ctx, stack_name,multi=False): +def _find_stacks(ctx, stack_names, multi=False): cb = ctx.obj['cb'] - # ALL acts ass config and multi=True - if stack_name == "ALL": - multi = True - stack_name = "config" - - stacks = cb.resolve_stacks(stack_name) - - if not stacks: - logger.error('Cannot find stack matching: {}'.format(stack_name)) - raise click.Abort() + stacks = [] + for s in stack_names: + stacks = stacks+cb.resolve_stacks(s) if not multi and len(stacks) > 1: - logger.error('Found more than one ({}) stacks matching name {}: {}. Abort.'.format(len(stacks), stack_name, [s.stackname for s in stacks])) + logger.error('Found more than one stack matching name ({}). Please set --multi if that is what you want.'.format(', '.join(stack_names))) + raise click.Abort() + + if not stacks: + logger.error('Cannot find stack matching: {}'.format(', '.join(stack_names))) raise click.Abort() return stacks diff --git a/cloudbender/stack.py b/cloudbender/stack.py index f93a965..b332bf5 100644 --- a/cloudbender/stack.py +++ b/cloudbender/stack.py @@ -314,7 +314,7 @@ class Stack(object): if not self.cfn_template: self.read_template_file() - logger.info('Creating {0}'.format(self.stackname)) + logger.info('Creating {0} {1}'.format(self.region, self.stackname)) response = self.connection_manager.call('cloudformation', 'create_stack', {'StackName':self.stackname, 'TemplateBody':self.cfn_template, @@ -336,7 +336,7 @@ class Stack(object): if not self.cfn_template: self.read_template_file() - logger.info('Updating {0}'.format(self.stackname)) + logger.info('Updating {0} {1}'.format(self.region, self.stackname)) try: response = self.connection_manager.call('cloudformation', 'update_stack', {'StackName':self.stackname, @@ -359,7 +359,7 @@ class Stack(object): def delete(self): """Deletes a stack """ - logger.info('Deleting {0}'.format(self.stackname)) + logger.info('Deleting {0} {1}'.format(self.region, self.stackname)) response = self.connection_manager.call('cloudformation', 'delete_stack', {'StackName':self.stackname}, profile=self.profile, region=self.region) @@ -493,6 +493,7 @@ class Stack(object): ] for event in new_events: logger.info(" ".join([ + self.region, self.stackname, event["LogicalResourceId"], event["ResourceType"],