diff --git a/CHANGELOG.md b/CHANGELOG.md index df88f78..5c4fceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.0.6 (March 30, 2020) + +FEATURES: + +* Add `--output` option for displaying stack outputs and show by default the outputs of the stack (if defined) during apply + ## 1.0.5 (March 13, 2020) BUG FIXES: diff --git a/README.md b/README.md index 9d33d45..5e8e305 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ pip install git+git://github.com/jeremietharaud/aws-cfn-cli.git When using Docker image, you can run `cfncli` using the following command: ``` -docker run --rm -i -e AWS_ACCESS_KEY_ID= -e AWS_SECRET_ACCESS_KEY= -e AWS_REGION= -v $PWD:/data jeremietharaud/cfncli cfncli +docker run --rm -i -v $PWD:/data jeremietharaud/cfncli cfncli ``` When using the python script directly: @@ -37,30 +37,32 @@ cfncli option `cfncli` takes into account multiple arguments: - * --stack-file stack-file (REQUIRED): name or path of the CFN stack file + * --stack-file stack-file (REQUIRED): Name or path of the CFN stack file - * --var Key=Value : list of CFN stack parameters in key=value format and separated by comma + * --var Key=Value : List of CFN stack parameters in key=value format and separated by comma - * --tags Key=Value : list of CFN tags parameters in key=value format and separated by comma + * --tags Key=Value : List of CFN tags parameters in key=value format and separated by comma - * --var-file var-file: name or path of the file containing variables of the stack. File must be whether in Json (list of ParameterKey/ParameterValue) or in Yaml format. If Yaml file, it should contain at least one of these section: `Name`, `Tags` or `Variables`. Note that this option will override --name, --var and --tags options. + * --var-file var-file: Name or path of the file containing variables of the stack. File must be whether in Json (list of ParameterKey/ParameterValue) or in Yaml format. If Yaml file, it should contain at least one of these section: `Name`, `Tags` or `Variables`. Note that this option will override --name, --var and --tags options. - * --name stack-name: name of the stack to deploy. By default, it uses the stack file name (without extension) + * --name stack-name: Name of the stack to deploy. By default, it uses the stack file name (without extension) - * --assume-role-arn: arn of the AWS IAM role to assume for receiving temporary permissions + * --assume-role-arn: Arn of the AWS IAM role to assume for receiving temporary permissions - * --plan: for planning changes on a CFN stack (already existing or new stack). It generates a change set and displays the changes. + * --plan: For planning changes on a CFN stack (already existing or new stack). It generates a change set and displays the changes. - * --apply: for applying changes on a CFN stack. A change set is generated then executed. + * --apply: For applying changes on a CFN stack. A change set is generated then executed. - * --destroy: for deleting a CFN stack. It displays the list of resources that are going to be removed. `--auto-approve` option is mandatory. + * --destroy: For deleting a CFN stack. It displays the list of resources that are going to be removed. `--auto-approve` option is mandatory. - * --auto-approve: option to be combined with `--delete` option for approving deletion of a stack. + * --auto-approve: Option to be combined with `--delete` option for approving deletion of a stack. - * --region: Name of the region to deploy the stack. If not set, it uses the region of your AWS profile. + * --region: aame of the region to deploy the stack. If not set, it uses the region of your AWS profile. * --validate: Validate the syntax of the stack file. + * --output: Displays outputs of the stack. + ## Default timeout The default timeout for the creation/update/deletion of a stack is `30` minutes. diff --git a/cfncli/.flake8 b/cfncli/.flake8 index ea97c3a..1fd4893 100644 --- a/cfncli/.flake8 +++ b/cfncli/.flake8 @@ -1,2 +1,2 @@ [flake8] -max-line-length = 140 +max-line-length = 160 diff --git a/cfncli/__init__.py b/cfncli/__init__.py index 858de17..da2182f 100644 --- a/cfncli/__init__.py +++ b/cfncli/__init__.py @@ -1 +1 @@ -__version__ = '1.0.5' +__version__ = '1.0.6' diff --git a/cfncli/cfncli.py b/cfncli/cfncli.py index 0180f95..ccbbfc6 100644 --- a/cfncli/cfncli.py +++ b/cfncli/cfncli.py @@ -218,7 +218,7 @@ def wait_create_or_update_cfn_stack(stack_name: str, client: Client, timeout: in if 'StackStatusReason' in stack: logger.error(stack['StackStatusReason']) else: - logger.error("%s has failed..." % (operation) ) + logger.error("%s has failed..." % (operation)) wait_rollback_cfn_stack(stack_name=stack_name, client=client, timeout=timeout) exit(1) if stack_status in ['CREATE_COMPLETE', 'UPDATE_COMPLETE']: @@ -320,6 +320,16 @@ def delete_cfn_stack(stack_name: str, client: Client, silent: bool) -> None: wait_deletion_cfn_stack(stack_name=stack_name, client=client, timeout=1800, silent=silent) +def display_outputs(stack_name: str, client: Client) -> None: + stack = get_cfn_stack(stack_name=stack_name, client=client) + if 'Outputs' in stack: + outputs = stack['Outputs'] + output_list = '' + for output in outputs: + output_list += ' %s = %s' % (output['ExportName'], output['OutputValue']) + logger.info('\nOutputs:\n\n' + output_list) + + def validate(stack_name: str, stack_file: str, client: Client) -> None: logger.info("Starting plan of the stack %s" % (stack_name)) with open(stack_file, 'r') as template: @@ -378,7 +388,6 @@ def apply(stack_name: str, change_set_name: str, change_set_type: str, client: C execute_change_set_cfn(stack_name=stack_name, change_set_name=change_set_name, client=client) wait_create_or_update_cfn_stack(stack_name=stack_name, client=client, timeout=1800, operation='Update') logger.info("Stack updated") - def destroy(stack_name: str, client: Client, auto_approve: bool) -> None: @@ -428,6 +437,7 @@ def main(): parser.add_argument('--apply', action="store_true", help='Launch the deployment of the stack') parser.add_argument('--destroy', action="store_true", help='Launch the deletion of the stack') parser.add_argument('--auto-approve', action="store_true", help='Auto approve the deployment') + parser.add_argument('--output', action="store_true", help='Show stack output') args = parser.parse_args() @@ -493,6 +503,17 @@ def main(): (change_set, change_set_type) = plan(stack_name=stack_name, stack_file=args.stack_file, client=client, keep_plan=True, params=params, tags=tags) if change_set is not None: apply(stack_name=stack_name, change_set_name=change_set, change_set_type=change_set_type, client=client, auto_approve=args.auto_approve) + display_outputs(stack_name=stack_name, client=client) + exit(0) + + if args.output: + client = get_cfn_client_session(region=args.region, assume_role_arn=args.assume_role_arn) + stack = get_cfn_stack(stack_name=stack_name, client=client) + if stack is not None: + display_outputs(stack_name=stack_name, client=client) + else: + logger.error('Stack not found.') + exit(1) exit(0) if args.destroy: