diff --git a/released/discovery_center/mission_3061/step1/locals.tf b/released/discovery_center/mission_3061/step1/locals.tf new file mode 100644 index 00000000..64cbcab2 --- /dev/null +++ b/released/discovery_center/mission_3061/step1/locals.tf @@ -0,0 +1,3 @@ +locals { + service_name__abap = "abap" +} diff --git a/released/discovery_center/mission_3061/step1/main.tf b/released/discovery_center/mission_3061/step1/main.tf index 6ed9739e..d5fdd960 100644 --- a/released/discovery_center/mission_3061/step1/main.tf +++ b/released/discovery_center/mission_3061/step1/main.tf @@ -1,10 +1,14 @@ ### # Setup of names based on variables ### +resource "random_uuid" "uuid" {} + locals { - subaccount_name = "${var.subaccount_prefix}-${var.abap_sid}" - subaccount_domain = lower("${var.subaccount_prefix}-${var.abap_sid}") - subaccount_cf_org = "CF-${var.subaccount_prefix}-${var.abap_sid}" + random_uuid = random_uuid.uuid.result + subaccount_domain = lower("${var.subaccount_prefix}-${var.abap_sid}-${local.random_uuid}") + subaccount_name = var.subaccount_name != "" ? var.subaccount_name : "${var.subaccount_prefix}-${var.abap_sid}" + subaccount_cf_org = substr(replace("${local.subaccount_domain}", "-", ""), 0, 32) + abap_admin_email = var.abap_admin_email != "" ? var.abap_admin_email : (length(var.qas_abap_admin) > 0 ? var.qas_abap_admin[0] : "") } ### @@ -22,20 +26,20 @@ resource "btp_subaccount" "abap_subaccount" { ### resource "btp_subaccount_entitlement" "abap__service_instance_plan" { subaccount_id = btp_subaccount.abap_subaccount.id - service_name = "abap" - plan_name = var.abap_si_plan + service_name = local.service_name__abap + plan_name = var.service_plan__abap } resource "btp_subaccount_entitlement" "abap__abap_compute_unit" { subaccount_id = btp_subaccount.abap_subaccount.id - service_name = "abap" + service_name = local.service_name__abap plan_name = "abap_compute_unit" amount = var.abap_compute_unit_quota } resource "btp_subaccount_entitlement" "abap__hana_compute_unit" { subaccount_id = btp_subaccount.abap_subaccount.id - service_name = "abap" + service_name = local.service_name__abap plan_name = "hana_compute_unit" amount = var.hana_compute_unit_quota } @@ -98,3 +102,29 @@ resource "btp_subaccount_trust_configuration" "subaccount_trust_abap" { subaccount_id = btp_subaccount.abap_subaccount.id identity_provider = var.custom_idp } + +resource "local_file" "output_vars_step1" { + count = var.create_tfvars_file_for_next_stage ? 1 : 0 + content = <<-EOT + origin = "${var.origin}" + + cf_api_url = "${jsondecode(btp_subaccount_environment_instance.cf_abap.labels)["API Endpoint"]}" + cf_org_id = "${btp_subaccount_environment_instance.cf_abap.platform_id}" + + cf_org_auditors = ${jsonencode(var.cf_org_auditors)} + cf_org_billing_managers = ${jsonencode(var.cf_org_billing_managers)} + cf_org_managers = ${jsonencode(var.cf_org_managers)} + cf_space_auditors = ${jsonencode(var.cf_space_auditors)} + cf_space_developers = ${jsonencode(var.cf_space_developers)} + cf_space_managers = ${jsonencode(var.cf_space_managers)} + + abap_sid = "${var.abap_sid}" + service_plan__abap = "${var.service_plan__abap}" + abap_compute_unit_quota = ${jsonencode(var.abap_compute_unit_quota)} + hana_compute_unit_quota = ${jsonencode(var.hana_compute_unit_quota)} + abap_admin_email = "${local.abap_admin_email}" + abap_is_development_allowed = ${var.abap_is_development_allowed} + + EOT + filename = "../step2/terraform.tfvars" +} diff --git a/released/discovery_center/mission_3061/step1/outputs.tf b/released/discovery_center/mission_3061/step1/outputs.tf index a093a1e8..748ec0ff 100644 --- a/released/discovery_center/mission_3061/step1/outputs.tf +++ b/released/discovery_center/mission_3061/step1/outputs.tf @@ -23,7 +23,77 @@ output "cf_api_url" { description = "API endpoint of the Cloud Foundry environment." } +output "cf_landscape_label" { + value = btp_subaccount_environment_instance.cf_abap.landscape_label + description = "Landscape label of the Cloud Foundry environment." +} + +output "cf_space_name" { + value = var.cf_space_name + description = "The name of the Cloud Foundry space." +} + output "abap_sid" { value = var.abap_sid description = "SID of the ABAP system." -} \ No newline at end of file +} + +output "abap_compute_unit_quota" { + value = var.abap_compute_unit_quota + description = "The amount of ABAP compute units to be assigned to the subaccount." +} + +output "hana_compute_unit_quota" { + value = var.hana_compute_unit_quota + description = "The amount of ABAP compute units to be assigned to the subaccount." +} + +output "origin" { + value = var.origin + description = "The identity provider for the UAA user." +} + +output "cf_org_managers" { + value = var.cf_org_managers + description = "List of Cloud Foundry org managers." +} + +output "cf_org_billing_managers" { + value = var.cf_org_billing_managers + description = "List of Cloud Foundry org billing managers." +} + +output "cf_org_auditors" { + value = var.cf_org_auditors + description = "List of Cloud Foundry org auditors." +} + +output "cf_space_managers" { + value = var.cf_space_managers + description = "List of managers for the Cloud Foundry space." +} + +output "cf_space_developers" { + value = var.cf_space_developers + description = "List of developers for the Cloud Foundry space." +} + +output "cf_space_auditors" { + value = var.cf_space_auditors + description = "The list of Cloud Foundry space auditors." +} + +output "service_plan__abap" { + value = var.service_plan__abap + description = "Plan for the service instance of ABAP." +} + +output "abap_admin_email" { + value = local.abap_admin_email + description = "Email of the ABAP Administrator." +} + +output "abap_is_development_allowed" { + value = var.abap_is_development_allowed + description = "Flag to define if development on the ABAP system is allowed." +} diff --git a/released/discovery_center/mission_3061/step1/provider.tf b/released/discovery_center/mission_3061/step1/provider.tf index f9791033..7f2d5d43 100644 --- a/released/discovery_center/mission_3061/step1/provider.tf +++ b/released/discovery_center/mission_3061/step1/provider.tf @@ -12,5 +12,9 @@ terraform { # Please checkout documentation on how best to authenticate against SAP BTP # via the Terraform provider for SAP BTP provider "btp" { - globalaccount = var.globalaccount + # Comment out the idp in case you need it to connect to your global account + # ------------------------------------------------------------------------- + # idp = var.custom_idp + globalaccount = var.globalaccount + cli_server_url = var.cli_server_url } diff --git a/released/discovery_center/mission_3061/step1/variables.tf b/released/discovery_center/mission_3061/step1/variables.tf index 1a1dd10d..8ee80fdc 100644 --- a/released/discovery_center/mission_3061/step1/variables.tf +++ b/released/discovery_center/mission_3061/step1/variables.tf @@ -6,6 +6,19 @@ variable "globalaccount" { variable "subaccount_prefix" { type = string description = "The prefix for the subaccount name and subdomain." + default = "ABAP-" +} + +variable "subaccount_name" { + type = string + description = "The name for the subaccount." + default = "" +} + +variable "cli_server_url" { + type = string + description = "The BTP CLI server URL." + default = "https://cli.btp.cloud.sap" } variable "region" { @@ -26,6 +39,84 @@ variable "cf_landscape_label" { default = "" } +variable "cf_space_name" { + type = string + description = "The name of the Cloud Foundry space." + default = "dev" +} + +variable "cf_org_managers" { + type = list(string) + description = "List of Cloud Foundry org managers." + default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_org_managers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_org_managers) + error_message = "Please enter a valid email address for the subaccount admins." + } +} + +variable "cf_org_billing_managers" { + type = list(string) + description = "List of Cloud Foundry org billing managers." + default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_org_billing_managers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_org_billing_managers) + error_message = "Please enter a valid email address for the subaccount admins." + } +} + +variable "cf_org_auditors" { + type = list(string) + description = "List of Cloud Foundry org auditors." + default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_org_auditors : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_org_auditors) + error_message = "Please enter a valid email address for the subaccount admins." + } +} + +variable "cf_space_managers" { + type = list(string) + description = "List of managers for the Cloud Foundry space." + default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_space_managers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_space_managers) + error_message = "Please enter a valid email address for the subaccount admins." + } +} + +variable "cf_space_developers" { + type = list(string) + description = "List of developers for the Cloud Foundry space." + default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_space_developers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_space_developers) + error_message = "Please enter a valid email address for the subaccount admins." + } +} + +variable "cf_space_auditors" { + type = list(string) + description = "The list of Cloud Foundry space auditors." + default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_space_auditors : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_space_auditors) + error_message = "Please enter a valid email address for the subaccount admins." + } +} + variable "abap_sid" { type = string description = "The system ID (SID) of the ABAP system." @@ -34,9 +125,10 @@ variable "abap_sid" { condition = can(regex("^[A-Z][A-Z0-9]{2}$", var.abap_sid)) error_message = "Please provide a valid system ID (SID). It must consist of exactly three alphanumeric characters. Only uppercase letters are allowed. The first character must be a letter (not a digit). The ID does not have to be technically unique." } + default = "A01" } -variable "abap_si_plan" { +variable "service_plan__abap" { type = string description = "Plan for the service instance of ABAP." default = "standard" @@ -54,7 +146,37 @@ variable "hana_compute_unit_quota" { default = 2 } +variable "abap_admin_email" { + type = string + description = "Email of the ABAP Administrator." + default = "" +} + +variable "abap_is_development_allowed" { + type = bool + description = "Flag to define if development on the ABAP system is allowed." + default = true +} + variable "custom_idp" { type = string description = "Name of custom IDP to be used for the subaccount" } + +variable "origin" { + type = string + description = "The identity provider for the UAA user." + default = "sap.ids" +} + +variable "create_tfvars_file_for_next_stage" { + type = bool + description = "Switch to enable the creation of the tfvars file for the next step." + default = false +} + +variable "qas_abap_admin" { + type = list(string) + description = "Email of the ABAP Administrator." + default = [] +} diff --git a/released/discovery_center/mission_3061/step2/README.md b/released/discovery_center/mission_3061/step2/README.md index afc695b8..36fdf2e1 100644 --- a/released/discovery_center/mission_3061/step2/README.md +++ b/released/discovery_center/mission_3061/step2/README.md @@ -6,7 +6,7 @@ This directory contains the setup of an ABAP environment from scratch namely a n This directory contains the configuration for the second step of the setup namely: -- the assignment of Cloud FOundry org roles +- the assignment of Cloud Foundry org roles - a new Cloud Foundry space - the assignment of Cloud Foundry space roles - the ABAP environment (service instance) diff --git a/released/discovery_center/mission_3061/step2/locals.tf b/released/discovery_center/mission_3061/step2/locals.tf new file mode 100644 index 00000000..64cbcab2 --- /dev/null +++ b/released/discovery_center/mission_3061/step2/locals.tf @@ -0,0 +1,3 @@ +locals { + service_name__abap = "abap" +} diff --git a/released/discovery_center/mission_3061/step2/main.tf b/released/discovery_center/mission_3061/step2/main.tf index d22fee12..051794c3 100644 --- a/released/discovery_center/mission_3061/step2/main.tf +++ b/released/discovery_center/mission_3061/step2/main.tf @@ -77,9 +77,10 @@ data "cloudfoundry_service" "abap_service_plans" { } resource "cloudfoundry_service_instance" "abap_si" { + depends_on = [cloudfoundry_space_role.space_managers, cloudfoundry_space_role.space_developers] name = local.abap_service_instance_name space = cloudfoundry_space.abap_space.id - service_plan = data.cloudfoundry_service.abap_service_plans.service_plans[var.abap_si_plan] + service_plan = data.cloudfoundry_service.abap_service_plans.service_plans[var.service_plan__abap] type = "managed" parameters = jsonencode({ admin_email = "${var.abap_admin_email}" diff --git a/released/discovery_center/mission_3061/step2/provider.tf b/released/discovery_center/mission_3061/step2/provider.tf index 70b91d16..1b8fc117 100644 --- a/released/discovery_center/mission_3061/step2/provider.tf +++ b/released/discovery_center/mission_3061/step2/provider.tf @@ -9,5 +9,8 @@ terraform { # This will only work if we know the region in advance provider "cloudfoundry" { + # Comment out the origin in case you need it to connect to your CF environment + # ---------------------------------------------------------------------------- + # origin = var.origin api_url = var.cf_api_url } diff --git a/released/discovery_center/mission_3061/step2/variables.tf b/released/discovery_center/mission_3061/step2/variables.tf index 63c3c244..48e7deb7 100644 --- a/released/discovery_center/mission_3061/step2/variables.tf +++ b/released/discovery_center/mission_3061/step2/variables.tf @@ -19,42 +19,78 @@ variable "cf_org_managers" { type = list(string) description = "List of Cloud Foundry org managers." default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_org_managers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_org_managers) + error_message = "Please enter a valid email address for the Cloud Foundry org managers." + } } variable "cf_org_billing_managers" { type = list(string) description = "List of Cloud Foundry org billing managers." default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_org_billing_managers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_org_billing_managers) + error_message = "Please enter a valid email address for the subaccount admins." + } } variable "cf_org_auditors" { type = list(string) description = "List of Cloud Foundry org auditors." default = [] -} -variable "cf_space_name" { - type = string - description = "The name of the Cloud Foundry space." - default = "dev" + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_org_auditors : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_org_auditors) + error_message = "Please enter a valid email address for the subaccount admins." + } } variable "cf_space_managers" { type = list(string) description = "List of managers for the Cloud Foundry space." default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_space_managers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_space_managers) + error_message = "Please enter a valid email address for the subaccount admins." + } } variable "cf_space_developers" { type = list(string) description = "List of developers for the Cloud Foundry space." default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_space_developers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_space_developers) + error_message = "Please enter a valid email address for the subaccount admins." + } } variable "cf_space_auditors" { type = list(string) description = "The list of Cloud Foundry space auditors." default = [] + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.cf_space_auditors : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_space_auditors) + error_message = "Please enter a valid email address for the subaccount admins." + } +} + +variable "cf_space_name" { + type = string + description = "The name of the Cloud Foundry space." + default = "dev" } variable "abap_sid" { @@ -67,7 +103,7 @@ variable "abap_sid" { } } -variable "abap_si_plan" { +variable "service_plan__abap" { type = string description = "Plan for the service instance of ABAP." default = "standard" @@ -76,6 +112,7 @@ variable "abap_si_plan" { variable "abap_admin_email" { type = string description = "Email of the ABAP Administrator." + default = "" } variable "abap_is_development_allowed" {