diff --git a/released/discovery_center/mission_3501/README.md b/released/discovery_center/mission_3501/README.md deleted file mode 100644 index b39d69cb..00000000 --- a/released/discovery_center/mission_3501/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Discovery Center Mission: Enhance core ERP business processes with resilient applications on SAP BTP (3501) - -## Overview - -This sample shows how to create a landscape for the Discovery Center Mission - [Enhance core ERP business processes with resilient applications on SAP BTP](https://discovery-center.cloud.sap/missiondetail/3501/) - -## Content of setup - -The setup comprises the following resources: - -- Creation of the SAP BTP subaccount -- Entitlements of services -- Subscriptions to applications -- Role collection assignments to users -- Creation of CF environments -- Management of users and roles on org and space level - -## Deploying the resources - -To deploy the resources you must: - -1. Export environment variables BTP_USERNAME, BTP_PASSWORD, CF_USER, and CF_PASSWORD with your username and password for the custom IdP of your global account. - -2. Change the variables in the `samples.tfvars` file in the main folder to meet your requirements - - > ⚠ NOTE: You should pay attention **specifically** to the users defined in the samples.tfvars whether they already exist in your SAP BTP accounts. Otherwise you might get error messages like e.g. `Error: The user could not be found: jane.doe@test.com`. - -3. Execute the apply.sh script. - -4. Verify e.g., in BTP cockpit that a new subaccount with a integration suite, SAP Business Application Studio, CF environment instance and a CF space have been created. - -5. Clean up by running the destroy.sh script. \ No newline at end of file diff --git a/released/discovery_center/mission_3501/apply.sh b/released/discovery_center/mission_3501/apply.sh deleted file mode 100755 index fb333585..00000000 --- a/released/discovery_center/mission_3501/apply.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -cd step1 - -terraform init -terraform apply -var-file='../samples.tfvars' -auto-approve -terraform output > ../step2/step1vars.tfvars - -cd ../step2 - -terraform init -terraform apply -var-file=step1vars.tfvars -var-file='../samples.tfvars' -auto-approve - -cd .. \ No newline at end of file diff --git a/released/discovery_center/mission_3501/destroy.sh b/released/discovery_center/mission_3501/destroy.sh deleted file mode 100755 index c149b746..00000000 --- a/released/discovery_center/mission_3501/destroy.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -cd step2 - -terraform destroy -var-file=step1vars.tfvars -var-file='../samples.tfvars' -auto-approve -rm step1vars.tfvars - -cd ../step1 - -terraform destroy -var-file='../samples.tfvars' -auto-approve - -cd .. \ No newline at end of file diff --git a/released/discovery_center/mission_3501/step1/README.md b/released/discovery_center/mission_3501/step1/README.md new file mode 100644 index 00000000..e8238175 --- /dev/null +++ b/released/discovery_center/mission_3501/step1/README.md @@ -0,0 +1,62 @@ +# Discovery Center Mission: Enhance core ERP business processes with resilient applications on SAP BTP (3501) - Step 1 + +## Overview + +This sample shows how to create a landscape for the Discovery Center Mission - [Enhance core ERP business processes with resilient applications on SAP BTP](https://discovery-center.cloud.sap/missiondetail/3501/) + +## Content of setup + +The setup comprises the following resources: + +- Creation of the SAP BTP subaccount +- Entitlements of services +- Subscriptions to applications +- Role collection assignments to users +- Creation of CF environments +- Management of users and roles on org and space level + +## Deploying the resources + +To deploy the resources you must: + +1. Set your credentials as environment variables + + ```bash + export BTP_USERNAME ='' + export BTP_PASSWORD ='' + export CF_USER ='' + export CF_PASSWORD ='' + ``` + +2. Change the variables in the `sample.tfvars` file in the main folder to meet your requirements + + > The minimal set of parameters you should specify (besides user_email and password) is global account (i.e. its subdomain) and the used custom_idp and all user assignments + + > ⚠ NOTE: You should pay attention **specifically** to the users defined in the sample.tfvars whether they already exist in your SAP BTP accounts. Otherwise, you might get error messages like, e.g., `Error: The user could not be found: jane.doe@test.com`. + + +3. Initialize your workspace: + + ```bash + terraform init + ``` + +4. You can check what Terraform plans to apply based on your configuration: + + ```bash + terraform plan -var-file="sample.tfvars" + ``` + +5. Apply your configuration to provision the resources: + + ```bash + terraform apply -var-file="sample.tfvars" + ``` + +## In the end + +You probably want to remove the assets after trying them out to avoid unnecessary costs. To do so execute the following command: + +```bash +terraform destroy -var-file="sample.tfvars" +``` \ No newline at end of file diff --git a/released/discovery_center/mission_3501/step1/locals.tf b/released/discovery_center/mission_3501/step1/locals.tf deleted file mode 100644 index 90bebd94..00000000 --- a/released/discovery_center/mission_3501/step1/locals.tf +++ /dev/null @@ -1,5 +0,0 @@ -locals { - service__sap_business_app_studio = "sapappstudio" - service_name__hana_cloud_tools = "hana-cloud-tools" - service_name__build_workzone = "SAPLaunchpad" -} \ No newline at end of file diff --git a/released/discovery_center/mission_3501/step1/main.tf b/released/discovery_center/mission_3501/step1/main.tf index 80424d5a..a65ee448 100644 --- a/released/discovery_center/mission_3501/step1/main.tf +++ b/released/discovery_center/mission_3501/step1/main.tf @@ -1,102 +1,117 @@ -############################################################################################### +# ------------------------------------------------------------------------------------------------------ # Setup of names in accordance to naming convention -############################################################################################### +# ------------------------------------------------------------------------------------------------------ resource "random_uuid" "uuid" {} locals { - random_uuid = random_uuid.uuid.result - project_subaccount_domain = lower(replace("mission-3501-${local.random_uuid}", "_", "-")) - project_subaccount_cf_org = substr(replace("${local.project_subaccount_domain}", "-", ""), 0, 32) + random_uuid = random_uuid.uuid.result + subaccount_domain = lower(replace("mission-3501-${local.random_uuid}", "_", "-")) + subaccount_cf_org = "cf-${random_uuid.uuid.result}" +} + +# ------------------------------------------------------------------------------------------------------ +# Subscriptions +# ------------------------------------------------------------------------------------------------------ + +locals { + service__sap_business_app_studio = "sapappstudio" + service_name__hana_cloud_tools = "hana-cloud-tools" + service_name__build_workzone = "SAPLaunchpad" } -############################################################################################### +# ------------------------------------------------------------------------------------------------------ # Creation of subaccount -############################################################################################### -resource "btp_subaccount" "project" { +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount" "dc_mission" { count = var.subaccount_id == "" ? 1 : 0 name = var.subaccount_name - subdomain = local.project_subaccount_domain + subdomain = local.subaccount_domain region = lower(var.region) usage = "USED_FOR_PRODUCTION" } -data "btp_subaccount" "project" { - id = var.subaccount_id != "" ? var.subaccount_id : btp_subaccount.project[0].id +data "btp_subaccount" "dc_mission" { + id = var.subaccount_id != "" ? var.subaccount_id : btp_subaccount.dc_mission[0].id +} + +# ------------------------------------------------------------------------------------------------------ +# Assign custom IDP to sub account (if custom_idp is set) +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_trust_configuration" "fully_customized" { + # Only create trust configuration if custom_idp has been set + count = var.custom_idp == "" ? 0 : 1 + subaccount_id = data.btp_subaccount.dc_mission.id + identity_provider = var.custom_idp } -############################################################################################### +locals { + custom_idp_tenant = var.custom_idp != "" ? element(split(".", var.custom_idp), 0) : "" + origin_key = local.custom_idp_tenant != "" ? "${local.custom_idp_tenant}-platform" : "sap.default" + origin_key_app_users = var.custom_idp != "" ? var.custom_idp_apps_origin_key : "sap.default" +} + +# ------------------------------------------------------------------------------------------------------ # Assignment of users as sub account administrators -############################################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_role_collection_assignment" "subaccount-admins" { - for_each = toset("${var.subaccount_admins}") - subaccount_id = data.btp_subaccount.project.id + for_each = toset(var.subaccount_admins) + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "Subaccount Administrator" + origin = local.origin_key user_name = each.value } -############################################################################################### +# ------------------------------------------------------------------------------------------------------ # Assignment of users as sub account service administrators -############################################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_role_collection_assignment" "subaccount-service-admins" { - for_each = toset("${var.subaccount_service_admins}") - subaccount_id = data.btp_subaccount.project.id + for_each = toset(var.subaccount_service_admins) + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "Subaccount Service Administrator" + origin = local.origin_key user_name = each.value } -###################################################################### +# ------------------------------------------------------------------------------------------------------ # Extract list of CF landscape labels from environments -###################################################################### +# ------------------------------------------------------------------------------------------------------ data "btp_subaccount_environments" "all" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id } # Take the landscape label from the first CF environment if no environment label is provided resource "terraform_data" "cf_landscape_label" { input = length(var.cf_landscape_label) > 0 ? var.cf_landscape_label : [for env in data.btp_subaccount_environments.all.values : env if env.service_name == "cloudfoundry" && env.environment_type == "cloudfoundry"][0].landscape_label } -###################################################################### +# ------------------------------------------------------------------------------------------------------ # Creation of Cloud Foundry environment -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_environment_instance" "cloudfoundry" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id name = var.cf_org_name environment_type = "cloudfoundry" service_name = "cloudfoundry" plan_name = "standard" landscape_label = terraform_data.cf_landscape_label.output parameters = jsonencode({ - instance_name = local.project_subaccount_cf_org + instance_name = local.subaccount_cf_org }) } -###################################################################### -# Entitlement of all general services -###################################################################### -resource "btp_subaccount_entitlement" "genentitlements" { - for_each = { - for index, entitlement in var.entitlements : - index => entitlement - } - subaccount_id = data.btp_subaccount.project.id - service_name = each.value.service_name - plan_name = each.value.plan_name -} - -# ###################################################################### +# # ------------------------------------------------------------------------------------------------------ # # Create app subscription to SAP Business APplication Studio -# ###################################################################### +# # ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "bas" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = local.service__sap_business_app_studio plan_name = var.service_plan__sap_business_app_studio } # Create app subscription to busineass applicaiton stuido resource "btp_subaccount_subscription" "bas" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id app_name = local.service__sap_business_app_studio plan_name = var.service_plan__sap_business_app_studio depends_on = [btp_subaccount_entitlement.bas] @@ -105,36 +120,18 @@ resource "btp_subaccount_subscription" "bas" { resource "btp_subaccount_role_collection_assignment" "bas_dev" { depends_on = [btp_subaccount_subscription.bas] for_each = toset(var.appstudio_developers) - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "Business_Application_Studio_Developer" + origin = local.origin_key_app_users user_name = each.value } resource "btp_subaccount_role_collection_assignment" "bas_admn" { depends_on = [btp_subaccount_subscription.bas] for_each = toset(var.appstudio_admins) - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "Business_Application_Studio_Administrator" - user_name = each.value -} - -###################################################################### -# Assign other Role Collection -###################################################################### - -resource "btp_subaccount_role_collection_assignment" "cloud_conn_admn" { - depends_on = [btp_subaccount_entitlement.genentitlements] - for_each = toset(var.cloudconnector_admins) - subaccount_id = data.btp_subaccount.project.id - role_collection_name = "Cloud Connector Administrator" - user_name = each.value -} - -resource "btp_subaccount_role_collection_assignment" "conn_dest_admn" { - depends_on = [btp_subaccount_entitlement.genentitlements] - for_each = toset(var.conn_dest_admins) - subaccount_id = data.btp_subaccount.project.id - role_collection_name = "Connectivity and Destination Administrator" + origin = local.origin_key_app_users user_name = each.value } @@ -142,13 +139,13 @@ resource "btp_subaccount_role_collection_assignment" "conn_dest_admn" { # Entitle subaccount for usage of SAP HANA Cloud tools # ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "hana_cloud_tools" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = local.service_name__hana_cloud_tools plan_name = "tools" } resource "btp_subaccount_subscription" "hana_cloud_tools" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id app_name = local.service_name__hana_cloud_tools plan_name = "tools" depends_on = [btp_subaccount_entitlement.hana_cloud_tools] @@ -157,9 +154,10 @@ resource "btp_subaccount_subscription" "hana_cloud_tools" { # Assign users to Role Collection: SAP HANA Cloud Administrator resource "btp_subaccount_role_collection_assignment" "hana_cloud_admin" { for_each = toset(var.hana_cloud_admins) - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "SAP HANA Cloud Administrator" user_name = each.value + origin = local.origin_key_app_users depends_on = [btp_subaccount_subscription.hana_cloud_tools] } @@ -167,21 +165,21 @@ resource "btp_subaccount_role_collection_assignment" "hana_cloud_admin" { # Entitle subaccount for usage of SAP HANA Cloud # ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "hana_cloud" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = "hana-cloud" plan_name = "hana" } # Get plan for SAP HANA Cloud data "btp_subaccount_service_plan" "hana_cloud" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id offering_name = "hana-cloud" name = "hana" depends_on = [btp_subaccount_entitlement.hana_cloud] } resource "btp_subaccount_service_instance" "hana_cloud" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id serviceplan_id = data.btp_subaccount_service_plan.hana_cloud.id name = "my-hana-cloud-instance" depends_on = [btp_subaccount_entitlement.hana_cloud] @@ -216,60 +214,62 @@ resource "btp_subaccount_service_instance" "hana_cloud" { # Create service binding to SAP HANA Cloud service resource "btp_subaccount_service_binding" "hana_cloud" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_instance_id = btp_subaccount_service_instance.hana_cloud.id name = "hana-cloud-key" } -###################################################################### +# ------------------------------------------------------------------------------------------------------ # Event Mesh -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "event_mesh" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = "enterprise-messaging" plan_name = "default" } resource "btp_subaccount_entitlement" "event_mesh_application" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = "enterprise-messaging-hub" plan_name = "standard" } resource "btp_subaccount_subscription" "event_mesh_application" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id app_name = "enterprise-messaging-hub" plan_name = "standard" depends_on = [btp_subaccount_entitlement.event_mesh_application] } resource "btp_subaccount_role_collection_assignment" "event_mesh_admin" { - depends_on = [btp_subaccount_entitlement.event_mesh_application] + depends_on = [btp_subaccount_subscription.event_mesh_application] for_each = toset(var.event_mesh_admins) - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "Enterprise Messaging Administrator" + origin = local.origin_key_app_users user_name = each.value } resource "btp_subaccount_role_collection_assignment" "event_mesh_developer" { - depends_on = [btp_subaccount_entitlement.event_mesh_application] + depends_on = [btp_subaccount_subscription.event_mesh_application] for_each = toset(var.event_mesh_developers) - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "Enterprise Messaging Developer" + origin = local.origin_key_app_users user_name = each.value } -###################################################################### +# ------------------------------------------------------------------------------------------------------ # CI CD -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "cicd" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = "cicd-app" plan_name = "default" } resource "btp_subaccount_subscription" "cicd" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id app_name = "cicd-app" plan_name = "default" depends_on = [btp_subaccount_entitlement.cicd] @@ -279,35 +279,36 @@ resource "btp_subaccount_subscription" "cicd" { resource "btp_subaccount_role_collection_assignment" "cicd_service_admin" { depends_on = [btp_subaccount_subscription.cicd] for_each = toset(var.cicd_service_admins) - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "CICD Service Administrator" + origin = local.origin_key_app_users user_name = each.value } -###################################################################### +# ------------------------------------------------------------------------------------------------------ # alm-ts -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "alm_ts" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = "alm-ts" plan_name = "standard" } resource "btp_subaccount_subscription" "alm_ts" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id app_name = "alm-ts" plan_name = "standard" depends_on = [btp_subaccount_entitlement.alm_ts] } data "btp_subaccount_roles" "all" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id depends_on = [btp_subaccount_subscription.alm_ts] } # Create the role collection - admin resource "btp_subaccount_role_collection" "alm_ts_admin" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id name = "TMS Admin" depends_on = [data.btp_subaccount_roles.all] roles = [ @@ -322,14 +323,15 @@ resource "btp_subaccount_role_collection" "alm_ts_admin" { resource "btp_subaccount_role_collection_assignment" "alm_ts_admin" { depends_on = [btp_subaccount_role_collection.alm_ts_admin] for_each = toset(var.tms_admins) - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "TMS Admin" + origin = local.origin_key_app_users user_name = each.value } # Create the role collection - import operator resource "btp_subaccount_role_collection" "alm_ts_import_operator" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id name = "TMS Import Operator" roles = [ @@ -345,45 +347,46 @@ resource "btp_subaccount_role_collection" "alm_ts_import_operator" { resource "btp_subaccount_role_collection_assignment" "alm_ts_import_operator" { depends_on = [btp_subaccount_role_collection.alm_ts_import_operator] for_each = toset(var.tms_import_operators) - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "TMS Import Operator" + origin = local.origin_key_app_users user_name = each.value } -###################################################################### +# ------------------------------------------------------------------------------------------------------ # autoscaler -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "autoscaler" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = "autoscaler" plan_name = "standard" } -###################################################################### +# ------------------------------------------------------------------------------------------------------ # alert-notification -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "alert_notification" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = "alert-notification" plan_name = "standard" } -###################################################################### +# ------------------------------------------------------------------------------------------------------ # application-logs -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "app_logs" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = "application-logs" plan_name = "lite" } -############################################################################################### +# ------------------------------------------------------------------------------------------------------ # Prepare and setup app: SAP Build Workzone, standard edition -############################################################################################### +# ------------------------------------------------------------------------------------------------------ # Entitle subaccount for usage of app destination SAP Build Workzone, standard edition resource "btp_subaccount_entitlement" "build_workzone" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id service_name = local.service_name__build_workzone plan_name = var.service_plan__build_workzone amount = var.service_plan__build_workzone == "free" ? 1 : null @@ -391,7 +394,7 @@ resource "btp_subaccount_entitlement" "build_workzone" { # Create app subscription to SAP Build Workzone, standard edition (depends on entitlement) resource "btp_subaccount_subscription" "build_workzone" { - subaccount_id = data.btp_subaccount.project.id + subaccount_id = data.btp_subaccount.dc_mission.id app_name = local.service_name__build_workzone plan_name = var.service_plan__build_workzone depends_on = [btp_subaccount_entitlement.build_workzone] @@ -399,10 +402,41 @@ resource "btp_subaccount_subscription" "build_workzone" { # Assign users to Role Collection: Launchpad_Admin (SAP Build Workzone, standard edition) resource "btp_subaccount_role_collection_assignment" "launchpad_admin" { - for_each = toset("${var.workzone_se_administrators}") - subaccount_id = data.btp_subaccount.project.id + for_each = toset(var.workzone_se_administrators) + subaccount_id = data.btp_subaccount.dc_mission.id role_collection_name = "Launchpad_Admin" + origin = local.origin_key_app_users user_name = each.value depends_on = [btp_subaccount_subscription.build_workzone] } +# ------------------------------------------------------------------------------------------------------ +# Create tfvars file for step 2 (if variable `create_tfvars_file_for_step2` is set to true) +# ------------------------------------------------------------------------------------------------------ +resource "local_file" "output_vars_step1" { + count = var.create_tfvars_file_for_step2 ? 1 : 0 + content = <<-EOT + globalaccount = "${var.globalaccount}" + cli_server_url = ${jsonencode(var.cli_server_url)} + custom_idp = ${jsonencode(var.custom_idp)} + + subaccount_id = "${data.btp_subaccount.dc_mission.id}" + + cf_api_url = "${jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["API Endpoint"]}" + + cf_org_id = "${jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["Org ID"]}" + cf_org_name = "${jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["Org Name"]}" + + cf_space_name = "${var.cf_space_name}" + + cf_org_users = ${jsonencode(var.cf_org_users)} + cf_org_admins = ${jsonencode(var.cf_org_admins)} + cf_space_developers = ${jsonencode(var.cf_space_developers)} + cf_space_managers = ${jsonencode(var.cf_space_managers)} + + + EOT + filename = "../step2/terraform.tfvars" +} + + diff --git a/released/discovery_center/mission_3501/step1/outputs.tf b/released/discovery_center/mission_3501/step1/outputs.tf index 56f90f7b..fc566926 100644 --- a/released/discovery_center/mission_3501/step1/outputs.tf +++ b/released/discovery_center/mission_3501/step1/outputs.tf @@ -11,5 +11,24 @@ output "cf_org_id" { } output "subaccount_id" { - value = data.btp_subaccount.project.id + value = data.btp_subaccount.dc_mission.id +} + +output "bas_url" { + value = btp_subaccount_subscription.bas.subscription_url +} +output "hana_cloud_tools_url" { + value = btp_subaccount_subscription.hana_cloud_tools.subscription_url +} +output "cicd_url" { + value = btp_subaccount_subscription.cicd.subscription_url +} +output "event_mesh_application_url" { + value = btp_subaccount_subscription.event_mesh_application.subscription_url +} +output "alm_ts_url" { + value = btp_subaccount_subscription.alm_ts.subscription_url +} +output "build_workzone_url" { + value = btp_subaccount_subscription.build_workzone.subscription_url } \ No newline at end of file diff --git a/released/discovery_center/mission_3501/samples.tfvars b/released/discovery_center/mission_3501/step1/sample.tfvars similarity index 77% rename from released/discovery_center/mission_3501/samples.tfvars rename to released/discovery_center/mission_3501/step1/sample.tfvars index 66d600f8..79927a9c 100644 --- a/released/discovery_center/mission_3501/samples.tfvars +++ b/released/discovery_center/mission_3501/step1/sample.tfvars @@ -1,15 +1,13 @@ globalaccount = "myglobalaccount" region = "us10" subaccount_name = "Discovery Center mission - 3501" -cf_org_name = "cf-environment" +custom_idp = "<>.accounts.ondemand.com" subaccount_admins = ["john.doe@sap.com"] subaccount_service_admins = ["john.doe@sap.com"] -appstudio_developers = ["john.doe@sap.com"] -appstudio_admins = ["john.doe@sap.com"] -cloudconnector_admins = ["john.doe@sap.com"] -conn_dest_admins = ["john.doe@sap.com"] +appstudio_developers = ["john.doe@sap.com"] +appstudio_admins = ["john.doe@sap.com"] cf_space_developers = ["john.doe@sap.com"] cf_space_managers = ["john.doe@sap.com"] diff --git a/released/discovery_center/mission_3501/step1/variables.tf b/released/discovery_center/mission_3501/step1/variables.tf index 8a7d2e66..7e979676 100644 --- a/released/discovery_center/mission_3501/step1/variables.tf +++ b/released/discovery_center/mission_3501/step1/variables.tf @@ -4,8 +4,7 @@ # subaccount variable "globalaccount" { type = string - description = "The globalaccount subdomain." - default = "yourglobalaccount" + description = "The globalaccount subdomain where the sub account shall be created." } variable "subaccount_id" { @@ -49,29 +48,77 @@ variable "cli_server_url" { default = "https://cli.btp.cloud.sap" } +variable "custom_idp" { + type = string + description = "The custom identity provider for the subaccount." + default = "" +} + +variable "custom_idp_apps_origin_key" { + type = string + description = "The custom identity provider for the subaccount." + default = "sap.custom" +} + +variable "origin" { + type = string + description = "Defines the origin key of the identity provider" + default = "sap.ids" + # The value for the origin_key can be defined + # but are normally set to "sap.ids", "sap.default" or "sap.custom" +} + +variable "origin_key" { + type = string + description = "Defines the origin key of the identity provider" + default = "" + # The value for the origin_key can be defined, set to "sap.ids", "sap.default" or "sap.custom" +} + # subaccount variables variable "subaccount_admins" { type = list(string) description = "Defines the colleagues who are added to each subaccount as subaccount administrators." - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if admins contains a list of valid email addresses - validation { - condition = length([for email in var.subaccount_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.subaccount_admins) - error_message = "Please enter a valid email address for the Subaccount Admins." - } } variable "subaccount_service_admins" { type = list(string) description = "Defines the colleagues who are added to each subaccount as subaccount service administrators." - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if admins contains a list of valid email addresses +} + +variable "cf_space_name" { + type = string + description = "Name of the Cloud Foundry space." + default = "dev" + validation { - condition = length([for email in var.subaccount_service_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.subaccount_service_admins) - error_message = "Please enter a valid email address for the Subaccount service Admins." + condition = can(regex("^.{1,255}$", var.cf_space_name)) + error_message = "The Cloud Foundry space name must not be emtpy and not exceed 255 characters." } } +variable "cf_org_admins" { + type = list(string) + description = "List of users to set as Cloudfoundry org administrators." +} + +variable "cf_org_users" { + type = list(string) + description = "List of users to set as Cloudfoundry org users." +} + +variable "cf_space_managers" { + type = list(string) + description = "Defines the colleagues who are added to a CF space as space manager." +} + +variable "cf_space_developers" { + type = list(string) + description = "Defines the colleagues who are added to a CF space as space developer." +} + + + variable "service_plan__sap_business_app_studio" { type = string description = "The plan for SAP Business Application Studio" @@ -82,94 +129,19 @@ variable "service_plan__sap_business_app_studio" { } } -### -# Entitlements -### -variable "entitlements" { - type = list(object({ - service_name = string - plan_name = string - type = string - })) - description = "The list of entitlements that shall be added to the subaccount." - default = [ - { - service_name = "connectivity" - plan_name = "lite", - type = "service" - }, - { - service_name = "destination" - plan_name = "lite", - type = "service" - }, - { - service_name = "html5-apps-repo" - plan_name = "app-host", - type = "service" - }, - { - service_name = "xsuaa" - plan_name = "application", - type = "service" - } - ] -} - variable "appstudio_developers" { type = list(string) description = "Business Application Studio Developers" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if Business Application Studio Developers contains a list of valid email addresses - validation { - condition = length([for email in var.appstudio_developers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.appstudio_developers) - error_message = "Please enter a valid email address for the Business Application Studio Developers" - } } variable "appstudio_admins" { type = list(string) description = "Business Application Studio Administrators" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if Business Application Studio Administrators contains a list of valid email addresses - validation { - condition = length([for email in var.appstudio_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.appstudio_admins) - error_message = "Please enter a valid email address for the Business Application Studio Administrators." - } -} - -variable "cloudconnector_admins" { - type = list(string) - description = "Cloud Connector Administrators" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if Cloud Connector Administrators contains a list of valid email addresses - validation { - condition = length([for email in var.cloudconnector_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cloudconnector_admins) - error_message = "Please enter a valid email address for the Cloud Connector Administrators." - } -} - -variable "conn_dest_admins" { - type = list(string) - description = "Connectivity and Destination Administrators" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if Connectivity and Destination Administrators contains a list of valid email addresses - validation { - condition = length([for email in var.conn_dest_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.conn_dest_admins) - error_message = "Please enter a valid email address for the Connectivity and Destination Administrators." - } } variable "hana_cloud_admins" { type = list(string) description = "Defines the colleagues who are added as admins to access the instance of SAP HANA Cloud." - default = ["jane.doe@test.com", "john.doe@test.com"] - - # add validation to check if admins contains a list of valid email addresses - validation { - condition = length([for email in var.hana_cloud_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.hana_cloud_admins) - error_message = "Please enter a valid email address for the admins of SAP HANA Cloud instance." - } } @@ -207,23 +179,11 @@ variable "hana_system_password" { variable "event_mesh_admins" { type = list(string) description = "Enterprise Messaging Administrators" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if admins contains a list of valid email addresses - validation { - condition = length([for email in var.event_mesh_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.event_mesh_admins) - error_message = "Please enter a valid email address for the Enterprise Messaging Administrators." - } } variable "event_mesh_developers" { type = list(string) description = "Enterprise Messaging Developers" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if Enterprise Messaging Developers contains a list of valid email addresses - validation { - condition = length([for email in var.event_mesh_developers : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.event_mesh_developers) - error_message = "Please enter a valid email address for the Enterprise Messaging Developers." - } } variable "service_plan__build_workzone" { @@ -239,45 +199,30 @@ variable "service_plan__build_workzone" { variable "workzone_se_administrators" { type = list(string) description = "Workzone Standard Edition Administrators" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if Workzone Standard Edition Administrators contains a list of valid email addresses - validation { - condition = length([for email in var.workzone_se_administrators : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.workzone_se_administrators) - error_message = "Please enter a valid email address for the Workzone Standard Edition Administratorss." - } } variable "tms_admins" { type = list(string) description = "TMS Administrators" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if TMS Administrators contains a list of valid email addresses - validation { - condition = length([for email in var.tms_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.tms_admins) - error_message = "Please enter a valid email address for the TMS Administrators." - } } variable "tms_import_operators" { type = list(string) description = "TMS Import Operators" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if TMS Import Operators contains a list of valid email addresses - validation { - condition = length([for email in var.tms_import_operators : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.tms_import_operators) - error_message = "Please enter a valid email address for the TMS Import Operators." - } } variable "cicd_service_admins" { type = list(string) description = "CICD Service Administrators" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if CICD Service Administrators contains a list of valid email addresses - validation { - condition = length([for email in var.cicd_service_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cicd_service_admins) - error_message = "Please enter a valid email address for the CICD Service Administrators." - } +} + +# ------------------------------------------------------------------------------------------------------ +# Switch for creating tfvars for step 2 +# ------------------------------------------------------------------------------------------------------ +variable "create_tfvars_file_for_step2" { + type = bool + description = "Switch to enable the creation of the tfvars file for step 2." + default = true } diff --git a/released/discovery_center/mission_3501/step2/README.md b/released/discovery_center/mission_3501/step2/README.md new file mode 100644 index 00000000..5f36c77a --- /dev/null +++ b/released/discovery_center/mission_3501/step2/README.md @@ -0,0 +1,39 @@ +# Discovery Center Mission: Enhance core ERP business processes with resilient applications on SAP BTP (3501) - Step 2 + +## Overview + +This script shows how to create a SAP BTP subaccount for Discovery Center Mission: Enhance core ERP business processes with resilient applications on SAP BTP (3501). Step 2 comprises all activities that depend on the step 1 completion. + + +## Deploying the resources + +To deploy the resources you must: + + +1. If you did not create a `tfvars` file in step 1 (via the variable `create_tfvars_file_for_step2`) you must manually Take the output of step 1 and transfer it in a `tfvars` file e.g. `sample.tfvars` file to meet your requirements. Of course you can also further adjust the generated `tfvars` file from step 1. + +2. If not already done in step 1, initialize your workspace: + + ```bash + terraform init + ``` + +3. You can check what Terraform plans to apply based on your configuration. If you use the generated `tfvars` file from step 1 you do not need need to explicitly add the filename to the command: + + ```bash + terraform plan -var-file="terraform.tfvars" + ``` + +4. According to the variants of step 3. apply your configuration to provision the resources either via: + + ```bash + terraform apply -var-file="terraform.tfvars" + ``` + +## In the end + +You probably want to remove the assets after trying them out to avoid unnecessary costs. To do so execute the command fitting your setup: + +```bash +terraform destroy -var-file="terraform.tfvars" +``` diff --git a/released/discovery_center/mission_3501/step2/main.tf b/released/discovery_center/mission_3501/step2/main.tf index b4812ee4..653fa227 100644 --- a/released/discovery_center/mission_3501/step2/main.tf +++ b/released/discovery_center/mission_3501/step2/main.tf @@ -1,26 +1,65 @@ -###################################################################### +# ------------------------------------------------------------------------------------------------------ +# Import custom trust config and disable for user login +# ------------------------------------------------------------------------------------------------------ +locals { + available_for_user_logon = var.custom_idp != "" ? false : true +} + +import { + to = btp_subaccount_trust_configuration.default + id = "${var.subaccount_id},sap.default" +} + +resource "btp_subaccount_trust_configuration" "default" { + subaccount_id = var.subaccount_id + identity_provider = "" + auto_create_shadow_users = false + available_for_user_logon = local.available_for_user_logon +} + +# ------------------------------------------------------------------------------------------------------ # Create space using CF provider -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "cloudfoundry_space" "dev" { - name = "DEV" + name = var.cf_space_name org = var.cf_org_id } -###################################################################### +# ------------------------------------------------------------------------------------------------------ +# SETUP ALL SERVICES FOR CF USAGE +# ------------------------------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------------------------------ +# USERS AND ROLES +# ------------------------------------------------------------------------------------------------------ +data "btp_whoami" "me" {} + +locals { + # Remove current user if issuer (idp) of logged in user is not same as used custom idp + cf_org_admins = data.btp_whoami.me.issuer != var.custom_idp ? var.cf_org_admins : setsubtract(toset(var.cf_org_admins), [data.btp_whoami.me.email]) + cf_org_users = data.btp_whoami.me.issuer != var.custom_idp ? var.cf_org_admins : setsubtract(toset(var.cf_org_users), [data.btp_whoami.me.email]) + + # get origin_key from custom.idp + custom_idp_tenant = var.custom_idp != "" ? element(split(".", var.custom_idp), 0) : "" + origin_key = local.custom_idp_tenant != "" ? "${local.custom_idp_tenant}-platform" : "sap.ids" +} + +# ------------------------------------------------------------------------------------------------------ # add org and space users and managers -###################################################################### +# ------------------------------------------------------------------------------------------------------ resource "cloudfoundry_org_role" "organization_user" { - for_each = toset(var.cf_org_users) + for_each = toset(local.cf_org_users) username = each.value type = "organization_user" org = var.cf_org_id + origin = local.origin_key } resource "cloudfoundry_org_role" "organization_manager" { - for_each = toset(var.cf_org_admins) + for_each = toset(local.cf_org_admins) username = each.value type = "organization_manager" org = var.cf_org_id + origin = local.origin_key } resource "cloudfoundry_space_role" "space_developer" { @@ -28,6 +67,7 @@ resource "cloudfoundry_space_role" "space_developer" { username = each.value type = "space_developer" space = cloudfoundry_space.dev.id + origin = local.origin_key depends_on = [cloudfoundry_org_role.organization_user, cloudfoundry_org_role.organization_manager] } @@ -36,5 +76,6 @@ resource "cloudfoundry_space_role" "space_manager" { username = each.value type = "space_manager" space = cloudfoundry_space.dev.id + origin = local.origin_key depends_on = [cloudfoundry_org_role.organization_user, cloudfoundry_org_role.organization_manager] -} \ No newline at end of file +} diff --git a/released/discovery_center/mission_3501/step2/outputs.tf b/released/discovery_center/mission_3501/step2/outputs.tf deleted file mode 100644 index ad4178cd..00000000 --- a/released/discovery_center/mission_3501/step2/outputs.tf +++ /dev/null @@ -1,19 +0,0 @@ -output "subaccount_id" { - value = var.subaccount_id -} - -output "cf_landscape_label" { - value = var.cf_landscape_label -} - -output "cf_org_id" { - value = var.cf_org_id -} - -output "cf_api_url" { - value = var.cf_api_url -} - -output "cf_space_name" { - value = cloudfoundry_space.dev.name -} \ No newline at end of file diff --git a/released/discovery_center/mission_3501/step2/provider.tf b/released/discovery_center/mission_3501/step2/provider.tf index b58d086e..7d04ed08 100644 --- a/released/discovery_center/mission_3501/step2/provider.tf +++ b/released/discovery_center/mission_3501/step2/provider.tf @@ -4,13 +4,19 @@ terraform { source = "SAP/cloudfoundry" version = "1.0.0-rc1" } + btp = { + source = "SAP/btp" + version = "~> 1.5.0" + } } } -###################################################################### -# Configure CF provider -###################################################################### +provider "btp" { + globalaccount = var.globalaccount + cli_server_url = var.cli_server_url +} + + provider "cloudfoundry" { - # resolve API URL from environment instance api_url = var.cf_api_url -} \ No newline at end of file +} diff --git a/released/discovery_center/mission_3501/step2/variables.tf b/released/discovery_center/mission_3501/step2/variables.tf index 0b435101..d5554516 100644 --- a/released/discovery_center/mission_3501/step2/variables.tf +++ b/released/discovery_center/mission_3501/step2/variables.tf @@ -1,8 +1,23 @@ -variable "cf_api_url" { - type = string +variable "globalaccount" { + type = string + description = "The globalaccount subdomain where the sub account shall be created." +} + +# The BTP CLI server URL +variable "cli_server_url" { + type = string + description = "The BTP CLI server URL." + default = "https://cli.btp.cloud.sap" +} + +# The CF Org name from the Cloud Foundry environment instance +variable "cf_org_name" { + type = string + description = "The Cloud Foundry Org name from the Cloud Foundry environment instance." + } -variable "cf_landscape_label" { +variable "cf_api_url" { type = string } @@ -17,43 +32,36 @@ variable "subaccount_id" { variable "cf_space_developers" { type = list(string) description = "CF Space developers" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if CF Space developers 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 CF Space developers." - } } variable "cf_space_managers" { type = list(string) description = "CF Space managers" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if CF Space managers 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 Cloud Connector Administrators." - } } variable "cf_org_admins" { type = list(string) description = "CF Org Admins" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if CF Org Admins contains a list of valid email addresses - validation { - condition = length([for email in var.cf_org_admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_org_admins) - error_message = "Please enter a valid email address for the CF Org Admins." - } } variable "cf_org_users" { type = list(string) description = "CF Org Users" - default = ["jane.doe@test.com", "john.doe@test.com"] - # add validation to check if CF Org Users contains a list of valid email addresses +} + +variable "custom_idp" { + type = string + description = "Defines the custom IDP to be used for the subaccount" + default = "" +} + +variable "cf_space_name" { + type = string + description = "Name of the Cloud Foundry space." + default = "dev" + validation { - condition = length([for email in var.cf_org_users : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.cf_org_users) - error_message = "Please enter a valid email address for the CF Org Users." + condition = can(regex("^.{1,255}$", var.cf_space_name)) + error_message = "The Cloud Foundry space name must not be emtpy and not exceed 255 characters." } }