Skip to content

Commit

Permalink
feat: adding external_account_overrides (#668)
Browse files Browse the repository at this point in the history
  • Loading branch information
eamonnfaherty committed Jul 6, 2023
1 parent 0463001 commit 59bc054
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 10 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[tool.poetry]
name = "aws-service-catalog-puppet"
version = "0.232.1"
version = "0.233.0"
description = "Making it easier to deploy ServiceCatalog products"
classifiers = ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Natural Language :: English"]
homepage = "https://service-catalog-tools-workshop.com/"
Expand Down
82 changes: 74 additions & 8 deletions servicecatalog_puppet/manifest_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import configparser
import json
import functools
import logging
import os
import re
Expand Down Expand Up @@ -164,7 +165,39 @@ def load(f, puppet_account_id):
return manifest


def expand_manifest(manifest, client):
@functools.lru_cache(maxsize=32)
def get_ssm_external_account_overrides():
result = dict()
with betterboto_client.ClientContextManager("ssm") as ssm:
paginator = ssm.get_paginator("get_parameters_by_path")
for page in paginator.paginate(
Path="/servicecatalog-puppet/manifest-external-account-overrides",
Recursive=True,
):
for parameter in page.get("Parameters", []):
_, _, _, account_id, attribute = parameter.get("Name").split("/")
if not result.get(account_id):
result[account_id] = dict()
result[account_id][attribute] = parameter.get("Value")

return result


def get_ssm_external_account_overrides_for(account_id, value, fail_if_missing):
result = get_ssm_external_account_overrides().get(account_id, {})
if fail_if_missing and not result:
raise Exception(
f"There is no override for {account_id} - path /servicecatalog-puppet/manifest-external-account-overrides/{account_id}/xxxx is missing"
)
result = result.get(value)
if fail_if_missing and not result:
raise Exception(
f"There is no override for {value}.{account_id}. SSM parameter /servicecatalog-puppet/manifest-external-account-overrides/{account_id}/{value} is missing"
)
return result


def expand_manifest(manifest, orgs_client):
new_manifest = deepcopy(manifest)
temp_accounts = []
conversions = dict()
Expand All @@ -175,7 +208,9 @@ def expand_manifest(manifest, client):
if account.get("account_id"):
account_id = account.get("account_id")
logger.info("Found an account: {}".format(account_id))
expanded_account = expand_account(account, client, account_id, manifest)
expanded_account = expand_account(
account, orgs_client, account_id, manifest
)
if expanded_account is None:
raise Exception(
f"You have listed account: {account_id} which is not ACTIVE"
Expand All @@ -185,16 +220,18 @@ def expand_manifest(manifest, client):
ou = account.get("ou")
logger.info("Found an ou: {}".format(ou))
if ou.startswith("/"):
ou = client.convert_path_to_ou(account.get("ou"))
ou = orgs_client.convert_path_to_ou(account.get("ou"))
conversions[account.get("ou")] = ou
account["ou_name"] = account["ou"]
account["ou"] = ou
temp_accounts += expand_ou(account, client, manifest)
temp_accounts += expand_ou(account, orgs_client, manifest)

for parameter_name, parameter_details in new_manifest.get("parameters", {}).items():
if parameter_details.get("macro"):
macro_to_run = macros.get(parameter_details.get("macro").get("method"))
result = macro_to_run(client, parameter_details.get("macro").get("args"))
result = macro_to_run(
orgs_client, parameter_details.get("macro").get("args")
)
parameter_details["default"] = result
del parameter_details["macro"]

Expand All @@ -204,7 +241,7 @@ def expand_manifest(manifest, client):
if parameter_details.get("macro"):
macro_to_run = macros.get(parameter_details.get("macro").get("method"))
result = macro_to_run(
client, parameter_details.get("macro").get("args")
orgs_client, parameter_details.get("macro").get("args")
)
parameter_details["default"] = result
del parameter_details["macro"]
Expand Down Expand Up @@ -237,7 +274,7 @@ def expand_manifest(manifest, client):
)
if organizations_account_tags != "ignored":
tags = list()
paginator = client.get_paginator("list_tags_for_resource")
paginator = orgs_client.get_paginator("list_tags_for_resource")
for page in paginator.paginate(ResourceId=stored_account_id,):
tags.extend(page.get("Tags", []))
tags = [f"{t['Key']}:{t['Value']}" for t in tags]
Expand All @@ -247,6 +284,35 @@ def expand_manifest(manifest, client):
elif organizations_account_tags == "honour":
stored_account["tags"] = tags

# Get tags from orgs if we should
external_account_overrides = stored_account.get(
"external_account_overrides", {}
)
if external_account_overrides.get("default_region"):
####
if external_account_overrides.get("default_region").get("source") == "ssm":
default_region = get_ssm_external_account_overrides_for(
stored_account.get("account_id"),
"default_region",
external_account_overrides.get("default_region").get(
"fail_if_missing", True
),
)
if default_region:
stored_account["default_region"] = default_region
if external_account_overrides.get("enabled_regions").get("source") == "ssm":
enabled_regions = get_ssm_external_account_overrides_for(
stored_account.get("account_id"),
"enabled_regions",
external_account_overrides.get("enabled_regions").get(
"fail_if_missing", True
),
)
if enabled_regions:
stored_account["enabled_regions"] = serialisation_utils.load(
enabled_regions
)

# append or overwrite if we should
if stored_account.get("append"):
append = stored_account.get("append")
Expand Down Expand Up @@ -280,7 +346,7 @@ def expand_manifest(manifest, client):
parameter_details.get("macro").get("method")
)
result = macro_to_run(
client, parameter_details.get("macro").get("args")
orgs_client, parameter_details.get("macro").get("args")
)
parameter_details["default"] = result
del parameter_details["macro"]
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@

setup_kwargs = {
'name': 'aws-service-catalog-puppet',
'version': '0.232.1',
'version': '0.233.0',
'description': 'Making it easier to deploy ServiceCatalog products',
'long_description': '# aws-service-catalog-puppet\n\n![logo](./docs/logo.png) \n\n## Badges\n\n[![codecov](https://codecov.io/gh/awslabs/aws-service-catalog-puppet/branch/master/graph/badge.svg?token=e8M7mdsmy0)](https://codecov.io/gh/awslabs/aws-service-catalog-puppet)\n\n\n## What is it?\nThis is a python3 framework that makes it easier to share multi region AWS Service Catalog portfolios and makes it \npossible to provision products into accounts declaratively using a metadata based rules engine.\n\nWith this framework you define your accounts in a YAML file. You give each account a set of tags, a default region and \na set of enabled regions.\n\nOnce you have done this you can define portfolios should be shared with each set of accounts using the tags and you \ncan specify which regions the shares occur in.\n\nIn addition to this, you can also define products that should be provisioned into accounts using the same tag based \napproach. The framework will assume role into the target account and provision the product on your behalf.\n\n\n## Getting started\n\nYou can read the [installation how to](https://service-catalog-tools-workshop.com/30-how-tos/10-installation/30-service-catalog-puppet.html)\nor you can read through the [every day use](https://service-catalog-tools-workshop.com/30-how-tos/50-every-day-use.html)\nguides.\n\nYou can read the [documentation](https://aws-service-catalog-puppet.readthedocs.io/en/latest/) to understand the inner \nworkings. \n\n\n## Going further\n\nThe framework is one of a pair. The other is [aws-service-catalog-factory](https://github.com/awslabs/aws-service-catalog-factory).\nWith Service Catalog Factory you can create pipelines that deploy multi region portfolios very easily. \n\n## License\n\nThis library is licensed under the Apache 2.0 License. \n \n',
'author': 'Eamonn Faherty',
Expand Down

0 comments on commit 59bc054

Please sign in to comment.