Skip to content

Commit

Permalink
updates for tags
Browse files Browse the repository at this point in the history
  • Loading branch information
morga471 committed Feb 12, 2026
1 parent 803ff77 commit 227f8eb
Show file tree
Hide file tree
Showing 39 changed files with 1,247 additions and 255 deletions.
2 changes: 1 addition & 1 deletion .pre-commit.yaml → .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ repos:
- id: terraform_fmt
- id: terraform_docs
- id: terraform_validate
- id: terraform_tflint
- id: terraform_tflint
9 changes: 9 additions & 0 deletions common/base_settings.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
data "aws_partition" "current" {}

locals {
account_id = data.aws_caller_identity.current.account_id
region = data.aws_region.current.id
partition = data.aws_partition.current.partition
}
16 changes: 16 additions & 0 deletions common/base_tags.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
locals {
standard_tags = {
ManagedBy = "Terraform"
Module = local.module_name
}

enforced_tags = merge(
local.standard_tags,
var.enforced_tags
)

tags = merge(
local.enforced_tags,
var.tags
)
}
34 changes: 34 additions & 0 deletions common/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# List portfolios to find by name pattern
data "aws_servicecatalog_portfolios" "all" {
count = var.portfolio_id == null ? 1 : 0
accept_language = var.accept_language
}

# Get portfolio details if we provided the ID
data "aws_servicecatalog_portfolio" "by_id" {
count = var.portfolio_id != null ? 1 : 0
id = var.portfolio_id
accept_language = var.accept_language
}

# Get product details by ID (requires product_id)
data "aws_servicecatalog_product" "by_id" {
count = var.product_id != null ? 1 : 0
id = var.product_id
accept_language = var.accept_language
}

# Get the latest provisioning artifact (product version)
data "aws_servicecatalog_provisioning_artifacts" "this" {
accept_language = var.accept_language
product_id = var.product_id != null ? var.product_id : var.product_id
}

# Get CloudFormation stack outputs if provisioned product exists
data "aws_cloudformation_stack" "this" {
count = var.retrieve_stack_outputs ? 1 : 0

name = format("SC-%s-%s", aws_servicecatalog_provisioned_product.this.id, aws_servicecatalog_provisioned_product.this.name)

depends_on = [aws_servicecatalog_provisioned_product.this]
}
39 changes: 39 additions & 0 deletions common/defaults.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
locals {
# Get portfolio ID from lookup or variable
portfolio_id = var.portfolio_id != null ? var.portfolio_id : try(
[for p in data.aws_servicecatalog_portfolios.all[0].details :
p.id if can(regex(var.portfolio_name_pattern, p.name))
][0],
null
)

# Get product ID from variable or portfolio lookup
product_id = var.product_id

# Get the latest provisioning artifact ID
latest_artifact_id = try(
[for artifact in data.aws_servicecatalog_provisioning_artifacts.this.provisioning_artifact_details :
artifact.id if artifact.active
][0],
null
)

# Use provided path_id or default to latest
provisioning_artifact_id = var.path_id != null ? var.path_id : local.latest_artifact_id

# Merge default parameters with user-provided parameters
default_parameters = {}

parameters = merge(
local.default_parameters,
var.parameters
)

# Convert parameters map to the format expected by aws_servicecatalog_provisioned_product
provisioning_parameters = [
for key, value in local.parameters : {
key = key
value = tostring(value)
}
]
}
2 changes: 2 additions & 0 deletions common/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Intentionally empty file for consistency with aws-s3 pattern
# Module-specific locals should be defined in each submodule
4 changes: 4 additions & 0 deletions common/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Product Submodule
#
# Provisions a Service Catalog product
# using a pre-configured portfolio and product
59 changes: 59 additions & 0 deletions common/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
output "provisioned_product_id" {
description = "The ID of the provisioned product"
value = aws_servicecatalog_provisioned_product.this.id
}

output "provisioned_product_name" {
description = "The name of the provisioned product"
value = aws_servicecatalog_provisioned_product.this.name
}

output "provisioned_product_arn" {
description = "The ARN of the provisioned product"
value = aws_servicecatalog_provisioned_product.this.arn
}

output "provisioned_product_type" {
description = "The type of the provisioned product"
value = aws_servicecatalog_provisioned_product.this.type
}

output "provisioned_product_status" {
description = "The status of the provisioned product"
value = aws_servicecatalog_provisioned_product.this.status
}

output "provisioned_product_status_message" {
description = "The status message for the provisioned product"
value = aws_servicecatalog_provisioned_product.this.status_message
}

output "cloudformation_stack_arn" {
description = "The ARN of the CloudFormation stack"
value = aws_servicecatalog_provisioned_product.this.cloudformation_stack_arn
}

output "launch_role_arn" {
description = "The ARN of the launch role"
value = aws_servicecatalog_provisioned_product.this.launch_role_arn
}

output "stack_outputs" {
description = "CloudFormation stack outputs"
value = var.retrieve_stack_outputs ? try(data.aws_cloudformation_stack.this[0].outputs, {}) : {}
}

output "portfolio_id" {
description = "The ID of the portfolio used"
value = local.portfolio_id
}

output "product_id" {
description = "The ID of the product used"
value = local.product_id
}

output "provisioning_artifact_id" {
description = "The ID of the provisioning artifact used"
value = local.provisioning_artifact_id
}
42 changes: 42 additions & 0 deletions common/resources.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
resource "aws_servicecatalog_provisioned_product" "this" {
name = var.provisioned_product_name
product_id = local.product_id
provisioning_artifact_id = local.provisioning_artifact_id
path_id = var.path_id
accept_language = var.accept_language
ignore_errors = var.ignore_errors
notification_arns = var.notification_arns
retain_physical_resources = var.retain_physical_resources

dynamic "provisioning_parameters" {
for_each = local.provisioning_parameters
content {
key = provisioning_parameters.value.key
value = provisioning_parameters.value.value
}
}

dynamic "stack_set_provisioning_preferences" {
for_each = var.stack_set_provisioning_preferences != null ? [var.stack_set_provisioning_preferences] : []
content {
accounts = try(stack_set_provisioning_preferences.value.accounts, null)
failure_tolerance_count = try(stack_set_provisioning_preferences.value.failure_tolerance_count, null)
failure_tolerance_percentage = try(stack_set_provisioning_preferences.value.failure_tolerance_percentage, null)
max_concurrency_count = try(stack_set_provisioning_preferences.value.max_concurrency_count, null)
max_concurrency_percentage = try(stack_set_provisioning_preferences.value.max_concurrency_percentage, null)
regions = try(stack_set_provisioning_preferences.value.regions, null)
}
}

tags = local.tags

timeouts {
create = var.timeout_create
update = var.timeout_update
delete = var.timeout_delete
}

depends_on = [
data.aws_servicecatalog_provisioning_artifacts.this
]
}
5 changes: 5 additions & 0 deletions common/variables.parameters.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "parameters" {
description = "Parameters to pass to the Service Catalog product. Map of parameter names to values"
type = map(string)
default = {}
}
94 changes: 94 additions & 0 deletions common/variables.product.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
variable "provisioned_product_name" {
description = "Name of the provisioned product"
type = string

validation {
condition = length(var.provisioned_product_name) > 0 && length(var.provisioned_product_name) <= 128
error_message = "provisioned_product_name must be between 1 and 128 characters"
}
}

variable "portfolio_id" {
description = "Portfolio ID. If not provided, will lookup by portfolio_name_pattern"
type = string
default = null
}

variable "portfolio_name_pattern" {
description = "Pattern to search for portfolio by name. Used when portfolio_id is not provided"
type = string
default = "edl-portfolio"
}

variable "product_id" {
description = "Product ID. If not provided, will lookup by product_name_pattern"
type = string
default = null
}

variable "product_name_pattern" {
description = "Pattern to search for product by name"
type = string
default = "linux-product"
}

variable "path_id" {
description = "Path identifier of the product. If not provided, will use the latest active artifact"
type = string
default = null
}

variable "ignore_errors" {
description = "Only applies to deleting. If true, errors from the underlying service are ignored"
type = bool
default = false
}

variable "notification_arns" {
description = "SNS topic ARNs to notify when the provisioned product changes"
type = list(string)
default = []
}

variable "retain_physical_resources" {
description = "Whether to retain the physical resources when the provisioned product is terminated"
type = bool
default = false
}

variable "stack_set_provisioning_preferences" {
description = "Configuration for StackSet provisioning"
type = object({
accounts = optional(list(string))
failure_tolerance_count = optional(number)
failure_tolerance_percentage = optional(number)
max_concurrency_count = optional(number)
max_concurrency_percentage = optional(number)
regions = optional(list(string))
})
default = null
}

variable "retrieve_stack_outputs" {
description = "Whether to retrieve CloudFormation stack outputs"
type = bool
default = true
}

variable "timeout_create" {
description = "Timeout for provisioned product creation"
type = string
default = "60m"
}

variable "timeout_update" {
description = "Timeout for provisioned product updates"
type = string
default = "60m"
}

variable "timeout_delete" {
description = "Timeout for provisioned product deletion"
type = string
default = "60m"
}
24 changes: 24 additions & 0 deletions common/variables.safeguards.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This file contains safeguard variables to prevent accidental destruction
# Pattern follows aws-s3 module conventions

variable "enable_deletion_protection" {
description = "Enable deletion protection to prevent accidental termination"
type = bool
default = false
}

locals {
deletion_protection_error = "Deletion protection is enabled. Set enable_deletion_protection = false to allow termination."
}

resource "null_resource" "deletion_protection" {
count = var.enable_deletion_protection ? 1 : 0

lifecycle {
prevent_destroy = true
}

triggers = {
provisioned_product_id = aws_servicecatalog_provisioned_product.this.id
}
}
22 changes: 22 additions & 0 deletions common/variables.tags.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
variable "tags" {
description = "Additional tags to apply to resources"
type = map(string)
default = {}
}

variable "enforced_tags" {
description = "Tags enforced on all resources"
type = map(string)
default = {}
}

variable "accept_language" {
description = "Language code for Service Catalog API calls"
type = string
default = "en"

validation {
condition = contains(["en", "jp", "zh"], var.accept_language)
error_message = "accept_language must be one of: en, jp, zh"
}
}
9 changes: 9 additions & 0 deletions common/version.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
9 changes: 9 additions & 0 deletions common/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
Loading

0 comments on commit 227f8eb

Please sign in to comment.