feat: Prevent blacklisted outputs from being written to output files, add easy stack reset for Pulumi stacks

This commit is contained in:
Stefan Reimer 2022-04-12 13:16:42 +02:00
parent 5db67920f7
commit 4abed82b8a
2 changed files with 24 additions and 8 deletions

View File

@ -153,18 +153,18 @@ def refresh(cb, stack_name):
@click.command() @click.command()
@click.argument("stack_name") @click.argument("stack_name")
@click.option( @click.option(
"--reset", "-r", "--remove-pending-operations",
is_flag=True, is_flag=True,
help="All pending stack operations are removed and the stack will be re-imported", help="All pending stack operations are removed and the stack will be re-imported",
) )
@click.pass_obj @click.pass_obj
def export(cb, stack_name, reset=False): def export(cb, stack_name, remove_pending_operations=False):
"""Exports a Pulumi stack to repair state""" """Exports a Pulumi stack to repair state"""
stacks = _find_stacks(cb, [stack_name]) stacks = _find_stacks(cb, [stack_name])
for s in stacks: for s in stacks:
if s.mode == "pulumi": if s.mode == "pulumi":
s.export(reset) s.export(remove_pending_operations)
else: else:
logger.info("{} uses Cloudformation, export skipped.".format(s.stackname)) logger.info("{} uses Cloudformation, export skipped.".format(s.stackname))

View File

@ -526,6 +526,16 @@ class Stack(object):
) )
ensure_dir(os.path.join(self.ctx["outputs_path"], self.rel_path)) ensure_dir(os.path.join(self.ctx["outputs_path"], self.rel_path))
# Blacklist at least AWS SecretKeys from leaking into git
# Pulumi to the rescue soon
blacklist = [".*SecretAccessKey.*"]
sanitized_outputs = {}
for k in self.outputs.keys():
sanitized_outputs[k] = self.outputs[k]
for val in blacklist:
if re.match(val, k, re.IGNORECASE):
sanitized_outputs[k] = "<Redacted>"
jenv = JinjaEnv() jenv = JinjaEnv()
template = jenv.from_string(my_template) template = jenv.from_string(my_template)
data = { data = {
@ -533,7 +543,7 @@ class Stack(object):
"timestamp": datetime.strftime( "timestamp": datetime.strftime(
datetime.now(tzutc()), "%d/%m/%y %H:%M" datetime.now(tzutc()), "%d/%m/%y %H:%M"
), ),
"outputs": self.outputs, "outputs": sanitized_outputs,
"parameters": self.parameters, "parameters": self.parameters,
} }
@ -840,7 +850,7 @@ class Stack(object):
def preview(self): def preview(self):
"""Preview a Pulumi stack up operation""" """Preview a Pulumi stack up operation"""
pulumi_init(self).preview(on_output=self._log_pulumi) pulumi_init(self, create=True).preview(on_output=self._log_pulumi)
return return
@ -852,19 +862,25 @@ class Stack(object):
# now lets import each defined resource # now lets import each defined resource
for r in self._pulumi_code.RESOURCES: for r in self._pulumi_code.RESOURCES:
args = ["import", r["type"], r["name"], r["id"], "--yes"] r_id = r["id"]
if not r_id:
r_id = input("Please enter ID for {} ({}):".format(r["name"], r["type"]))
logger.info("Importing {} ({}) as {}".format(r_id, r["type"], r["name"]))
args = ["import", r["type"], r["name"], r_id, "--yes"]
pulumi_stack._run_pulumi_cmd_sync(args) pulumi_stack._run_pulumi_cmd_sync(args)
return return
@pulumi_ws @pulumi_ws
def export(self, reset): def export(self, remove_pending_operations):
"""Exports a Pulumi stack""" """Exports a Pulumi stack"""
pulumi_stack = pulumi_init(self) pulumi_stack = pulumi_init(self)
deployment = pulumi_stack.export_stack() deployment = pulumi_stack.export_stack()
if reset: if remove_pending_operations:
deployment.deployment.pop("pending_operations", None) deployment.deployment.pop("pending_operations", None)
pulumi_stack.import_stack(deployment) pulumi_stack.import_stack(deployment)
logger.info("Removed all pending_operations from %s" % self.stackname) logger.info("Removed all pending_operations from %s" % self.stackname)