2021-09-20 14:19:14 +00:00
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import shutil
|
|
|
|
import importlib
|
2021-09-23 17:27:06 +00:00
|
|
|
import pkg_resources
|
2021-09-20 14:19:14 +00:00
|
|
|
import pulumi
|
|
|
|
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
def pulumi_init(stack):
|
|
|
|
|
|
|
|
# Fail early if pulumi binaries are not available
|
|
|
|
if not shutil.which('pulumi'):
|
|
|
|
raise FileNotFoundError("Cannot find pulumi binary, see https://www.pulumi.com/docs/get-started/install/")
|
|
|
|
|
|
|
|
# add all artifact_paths/pulumi to the search path for easier imports in the pulumi code
|
|
|
|
for artifacts_path in stack.ctx['artifact_paths']:
|
|
|
|
_path = '{}/pulumi'.format(artifacts_path.resolve())
|
|
|
|
sys.path.append(_path)
|
|
|
|
|
|
|
|
# Try local implementation first, similar to Jinja2 mode
|
|
|
|
_found = False
|
|
|
|
try:
|
|
|
|
_stack = importlib.import_module('config.{}.{}'.format(stack.rel_path, stack.template).replace('/', '.'))
|
|
|
|
_found = True
|
|
|
|
|
|
|
|
except ImportError:
|
|
|
|
for artifacts_path in stack.ctx['artifact_paths']:
|
|
|
|
try:
|
|
|
|
spec = importlib.util.spec_from_file_location("_stack", '{}/pulumi/{}.py'.format(artifacts_path.resolve(), stack.template))
|
|
|
|
_stack = importlib.util.module_from_spec(spec)
|
|
|
|
spec.loader.exec_module(_stack)
|
|
|
|
_found = True
|
|
|
|
|
|
|
|
except FileNotFoundError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
if not _found:
|
|
|
|
raise FileNotFoundError("Cannot find Pulumi implementation for {}".format(stack.stackname))
|
|
|
|
|
|
|
|
project_name = stack.parameters['Conglomerate']
|
|
|
|
|
|
|
|
# Remove stacknameprefix if equals Conglomerate as Pulumi implicitly prefixes project_name
|
|
|
|
pulumi_stackname = re.sub(r'^' + project_name + '-?', '', stack.stackname)
|
2021-10-04 15:51:16 +00:00
|
|
|
try:
|
|
|
|
pulumi_backend = '{}/{}/{}'.format(stack.pulumi['backend'], project_name, stack.region)
|
|
|
|
|
|
|
|
except KeyError:
|
|
|
|
raise KeyError('Missing pulumi.backend setting !')
|
2021-09-20 14:19:14 +00:00
|
|
|
|
|
|
|
account_id = stack.connection_manager.call('sts', 'get_caller_identity', profile=stack.profile, region=stack.region)['Account']
|
|
|
|
# Ugly hack as Pulumi currently doesnt support MFA_TOKENs during role assumptions
|
|
|
|
# Do NOT set them via 'aws:secretKey' as they end up in the stack.json in plain text !!!
|
|
|
|
if stack.connection_manager._sessions[(stack.profile, stack.region)].get_credentials().token:
|
|
|
|
os.environ['AWS_SESSION_TOKEN'] = stack.connection_manager._sessions[(stack.profile, stack.region)].get_credentials().token
|
|
|
|
|
|
|
|
os.environ['AWS_ACCESS_KEY_ID'] = stack.connection_manager._sessions[(stack.profile, stack.region)].get_credentials().access_key
|
|
|
|
os.environ['AWS_SECRET_ACCESS_KEY'] = stack.connection_manager._sessions[(stack.profile, stack.region)].get_credentials().secret_key
|
2021-10-04 15:51:16 +00:00
|
|
|
os.environ['AWS_DEFAULT_REGION'] = stack.region
|
2021-09-20 14:19:14 +00:00
|
|
|
|
|
|
|
# Secrets provider
|
|
|
|
try:
|
|
|
|
secrets_provider = stack.pulumi['secretsProvider']
|
|
|
|
if secrets_provider == 'passphrase' and 'PULUMI_CONFIG_PASSPHRASE' not in os.environ:
|
|
|
|
raise ValueError('Missing PULUMI_CONFIG_PASSPHRASE environment variable!')
|
|
|
|
|
|
|
|
except KeyError:
|
2021-10-04 15:51:16 +00:00
|
|
|
logger.warning('Missing pulumi.secretsProvider setting, secrets disabled !')
|
|
|
|
secrets_provider = None
|
2021-09-20 14:19:14 +00:00
|
|
|
|
2021-09-23 17:27:06 +00:00
|
|
|
# Set tag for stack file name and version
|
|
|
|
_tags = stack.tags
|
|
|
|
try:
|
|
|
|
_version = _stack.VERSION
|
|
|
|
except AttributeError:
|
|
|
|
_version = 'undefined'
|
|
|
|
|
|
|
|
_tags['zero-downtime.net/cloudbender'] = '{}:{}'.format(os.path.basename(_stack.__file__), _version)
|
|
|
|
|
2021-09-20 14:19:14 +00:00
|
|
|
_config = {
|
|
|
|
"aws:region": stack.region,
|
|
|
|
"aws:profile": stack.profile,
|
2021-09-23 17:27:06 +00:00
|
|
|
"aws:defaultTags": {"tags": _tags},
|
2021-09-20 14:19:14 +00:00
|
|
|
"zdt:region": stack.region,
|
2021-09-23 17:27:06 +00:00
|
|
|
"zdt:awsAccountId": account_id,
|
2021-09-20 14:19:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# inject all parameters as config in the <Conglomerate> namespace
|
|
|
|
for p in stack.parameters:
|
|
|
|
_config['{}:{}'.format(stack.parameters['Conglomerate'], p)] = stack.parameters[p]
|
|
|
|
|
|
|
|
stack_settings = pulumi.automation.StackSettings(
|
|
|
|
config=_config,
|
|
|
|
secrets_provider=secrets_provider,
|
|
|
|
encryption_salt=stack.pulumi.get('encryptionsalt', None),
|
|
|
|
encrypted_key=stack.pulumi.get('encryptedkey', None)
|
|
|
|
)
|
|
|
|
|
|
|
|
project_settings = pulumi.automation.ProjectSettings(
|
|
|
|
name=project_name,
|
|
|
|
runtime="python",
|
|
|
|
backend={"url": pulumi_backend})
|
|
|
|
|
|
|
|
ws_opts = pulumi.automation.LocalWorkspaceOptions(
|
|
|
|
work_dir=stack.work_dir,
|
|
|
|
project_settings=project_settings,
|
|
|
|
stack_settings={pulumi_stackname: stack_settings},
|
|
|
|
secrets_provider=secrets_provider)
|
|
|
|
|
|
|
|
stack = pulumi.automation.create_or_select_stack(stack_name=pulumi_stackname, project_name=project_name, program=_stack.pulumi_program, opts=ws_opts)
|
2021-09-23 17:27:06 +00:00
|
|
|
stack.workspace.install_plugin("aws", pkg_resources.get_distribution("pulumi_aws").version)
|
2021-09-20 14:19:14 +00:00
|
|
|
|
|
|
|
return stack
|