diff --git a/cloudbender/cli.py b/cloudbender/cli.py index eca8649..5f26b2e 100644 --- a/cloudbender/cli.py +++ b/cloudbender/cli.py @@ -143,6 +143,21 @@ def refresh(cb, stack_name): logger.info('{} uses Cloudformation, refresh skipped.'.format(s.stackname)) +@click.command() +@click.argument("stack_name") +@click.option("--reset", is_flag=True, help="All pending stack operations are removed and the stack will be re-imported") +@click.pass_obj +def export(cb, stack_name, reset=False): + """ Exports a Pulumi stack to repair state """ + stacks = _find_stacks(cb, [stack_name]) + + for s in stacks: + if s.mode == 'pulumi': + s.export(reset) + else: + logger.info('{} uses Cloudformation, export skipped.'.format(s.stackname)) + + @click.command() @click.argument("stack_name") @click.argument("key") @@ -331,6 +346,7 @@ cli.add_command(refresh) cli.add_command(preview) cli.add_command(set_config) cli.add_command(get_config) +cli.add_command(export) if __name__ == '__main__': cli(obj={}) diff --git a/cloudbender/stack.py b/cloudbender/stack.py index 529d1bb..26661c3 100644 --- a/cloudbender/stack.py +++ b/cloudbender/stack.py @@ -1,6 +1,7 @@ import os import re import hashlib +import json import yaml import time import pathlib @@ -387,6 +388,11 @@ class Stack(object): stack = pulumi_init(self) self.outputs = stack.outputs() + # If secrets replace with clear values for now + for k in self.outputs.keys(): + if self.outputs[k].secret: + self.outputs[k] = self.outputs[k].value + else: self.read_template_file() try: @@ -664,6 +670,22 @@ class Stack(object): return + @pulumi_ws + def export(self, reset): + """ Exports a Pulumi stack """ + + stack = pulumi_init(self) + deployment = stack.export_stack() + + if reset: + deployment.deployment.pop('pending_operations', None) + stack.import_stack(deployment) + logger.info('Removed all pending_operations from %s' % self.stackname) + else: + print(json.dumps(deployment.deployment)) + + return + @pulumi_ws def set_config(self, key, value, secret): """ Set a config or secret """