Skip to content

Commit

Permalink
adding support for tag options (#312)
Browse files Browse the repository at this point in the history
* adding support for tag options
  • Loading branch information
eamonnfaherty authored Nov 16, 2022
1 parent 72ec67d commit f44b9d5
Show file tree
Hide file tree
Showing 13 changed files with 261 additions and 14 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-factory"
version = "0.93.0"
version = "0.94.0"
description = "Making it easier to build 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
114 changes: 105 additions & 9 deletions servicecatalog_factory/commands/task_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,34 @@ def generate_tasks_for_portfolios(
tags=item.get("Tags", []),
)

for tag_option in item.get("TagOptions", []):
tag_option_key = tag_option.get("Key")
tag_option_value = tag_option.get("Value")

create_tag_option_task_ref = f"create-tag-option-{region}-{tag_option_key}-{tag_option_value}"
if not task_reference.get(create_tag_option_task_ref):
task_reference[create_tag_option_task_ref] = dict(
task_reference=create_tag_option_task_ref,
section_name=section_names.CREATE_TAG_OPTION,
region=region,
dependencies_by_reference=[],
tag_option_key=tag_option_key,
tag_option_value=tag_option_value,
)

associate_tag_option_task_ref = f"associate-tag-option-{portfolio_name}-{region}--{tag_option_key}-{tag_option_value}"
task_reference[associate_tag_option_task_ref] = dict(
task_reference=associate_tag_option_task_ref,
section_name=section_names.ASSOCIATE_TAG_OPTION,
region=region,
dependencies_by_reference=[
create_portfolio_task_ref,
create_tag_option_task_ref,
],
create_portfolio_task_ref=create_portfolio_task_ref,
create_tag_option_task_ref=create_tag_option_task_ref,
)

# ADD ASSOCIATIONS FOR THE PORTFOLIO
if item.get("Associations"):
task_reference[
Expand Down Expand Up @@ -258,6 +286,34 @@ def generate_tasks_for_portfolios(
tags=product.get("Tags", []) + item.get("Tags", []),
)

for tag_option in product.get("TagOptions", []):
tag_option_key = tag_option.get("Key")
tag_option_value = tag_option.get("Value")

create_tag_option_task_ref = f"create-tag-option-{region}-{tag_option_key}-{tag_option_value}"
if not task_reference.get(create_tag_option_task_ref):
task_reference[create_tag_option_task_ref] = dict(
task_reference=create_tag_option_task_ref,
section_name=section_names.CREATE_TAG_OPTION,
region=region,
dependencies_by_reference=[],
tag_option_key=tag_option_key,
tag_option_value=tag_option_value,
)

associate_tag_option_task_ref = f"associate-tag-option-{portfolio_name}-{product.get('Name')}-{region}--{tag_option_key}-{tag_option_value}"
task_reference[associate_tag_option_task_ref] = dict(
task_reference=associate_tag_option_task_ref,
section_name=section_names.ASSOCIATE_TAG_OPTION,
region=region,
dependencies_by_reference=[
create_product_task_ref,
create_tag_option_task_ref,
],
create_product_task_ref=create_product_task_ref,
create_tag_option_task_ref=create_tag_option_task_ref,
)

# ASSOCIATE PRODUCT WITH PORTFOLIO
create_product_association_ref = f"create-product-association-{portfolio_name}-{product.get('Name')}-{region}"
task_reference[create_product_association_ref] = dict(
Expand Down Expand Up @@ -413,9 +469,41 @@ def generate_tasks_for_portfolios(
tags=item.get("Tags", []),
)

for tag_option in item.get("TagOptions", []):
tag_option_key = tag_option.get("Key")
tag_option_value = tag_option.get("Value")

create_tag_option_task_ref = f"create-tag-option-{region}-{tag_option_key}-{tag_option_value}"
if not task_reference.get(create_tag_option_task_ref):
task_reference[create_tag_option_task_ref] = dict(
task_reference=create_tag_option_task_ref,
section_name=section_names.CREATE_TAG_OPTION,
region=region,
dependencies_by_reference=[],
tag_option_key=tag_option_key,
tag_option_value=tag_option_value,
)

associate_tag_option_task_ref = f"associate-tag-option-{item.get('Name')}-{region}--{tag_option_key}-{tag_option_value}"
task_reference[associate_tag_option_task_ref] = dict(
task_reference=associate_tag_option_task_ref,
section_name=section_names.ASSOCIATE_TAG_OPTION,
region=region,
dependencies_by_reference=[
create_product_task_ref,
create_tag_option_task_ref,
],
create_product_task_ref=create_product_task_ref,
create_tag_option_task_ref=create_tag_option_task_ref,
)

for version in item.get("Versions", []):
# CREATE CODE REPO IF NEEDED
if version.get("Source", {}).get("Configuration", {}).get("Code"):
if (
version.get("Source", {})
.get("Configuration", {})
.get("Code")
):
source = always_merger.merge({}, item.get("Source", {}))
always_merger.merge(source, version.get("Source", {}))
configuration = source.get("Configuration")
Expand Down Expand Up @@ -455,7 +543,9 @@ def generate_tasks_for_portfolios(
if pipeline_mode == constants.PIPELINE_MODE_SPILT:
for version in item.get("Versions", []):
task_ref = f"create-generic-split-pipeline-product-{product_name}-{version.get('Name')}"
task_reference[task_ref] = create_task_for_split_pipeline(
task_reference[
task_ref
] = create_task_for_split_pipeline(
task_ref,
"product",
item,
Expand All @@ -467,10 +557,10 @@ def generate_tasks_for_portfolios(
versions = list()
for version in item.get("Versions", []):
versions.append(version)
task_ref = (
f"create-generic-combined-pipeline-product-{product_name}"
)
task_reference[task_ref] = create_task_for_combined_pipeline(
task_ref = f"create-generic-combined-pipeline-product-{product_name}"
task_reference[
task_ref
] = create_task_for_combined_pipeline(
task_ref,
"product",
item,
Expand All @@ -480,7 +570,9 @@ def generate_tasks_for_portfolios(
)

else:
raise Exception(f"Unsupported pipeline_mode: {pipeline_mode}")
raise Exception(
f"Unsupported pipeline_mode: {pipeline_mode}"
)

for portfolio_name_suffix in item.get("Portfolios", []):
portfolio_name = f"{p_name}-{portfolio_name_suffix}"
Expand Down Expand Up @@ -515,8 +607,12 @@ def generate_tasks_for_portfolios(
.get("LocalRoleName")
)
launch_role_name_constraint_task_ref = f"create-launch-role-name-constraint-{portfolio_name}-{region}"
if not task_reference.get(launch_role_name_constraint_task_ref):
task_reference[launch_role_name_constraint_task_ref] = dict(
if not task_reference.get(
launch_role_name_constraint_task_ref
):
task_reference[
launch_role_name_constraint_task_ref
] = dict(
portfolio_name=portfolio_name,
task_reference=launch_role_name_constraint_task_ref,
section_name=section_names.CREATE_LAUNCH_ROLE_NAME_CONSTRAINTS_TASK,
Expand Down
4 changes: 3 additions & 1 deletion servicecatalog_factory/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,6 @@ def get_should_pipelines_inherit_tags():


def get_aws_url_suffix():
return os.getenv(environmental_variables.AWS_URL_SUFFIX, constants.AWS_URL_SUFFIX_DEFAULT)
return os.getenv(
environmental_variables.AWS_URL_SUFFIX, constants.AWS_URL_SUFFIX_DEFAULT
)
2 changes: 1 addition & 1 deletion servicecatalog_factory/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,4 @@
FACTORY_LOGGER_NAME = "factory-logger"
FACTORY_SCHEDULER_LOGGER_NAME = "factory-logger-scheduler"

AWS_URL_SUFFIX_DEFAULT = "amazonaws.com"
AWS_URL_SUFFIX_DEFAULT = "amazonaws.com"
2 changes: 1 addition & 1 deletion servicecatalog_factory/environmental_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

CACHE_INVALIDATOR = "SCT_CACHE_INVALIDATOR"

AWS_URL_SUFFIX = "AWS_URL_SUFFIX"
AWS_URL_SUFFIX = "AWS_URL_SUFFIX"
3 changes: 3 additions & 0 deletions servicecatalog_factory/schema/schema-portfolios.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ portfolio:
Tags: list(include('tag'), required=False)
Components: list(include('product'), required=False)
Products: list(include('product'), required=False)
TagOptions: list(include('tag'), required=False)

tag:
Key: str()
Expand Down Expand Up @@ -106,6 +107,7 @@ product_without_source:
Versions: list(include('version_with_source'), required=False)
Portfolios: list(required=False)
Constraints: include('constraints', required=False)
TagOptions: list(include('tag'), required=False)

product_with_source:
Name: str()
Expand All @@ -126,6 +128,7 @@ product_with_source:
Versions: list(include('version'), required=False)
Portfolios: list(required=False)
Constraints: include('constraints', required=False)
TagOptions: list(include('tag'), required=False)

constraints:
Launch: include('launch')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@
"SERVICE_CATALOG_UPDATE_PROVISIONING_ARTIFACT" + PER_REGION_OF_ACCOUNT
)

SERVICE_CATALOG_CREATE_TAG_OPTION_PER_REGION_OF_ACCOUNT = (
"SERVICE_CATALOG_CREATE_TAG_OPTION" + PER_REGION_OF_ACCOUNT
)
SERVICE_CATALOG_ASSOCIATE_TAG_OPTION_PER_REGION_OF_ACCOUNT = (
"SERVICE_CATALOG_ASSOCIATE_TAG_OPTION" + PER_REGION_OF_ACCOUNT
)
SSM_GET_PARAMETER_PER_REGION_OF_ACCOUNT = "SSM_GET_PARAMETER" + PER_REGION_OF_ACCOUNT
SSM_DELETE_PARAMETER_PER_REGION_OF_ACCOUNT = (
"SSM_DELETE_PARAMETER" + PER_REGION_OF_ACCOUNT
Expand Down
16 changes: 16 additions & 0 deletions servicecatalog_factory/workflow/dependencies/resources_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ def create(section_name, parameters_to_use):
r.CODECOMMIT_CREATE_COMMIT_PER_REGION_OF_ACCOUNT,
]

elif section_name == section_names.CREATE_TAG_OPTION:
if status == "terminated":
resources = []
else:
resources = [
r.SERVICE_CATALOG_CREATE_TAG_OPTION_PER_REGION_OF_ACCOUNT,
]

elif section_name == section_names.ASSOCIATE_TAG_OPTION:
if status == "terminated":
resources = []
else:
resources = [
r.SERVICE_CATALOG_ASSOCIATE_TAG_OPTION_PER_REGION_OF_ACCOUNT,
]

else:
raise Exception(f"Unknown section_name: {section_name}")

Expand Down
2 changes: 2 additions & 0 deletions servicecatalog_factory/workflow/dependencies/section_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
GET_BUCKET = "get-bucket"
CREATE_PRODUCT_TASK = "create-product-task"
CREATE_PORTFOLIO_TASK = "create-portfolio-task"
CREATE_TAG_OPTION = "create-tag-option"
ASSOCIATE_TAG_OPTION = "associate-tag-option"
CREATE_GENERIC_COMBINED_PIPELINE_TASK = "create-generic-combined-pipeline-task"
CREATE_PORTFOLIO_ASSOCIATIONS_TASK = "create-portfolio-associations-task"
CREATE_PRODUCT_ASSOCIATION_TASK = "create-product-association-task"
Expand Down
37 changes: 37 additions & 0 deletions servicecatalog_factory/workflow/dependencies/task_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,5 +195,42 @@ def create(
bucket=parameters_to_use.get("bucket"),
key=parameters_to_use.get("key"),
)

elif section_name == section_names.CREATE_TAG_OPTION:
if status == "terminated":
raise Exception("NOT BUILT YET")
else:
from servicecatalog_factory.workflow.portfolios import (
create_tag_option_task,
)

return create_tag_option_task.CreateTagOptionTask(
**minimum_common_parameters,
region=parameters_to_use.get("region"),
tag_option_key=parameters_to_use.get("tag_option_key"),
tag_option_value=parameters_to_use.get("tag_option_value"),
)

elif section_name == section_names.ASSOCIATE_TAG_OPTION:
if status == "terminated":
raise Exception("NOT BUILT YET")
else:
from servicecatalog_factory.workflow.portfolios import (
associate_tag_option_task,
)

return associate_tag_option_task.AssociateTagOptionTask(
**minimum_common_parameters,
region=parameters_to_use.get("region"),
create_portfolio_task_ref=parameters_to_use.get(
"create_portfolio_task_ref"
),
create_product_task_ref=parameters_to_use.get(
"create_product_task_ref"
),
create_tag_option_task_ref=parameters_to_use.get(
"create_tag_option_task_ref"
),
)
else:
raise Exception(f"Unknown section_name: {section_name}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
import luigi

from servicecatalog_factory.workflow.tasks import FactoryTask


class AssociateTagOptionTask(FactoryTask):
region = luigi.Parameter()

create_product_task_ref = luigi.Parameter()
create_portfolio_task_ref = luigi.Parameter()
create_tag_option_task_ref = luigi.Parameter()

def params_for_results_display(self):
return {
"region": self.region,
"create_product_task_ref": self.create_product_task_ref,
"create_portfolio_task_ref": self.create_portfolio_task_ref,
"create_tag_option_task_ref": self.create_tag_option_task_ref,
}

def run(self):
with self.regional_client("servicecatalog") as servicecatalog:
if self.create_portfolio_task_ref:
portfolio_details = self.get_output_from_reference_dependency(
self.create_portfolio_task_ref
)
resource_id = portfolio_details.get("Id")
elif self.create_product_task_ref:
product_details = self.get_output_from_reference_dependency(
self.create_product_task_ref
)
resource_id = product_details.get("ProductId")
else:
raise Exception("Did not find a resource to associate with")

tag_option_details = self.get_output_from_reference_dependency(
self.create_tag_option_task_ref
)

try:
servicecatalog.associate_tag_option_with_resource(
ResourceId=resource_id, TagOptionId=tag_option_details.get("Id"),
)
except servicecatalog.exceptions.DuplicateResourceException:
pass
self.write_output_raw("{}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
import luigi

from servicecatalog_factory.workflow.tasks import FactoryTask


class CreateTagOptionTask(FactoryTask):
region = luigi.Parameter()
tag_option_key = luigi.Parameter()
tag_option_value = luigi.Parameter()

def params_for_results_display(self):
return {
"region": self.region,
"tag_option_key": self.tag_option_key,
"tag_option_value": self.tag_option_value,
}

def run(self):
with self.regional_client("servicecatalog") as servicecatalog:
try:
result = servicecatalog.create_tag_option(
Key=self.tag_option_key, Value=self.tag_option_value
).get("TagOptionDetail")
except servicecatalog.exceptions.DuplicateResourceException:
result = servicecatalog.list_tag_options(
Filters={
"Key": self.tag_option_key,
"Value": self.tag_option_value,
},
PageSize=2,
).get("TagOptionDetails")
assert len(result) == 1
result = result[0]

self.write_output(result)
Loading

0 comments on commit f44b9d5

Please sign in to comment.