feat: add assimilate task to import resources into Pulumi stacks, various Pulumi related fixes
This commit is contained in:
parent
4196b54a20
commit
5db67920f7
@ -1,6 +1,6 @@
|
|||||||
ARG RUNTIME_VERSION="3.7"
|
ARG RUNTIME_VERSION="3.7"
|
||||||
ARG DISTRO_VERSION="3.15"
|
ARG DISTRO_VERSION="3.15"
|
||||||
ARG PULUMI_VERSION="3.24.1"
|
ARG PULUMI_VERSION="3.26.1"
|
||||||
|
|
||||||
FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS builder
|
FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS builder
|
||||||
ARG PULUMI_VERSION
|
ARG PULUMI_VERSION
|
||||||
|
@ -169,6 +169,22 @@ def export(cb, stack_name, reset=False):
|
|||||||
logger.info("{} uses Cloudformation, export skipped.".format(s.stackname))
|
logger.info("{} uses Cloudformation, export skipped.".format(s.stackname))
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.argument("stack_name")
|
||||||
|
@click.pass_obj
|
||||||
|
def assimilate(cb, stack_name):
|
||||||
|
"""Imports potentially existing resources into Pulumi stack"""
|
||||||
|
stacks = _find_stacks(cb, [stack_name])
|
||||||
|
|
||||||
|
for s in stacks:
|
||||||
|
if s.mode == "pulumi":
|
||||||
|
s.assimilate()
|
||||||
|
else:
|
||||||
|
logger.info(
|
||||||
|
"{} uses Cloudformation, cannot assimilate.".format(s.stackname)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.argument("stack_name")
|
@click.argument("stack_name")
|
||||||
@click.argument("key")
|
@click.argument("key")
|
||||||
@ -391,6 +407,7 @@ cli.add_command(preview)
|
|||||||
cli.add_command(set_config)
|
cli.add_command(set_config)
|
||||||
cli.add_command(get_config)
|
cli.add_command(get_config)
|
||||||
cli.add_command(export)
|
cli.add_command(export)
|
||||||
|
cli.add_command(assimilate)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cli(obj={})
|
cli(obj={})
|
||||||
|
@ -11,7 +11,7 @@ import logging
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def pulumi_init(stack):
|
def pulumi_init(stack, create=False):
|
||||||
|
|
||||||
# Fail early if pulumi binaries are not available
|
# Fail early if pulumi binaries are not available
|
||||||
if not shutil.which("pulumi"):
|
if not shutil.which("pulumi"):
|
||||||
@ -51,6 +51,8 @@ def pulumi_init(stack):
|
|||||||
"Cannot find Pulumi implementation for {}".format(stack.stackname)
|
"Cannot find Pulumi implementation for {}".format(stack.stackname)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Store internal pulumi code reference
|
||||||
|
stack._pulumi_code = _stack
|
||||||
project_name = stack.parameters["Conglomerate"]
|
project_name = stack.parameters["Conglomerate"]
|
||||||
|
|
||||||
# Remove stacknameprefix if equals Conglomerate as Pulumi implicitly prefixes project_name
|
# Remove stacknameprefix if equals Conglomerate as Pulumi implicitly prefixes project_name
|
||||||
@ -102,8 +104,10 @@ def pulumi_init(stack):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
if _stack.IKNOWHATIDO:
|
if stack._pulumi_code.IKNOWHATIDO:
|
||||||
logger.warning("Missing pulumi.secretsProvider setting, IKNOWHATIDO enabled ... ")
|
logger.warning(
|
||||||
|
"Missing pulumi.secretsProvider setting, IKNOWHATIDO enabled ... "
|
||||||
|
)
|
||||||
secrets_provider = None
|
secrets_provider = None
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ValueError("Missing pulumi.secretsProvider setting!")
|
raise ValueError("Missing pulumi.secretsProvider setting!")
|
||||||
@ -111,12 +115,12 @@ def pulumi_init(stack):
|
|||||||
# Set tag for stack file name and version
|
# Set tag for stack file name and version
|
||||||
_tags = stack.tags
|
_tags = stack.tags
|
||||||
try:
|
try:
|
||||||
_version = _stack.VERSION
|
_version = stack._pulumi_code.VERSION
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
_version = "undefined"
|
_version = "undefined"
|
||||||
|
|
||||||
_tags["zero-downtime.net/cloudbender"] = "{}:{}".format(
|
_tags["zero-downtime.net/cloudbender"] = "{}:{}".format(
|
||||||
os.path.basename(_stack.__file__), _version
|
os.path.basename(stack._pulumi_code.__file__), _version
|
||||||
)
|
)
|
||||||
|
|
||||||
_config = {
|
_config = {
|
||||||
@ -151,14 +155,23 @@ def pulumi_init(stack):
|
|||||||
secrets_provider=secrets_provider,
|
secrets_provider=secrets_provider,
|
||||||
)
|
)
|
||||||
|
|
||||||
stack = pulumi.automation.create_or_select_stack(
|
if create:
|
||||||
stack_name=pulumi_stackname,
|
pulumi_stack = pulumi.automation.create_or_select_stack(
|
||||||
project_name=project_name,
|
stack_name=pulumi_stackname,
|
||||||
program=_stack.pulumi_program,
|
project_name=project_name,
|
||||||
opts=ws_opts,
|
program=stack._pulumi_code.pulumi_program,
|
||||||
)
|
opts=ws_opts,
|
||||||
stack.workspace.install_plugin(
|
)
|
||||||
"aws", pkg_resources.get_distribution("pulumi_aws").version
|
pulumi_stack.workspace.install_plugin(
|
||||||
)
|
"aws", pkg_resources.get_distribution("pulumi_aws").version
|
||||||
|
)
|
||||||
|
|
||||||
return stack
|
else:
|
||||||
|
pulumi_stack = pulumi.automation.select_stack(
|
||||||
|
stack_name=pulumi_stackname,
|
||||||
|
project_name=project_name,
|
||||||
|
program=stack._pulumi_code.pulumi_program,
|
||||||
|
opts=ws_opts,
|
||||||
|
)
|
||||||
|
|
||||||
|
return pulumi_stack
|
||||||
|
@ -83,6 +83,7 @@ class Stack(object):
|
|||||||
self.template_bucket_url = None
|
self.template_bucket_url = None
|
||||||
self.work_dir = None
|
self.work_dir = None
|
||||||
self.pulumi = {}
|
self.pulumi = {}
|
||||||
|
self._pulumi_stack = None
|
||||||
|
|
||||||
def dump_config(self):
|
def dump_config(self):
|
||||||
logger.debug("<Stack {}: {}>".format(self.id, pprint.pformat(vars(self))))
|
logger.debug("<Stack {}: {}>".format(self.id, pprint.pformat(vars(self))))
|
||||||
@ -483,8 +484,7 @@ class Stack(object):
|
|||||||
"""gets outputs of the stack"""
|
"""gets outputs of the stack"""
|
||||||
|
|
||||||
if self.mode == "pulumi":
|
if self.mode == "pulumi":
|
||||||
stack = pulumi_init(self)
|
self.outputs = pulumi_init(self).outputs()
|
||||||
self.outputs = stack.outputs()
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.read_template_file()
|
self.read_template_file()
|
||||||
@ -545,7 +545,7 @@ class Stack(object):
|
|||||||
|
|
||||||
# If secrets replace with clear values for now, display ONLY
|
# If secrets replace with clear values for now, display ONLY
|
||||||
for k in self.outputs.keys():
|
for k in self.outputs.keys():
|
||||||
if hasattr(self.outputs[k], 'secret') and self.outputs[k].secret:
|
if hasattr(self.outputs[k], "secret") and self.outputs[k].secret:
|
||||||
self.outputs[k] = self.outputs[k].value
|
self.outputs[k] = self.outputs[k].value
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
@ -713,8 +713,7 @@ class Stack(object):
|
|||||||
"""Creates a stack"""
|
"""Creates a stack"""
|
||||||
|
|
||||||
if self.mode == "pulumi":
|
if self.mode == "pulumi":
|
||||||
stack = pulumi_init(self)
|
pulumi_init(self, create=True).up(on_output=self._log_pulumi)
|
||||||
stack.up(on_output=self._log_pulumi)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Prepare parameters
|
# Prepare parameters
|
||||||
@ -812,8 +811,9 @@ class Stack(object):
|
|||||||
logger.info("Deleting {0} {1}".format(self.region, self.stackname))
|
logger.info("Deleting {0} {1}".format(self.region, self.stackname))
|
||||||
|
|
||||||
if self.mode == "pulumi":
|
if self.mode == "pulumi":
|
||||||
stack = pulumi_init(self)
|
pulumi_stack = pulumi_init(self)
|
||||||
stack.destroy(on_output=self._log_pulumi)
|
pulumi_stack.destroy(on_output=self._log_pulumi)
|
||||||
|
pulumi_stack.workspace.remove_stack(pulumi_stack.name)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -832,8 +832,7 @@ class Stack(object):
|
|||||||
def refresh(self):
|
def refresh(self):
|
||||||
"""Refreshes a Pulumi stack"""
|
"""Refreshes a Pulumi stack"""
|
||||||
|
|
||||||
stack = pulumi_init(self)
|
pulumi_init(self).refresh(on_output=self._log_pulumi)
|
||||||
stack.refresh(on_output=self._log_pulumi)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -841,8 +840,20 @@ class Stack(object):
|
|||||||
def preview(self):
|
def preview(self):
|
||||||
"""Preview a Pulumi stack up operation"""
|
"""Preview a Pulumi stack up operation"""
|
||||||
|
|
||||||
stack = pulumi_init(self)
|
pulumi_init(self).preview(on_output=self._log_pulumi)
|
||||||
stack.preview(on_output=self._log_pulumi)
|
|
||||||
|
return
|
||||||
|
|
||||||
|
@pulumi_ws
|
||||||
|
def assimilate(self):
|
||||||
|
"""Import resources into Pulumi stack"""
|
||||||
|
|
||||||
|
pulumi_stack = pulumi_init(self, create=True)
|
||||||
|
|
||||||
|
# now lets import each defined resource
|
||||||
|
for r in self._pulumi_code.RESOURCES:
|
||||||
|
args = ["import", r["type"], r["name"], r["id"], "--yes"]
|
||||||
|
pulumi_stack._run_pulumi_cmd_sync(args)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -850,12 +861,12 @@ class Stack(object):
|
|||||||
def export(self, reset):
|
def export(self, reset):
|
||||||
"""Exports a Pulumi stack"""
|
"""Exports a Pulumi stack"""
|
||||||
|
|
||||||
stack = pulumi_init(self)
|
pulumi_stack = pulumi_init(self)
|
||||||
deployment = stack.export_stack()
|
deployment = pulumi_stack.export_stack()
|
||||||
|
|
||||||
if reset:
|
if reset:
|
||||||
deployment.deployment.pop("pending_operations", None)
|
deployment.deployment.pop("pending_operations", None)
|
||||||
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)
|
||||||
else:
|
else:
|
||||||
print(json.dumps(deployment.deployment))
|
print(json.dumps(deployment.deployment))
|
||||||
@ -866,12 +877,14 @@ class Stack(object):
|
|||||||
def set_config(self, key, value, secret):
|
def set_config(self, key, value, secret):
|
||||||
"""Set a config or secret"""
|
"""Set a config or secret"""
|
||||||
|
|
||||||
stack = pulumi_init(self)
|
pulumi_stack = pulumi_init(self, create=True)
|
||||||
stack.set_config(key, pulumi.automation.ConfigValue(value, secret))
|
pulumi_stack.set_config(key, pulumi.automation.ConfigValue(value, secret))
|
||||||
|
|
||||||
# Store salt or key and encrypted value in CloudBender stack config
|
# Store salt or key and encrypted value in CloudBender stack config
|
||||||
settings = None
|
settings = None
|
||||||
pulumi_settings = stack.workspace.stack_settings(stack.name)._serialize()
|
pulumi_settings = pulumi_stack.workspace.stack_settings(
|
||||||
|
pulumi_stack.name
|
||||||
|
)._serialize()
|
||||||
|
|
||||||
with open(self.path, "r") as file:
|
with open(self.path, "r") as file:
|
||||||
settings = yaml.safe_load(file)
|
settings = yaml.safe_load(file)
|
||||||
@ -899,8 +912,7 @@ class Stack(object):
|
|||||||
def get_config(self, key):
|
def get_config(self, key):
|
||||||
"""Get a config or secret"""
|
"""Get a config or secret"""
|
||||||
|
|
||||||
stack = pulumi_init(self)
|
print(pulumi_init(self).get_config(key).value)
|
||||||
print(stack.get_config(key).value)
|
|
||||||
|
|
||||||
def create_change_set(self, change_set_name):
|
def create_change_set(self, change_set_name):
|
||||||
"""Creates a Change Set with the name ``change_set_name``."""
|
"""Creates a Change Set with the name ``change_set_name``."""
|
||||||
|
Loading…
Reference in New Issue
Block a user