From 2039e5302cec4947112d1070fc8321f6f849fbbe Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Tue, 2 Jul 2024 09:57:28 +0000 Subject: [PATCH 01/14] initial commit --- .../discovery_center/mission_4371/README.md | 56 ++++++++++ .../discovery_center/mission_4371/main.tf | 42 ++++++++ .../mission_4371/modules/ai/ai.tf | 90 ++++++++++++++++ .../mission_4371/modules/ai/ai_outputs.tf | 21 ++++ .../mission_4371/modules/ai/ai_variables.tf | 70 ++++++++++++ .../modules/hana-cloud/hana_cloud.tf | 94 ++++++++++++++++ .../modules/hana-cloud/hana_cloud_outputs.tf | 20 ++++ .../hana-cloud/hana_cloud_variables.tf | 49 +++++++++ .../discovery_center/mission_4371/provider.tf | 13 +++ .../mission_4371/sample.tfvars | 35 ++++++ .../mission_4371/variables.tf | 100 ++++++++++++++++++ 11 files changed, 590 insertions(+) create mode 100644 released/discovery_center/mission_4371/README.md create mode 100644 released/discovery_center/mission_4371/main.tf create mode 100644 released/discovery_center/mission_4371/modules/ai/ai.tf create mode 100644 released/discovery_center/mission_4371/modules/ai/ai_outputs.tf create mode 100644 released/discovery_center/mission_4371/modules/ai/ai_variables.tf create mode 100644 released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud.tf create mode 100644 released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_outputs.tf create mode 100644 released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_variables.tf create mode 100644 released/discovery_center/mission_4371/provider.tf create mode 100644 released/discovery_center/mission_4371/sample.tfvars create mode 100644 released/discovery_center/mission_4371/variables.tf diff --git a/released/discovery_center/mission_4371/README.md b/released/discovery_center/mission_4371/README.md new file mode 100644 index 00000000..a5b72470 --- /dev/null +++ b/released/discovery_center/mission_4371/README.md @@ -0,0 +1,56 @@ +# Setting up a sub account with the SAP AI Core service deployed + +## Overview + +This script shows how to create a SAP BTP subaccount with the `SAP AI Core` service deployed + +## Content of setup + +The setup comprises the following resources: + +- Creation of a SAP BTP subaccount +- Entitlement of the SAP AI Core service +- Entitlement and setup of SAP HANA Cloud (incl. hana cloud tools) +- Role collection assignments to users + +## Deploying the resources + +To deploy the resources you must: + +1. Change the variables in the `sample.tfvars` file to meet your requirements + + +2. Export the variables for user name and password + + ```bash + export BTP_USERNAME='' + export BTP_PASSWORD='' + ``` + +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" + ``` + +6. You'll notice, that a `.env` file has been created, containing some environment variables that you can use for your genAI experiments. + +## 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 +``` diff --git a/released/discovery_center/mission_4371/main.tf b/released/discovery_center/mission_4371/main.tf new file mode 100644 index 00000000..0e1c9f21 --- /dev/null +++ b/released/discovery_center/mission_4371/main.tf @@ -0,0 +1,42 @@ +# ------------------------------------------------------------------------------------------------------ +# Setup subaccount domain (to ensure uniqueness in BTP global account) +# ------------------------------------------------------------------------------------------------------ +resource "random_id" "subaccount_domain_suffix" { + byte_length = 12 +} + +# ------------------------------------------------------------------------------------------------------ +# Creation of subaccount +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount" "gen_ai" { + name = var.subaccount_name + subdomain = join("-", ["genai-starter-kit", random_id.subaccount_domain_suffix.hex]) + region = lower(var.region) +} + +# ------------------------------------------------------------------------------------------------------ +# Prepare & setup the SAP AI Core service (ensure your global account has the respective entitlements) +# ------------------------------------------------------------------------------------------------------ +module "ai_setup" { + source = "./modules/ai" + + subaccount_id = btp_subaccount.gen_ai.id + setup_ai_launchpad = var.setup_ai_launchpad + ai_core_plan_name = var.ai_core_plan_name + target_ai_core_model = var.target_ai_core_model + admins = var.admins + +} + +module "hana_cloud_setup" { + source = "./modules/hana-cloud" + + subaccount_id = btp_subaccount.gen_ai.id + hana_system_password = var.hana_system_password + admins = var.admins +} + +resource "local_file" "env_file" { + content = join("\n", [module.ai_setup.ai_core_envs, module.hana_cloud_setup.hana_cloud_envs]) + filename = ".env" +} diff --git a/released/discovery_center/mission_4371/modules/ai/ai.tf b/released/discovery_center/mission_4371/modules/ai/ai.tf new file mode 100644 index 00000000..3f583901 --- /dev/null +++ b/released/discovery_center/mission_4371/modules/ai/ai.tf @@ -0,0 +1,90 @@ +# ------------------------------------------------------------------------------------------------------ +# Prepare & setup the SAP AI Core service (ensure your global account has the respective entitlements) +# ------------------------------------------------------------------------------------------------------ +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.4.0" + } + } +} +# ------------------------------------------------------------------------------------------------------ +# Prepare the list of admins and roles for the AI Launchpad +# ------------------------------------------------------------------------------------------------------ +locals { + role_mapping_admins_ai_launchpad = distinct(flatten([ + for admin in var.admins : [ + for role in var.roles_ai_launchpad : { + user_name = admin + role_name = role + } + ] + ] + )) +} + +# Entitle subaccount for usage of SAP AI Core service +# ------------------------------------------------------------------------------------------------------ +# Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for +# available plans and their region availability +resource "btp_subaccount_entitlement" "ai_core" { + subaccount_id = var.subaccount_id + service_name = "aicore" + plan_name = var.ai_core_plan_name +} + +# Get plan for SAP AI Core service +data "btp_subaccount_service_plan" "ai_core" { + subaccount_id = var.subaccount_id + offering_name = "aicore" + name = var.ai_core_plan_name + depends_on = [btp_subaccount_entitlement.ai_core] +} + +# Create service instance for SAP AI Core service +resource "btp_subaccount_service_instance" "ai_core" { + subaccount_id = var.subaccount_id + serviceplan_id = data.btp_subaccount_service_plan.ai_core.id + name = "my-ai-core-instance" + depends_on = [btp_subaccount_entitlement.ai_core] +} + +# Create service binding to SAP AI Core service (exposed for a specific user group) +resource "btp_subaccount_service_binding" "ai_core_binding" { + subaccount_id = var.subaccount_id + service_instance_id = btp_subaccount_service_instance.ai_core.id + name = "ai-core-key" +} + +# ------------------------------------------------------------------------------------------------------ +# Prepare & setup SAP AI Launchpad +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "ai_launchpad" { + count = var.setup_ai_launchpad ? 1 : 0 + + subaccount_id = var.subaccount_id + service_name = "ai-launchpad" + plan_name = "standard" +} + +resource "btp_subaccount_subscription" "ai_launchpad" { + count = var.setup_ai_launchpad ? 1 : 0 + + subaccount_id = var.subaccount_id + app_name = "ai-launchpad" + plan_name = "standard" + depends_on = [btp_subaccount_entitlement.ai_launchpad] +} + +# Assign users to Role Collection of SAP AI Launchpad +resource "btp_subaccount_role_collection_assignment" "ai_launchpad_role_mapping" { + + for_each = { for entry in local.role_mapping_admins_ai_launchpad : "${entry.user_name}.${entry.role_name}" => entry + if var.setup_ai_launchpad == true } + + subaccount_id = var.subaccount_id + role_collection_name = each.value.role_name + user_name = each.value.user_name + depends_on = [btp_subaccount_subscription.ai_launchpad] +} diff --git a/released/discovery_center/mission_4371/modules/ai/ai_outputs.tf b/released/discovery_center/mission_4371/modules/ai/ai_outputs.tf new file mode 100644 index 00000000..d6030a9a --- /dev/null +++ b/released/discovery_center/mission_4371/modules/ai/ai_outputs.tf @@ -0,0 +1,21 @@ +output "ai_core_service_instance_id" { + value = btp_subaccount_service_instance.ai_core.id + description = "The ID of the AI Core service instance." +} + +output "ai_core_service_instance_name" { + value = btp_subaccount_service_instance.ai_core.name + description = "The ID of the AI Core service instance." +} + +output "ai_core_envs" { + value = <<-EOT + AICORE_AUTH_URL=${jsondecode(btp_subaccount_service_binding.ai_core_binding.credentials)["url"]} + AICORE_CLIENT_ID=${jsondecode(btp_subaccount_service_binding.ai_core_binding.credentials)["clientid"]} + AICORE_CLIENT_SECRET=${jsondecode(btp_subaccount_service_binding.ai_core_binding.credentials)["clientsecret"]} + AICORE_BASE_URL=${jsondecode(btp_subaccount_service_binding.ai_core_binding.credentials)["serviceurls"]["AI_API_URL"]} + AICORE_RESOURCE_GROUP=default + TARGET_AI_CORE_MODEL=${jsonencode(var.target_ai_core_model)} + EOT + description = "The environment variables for the AI Core service." +} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/modules/ai/ai_variables.tf b/released/discovery_center/mission_4371/modules/ai/ai_variables.tf new file mode 100644 index 00000000..a8f0c286 --- /dev/null +++ b/released/discovery_center/mission_4371/modules/ai/ai_variables.tf @@ -0,0 +1,70 @@ +variable "subaccount_id" { + type = string + description = "The subaccount domain (has to be unique within the BTP region)." +} + +variable "cli_server_url" { + type = string + description = "The BTP CLI server URL." + default = "https://cpcli.cf.sap.hana.ondemand.com" +} + +variable "ai_core_plan_name" { + type = string + description = "The name of the AI Core service plan." + default = "sap-internal" + validation { + condition = contains(["sap-internal", "extended"], var.ai_core_plan_name) + error_message = "Valid values for ai_core_plan_name are: sap-internal, extended." + } +} + + +variable "target_ai_core_model" { + type = list(any) + description = "Defines the target AI core model to be used by the AI Core service" + default = ["gpt-35-turbo"] + + validation { + condition = length([ + for o in var.target_ai_core_model : true + if contains(["gpt-35-turbo", "gpt-35-turbo-16k", "gpt-4", "gpt-4-32k", "text-embedding-ada-002", "tiiuae--falcon-40b-instruct"], o) + ]) == length(var.target_ai_core_model) + error_message = "Please enter a valid entry for the target_ai_core_model of the AI Core service. Valid values are: gpt-35-turbo, gpt-35-turbo-16k, gpt-4, gpt-4-32k, text-embedding-ada-002, tiiuae--falcon-40b-instruct." + } +} + + +variable "admins" { + type = list(string) + description = "Defines the colleagues who are added to each subaccount as emergency administrators." + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.admins) + error_message = "Please enter a valid email address for the admins." + } + +} + +variable "setup_ai_launchpad" { + type = bool + description = "Switch to enable the setup of the AI Launchpad." + default = false +} + + +# Define roles for a user of the SAP AI Launchpad +variable "roles_ai_launchpad" { + type = list(string) + description = "Defines the list of roles to be assigned to the users in the AI Launchpad." + default = [ + "ailaunchpad_aicore_admin_editor", + "ailaunchpad_allow_all_resourcegroups", + "ailaunchpad_genai_administrator", + "ailaunchpad_mloperations_editor", + "ailaunchpad_connections_editor" + ] + +} + diff --git a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud.tf b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud.tf new file mode 100644 index 00000000..ba771562 --- /dev/null +++ b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud.tf @@ -0,0 +1,94 @@ +# ------------------------------------------------------------------------------------------------------ +# Prepare & setup SAP HANA Cloud for usage of Vector Engine +# ------------------------------------------------------------------------------------------------------ +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.4.0" + } + } +} + +# ------------------------------------------------------------------------------------------------------ +# Entitle subaccount for usage of SAP HANA Cloud tools +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "hana_cloud_tools" { + subaccount_id = var.subaccount_id + service_name = "hana-cloud-tools" + plan_name = "tools" +} + +resource "btp_subaccount_subscription" "hana_cloud_tools" { + subaccount_id = var.subaccount_id + app_name = "hana-cloud-tools" + plan_name = "tools" + depends_on = [btp_subaccount_entitlement.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.admins) + subaccount_id = var.subaccount_id + role_collection_name = "SAP HANA Cloud Administrator" + user_name = each.value + depends_on = [btp_subaccount_subscription.hana_cloud_tools] +} + +# ------------------------------------------------------------------------------------------------------ +# Entitle subaccount for usage of SAP HANA Cloud +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "hana_cloud" { + subaccount_id = var.subaccount_id + service_name = "hana-cloud" + plan_name = "hana" +} + +# Get plan for SAP HANA Cloud +data "btp_subaccount_service_plan" "hana_cloud" { + subaccount_id = var.subaccount_id + offering_name = "hana-cloud" + name = "hana" + depends_on = [btp_subaccount_entitlement.hana_cloud] +} + +resource "btp_subaccount_service_instance" "hana_cloud" { + subaccount_id = var.subaccount_id + serviceplan_id = data.btp_subaccount_service_plan.hana_cloud.id + name = "my-hana-cloud-instance" + depends_on = [btp_subaccount_entitlement.hana_cloud] + parameters = jsonencode( + { + "data" : { + "memory" : 32, + "edition" : "cloud", + "systempassword" : "${var.hana_system_password}", + "additionalWorkers" : 0, + "disasterRecoveryMode" : "no_disaster_recovery", + "enabledservices" : { + "docstore" : false, + "dpserver" : true, + "scriptserver" : false + }, + "requestedOperation" : {}, + "serviceStopped" : false, + "slaLevel" : "standard", + "storage" : 120, + "vcpu" : 2, + "whitelistIPs" : ["0.0.0.0/0"] + } + }) + + timeouts = { + create = "45m" + update = "45m" + delete = "45m" + } +} + +# Create service binding to SAP HANA Cloud service +resource "btp_subaccount_service_binding" "hana_cloud" { + subaccount_id = var.subaccount_id + service_instance_id = btp_subaccount_service_instance.hana_cloud.id + name = "hana-cloud-key" +} diff --git a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_outputs.tf b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_outputs.tf new file mode 100644 index 00000000..7eff1651 --- /dev/null +++ b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_outputs.tf @@ -0,0 +1,20 @@ + +output "hana_cloud_service_instance_id" { + value = btp_subaccount_service_instance.hana_cloud.id + description = "The ID of the HANA Cloud service instance." +} + +output "hana_cloud_service_instance_name" { + value = btp_subaccount_service_instance.hana_cloud.name + description = "The ID of the HANA Cloud service instance." +} + +output "hana_cloud_envs" { + value = <<-EOT + HANA_DB_ADDRESS=${jsondecode(btp_subaccount_service_binding.hana_cloud.credentials)["host"]} + HANA_DB_PORT=${jsondecode(btp_subaccount_service_binding.hana_cloud.credentials)["port"]} + HANA_DB_USER=DBADMIN + HANA_DB_PASSWORD=${var.hana_system_password} + EOT + description = "Environment variables for the HANA Cloud service." +} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_variables.tf b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_variables.tf new file mode 100644 index 00000000..d9618592 --- /dev/null +++ b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_variables.tf @@ -0,0 +1,49 @@ + +variable "subaccount_id" { + type = string + description = "The subaccount id." +} + + +variable "hana_system_password" { + type = string + description = "The password of the database 'superuser' DBADMIN." + sensitive = true + + # add validation to check if the password is at least 8 characters long + validation { + condition = length(var.hana_system_password) > 7 + error_message = "The hana_system_password must be at least 8 characters long." + } + + # add validation to check if the password contains at least one upper case + validation { + condition = can(regex("[A-Z]", var.hana_system_password)) + error_message = "The hana_system_password must contain at least one upper case." + } + + # add validation to check if the password contains at least two lower case characters + validation { + condition = can(regex("[a-z]{2}", var.hana_system_password)) + error_message = "The hana_system_password must contain at least two lower case characters." + } + + # add validation to check if the password contains at least one numeric character + validation { + condition = can(regex("[0-9]", var.hana_system_password)) + error_message = "The hana_system_password must contain at least one numeric character." + } + +} + +variable "admins" { + type = list(string) + description = "Defines the colleagues who are added to each subaccount as emergency administrators." + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.admins) + error_message = "Please enter a valid email address for the admins." + } + +} diff --git a/released/discovery_center/mission_4371/provider.tf b/released/discovery_center/mission_4371/provider.tf new file mode 100644 index 00000000..7ceab97d --- /dev/null +++ b/released/discovery_center/mission_4371/provider.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + btp = { + source = "SAP/btp" + version = "~> 1.4.0" + } + } +} + +provider "btp" { + globalaccount = var.globalaccount + cli_server_url = var.cli_server_url +} diff --git a/released/discovery_center/mission_4371/sample.tfvars b/released/discovery_center/mission_4371/sample.tfvars new file mode 100644 index 00000000..26d67865 --- /dev/null +++ b/released/discovery_center/mission_4371/sample.tfvars @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------------------------------------------ +# Your BTP user credentials (you can also provide them as environment variables) +# ------------------------------------------------------------------------------------------------------ +#BTP_USERNAME="your.email@test.com" +# ------------------------------------------------------------------------------------------------------ +# Comment out the next line if you want to provide the password here instead of typing it in the console (not recommended for security reasons) +#BTP_PASSWORD="xxxxx" + +# ------------------------------------------------------------------------------------------------------ +# Provider configuration +# ------------------------------------------------------------------------------------------------------ +# Your global account subdomain +globalaccount = "xxxxxxxx-xxxxxxx-xxxxxxx-xxxxxxxx-xxxxxx" + +# The CLI server URL (needs to be set to null if you are using the default CLI server) +cli_server_url = null + +# Region for your subaccount +region = "us10" + +# Name of your sub account +subaccount_name = "GenAI on BTP" + +# If set to true, the script will create an app subscription for the AI Launchpad +setup_ai_launchpad = false + +# The model that the AI Core service should use +target_ai_core_model = ["gpt-35-turbo", "text-embedding-ada-002"] + +# The admin users +admins = ["jane.doe@test.com", "your.email@test.com"] + +# Comment out the next line if you want to provide the password here instead of typing it in the console (not recommended for security reasons) +#hana_system_password = "xxxxxx" + diff --git a/released/discovery_center/mission_4371/variables.tf b/released/discovery_center/mission_4371/variables.tf new file mode 100644 index 00000000..fee2f6cf --- /dev/null +++ b/released/discovery_center/mission_4371/variables.tf @@ -0,0 +1,100 @@ +variable "globalaccount" { + type = string + description = "The globalaccount subdomain where the sub account shall be created." +} + +variable "setup_ai_launchpad" { + type = bool + description = "Switch to enable the setup of the AI Launchpad." + default = true +} + +variable "subaccount_name" { + type = string + description = "The subaccount name." + default = "My SAP Build Apps subaccount." +} + +variable "cli_server_url" { + type = string + description = "The BTP CLI server URL." + default = "https://cpcli.cf.sap.hana.ondemand.com" +} + +variable "ai_core_plan_name" { + type = string + description = "The name of the AI Core service plan." + default = "extended" + validation { + condition = contains(["extended"], var.ai_core_plan_name) + error_message = "Valid values for ai_core_plan_name are: extended." + } +} + +variable "hana_system_password" { + type = string + description = "The password of the database 'superuser' DBADMIN." + sensitive = true + + # add validation to check if the password is at least 8 characters long + validation { + condition = length(var.hana_system_password) > 7 + error_message = "The hana_system_password must be at least 8 characters long." + } + + # add validation to check if the password contains at least one upper case + validation { + condition = can(regex("[A-Z]", var.hana_system_password)) + error_message = "The hana_system_password must contain at least one upper case." + } + + # add validation to check if the password contains at least two lower case characters + validation { + condition = can(regex("[a-z]{2}", var.hana_system_password)) + error_message = "The hana_system_password must contain at least two lower case characters." + } + + # add validation to check if the password contains at least one numeric character + validation { + condition = can(regex("[0-9]", var.hana_system_password)) + error_message = "The hana_system_password must contain at least one numeric character." + } +} + +variable "target_ai_core_model" { + type = list(any) + description = "Defines the target AI core model to be used by the AI Core service" + default = ["gpt-35-turbo"] + + validation { + condition = length([ + for o in var.target_ai_core_model : true + if contains(["gpt-35-turbo", "gpt-35-turbo-16k", "gpt-4", "gpt-4-32k", "text-embedding-ada-002", "tiiuae--falcon-40b-instruct"], o) + ]) == length(var.target_ai_core_model) + error_message = "Please enter a valid entry for the target_ai_core_model of the AI Core service. Valid values are: gpt-35-turbo, gpt-35-turbo-16k, gpt-4, gpt-4-32k, text-embedding-ada-002, tiiuae--falcon-40b-instruct." + } +} + +variable "region" { + type = string + description = "The region where the sub account shall be created in." + default = "us10" + + # Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for the latest list of regions + # supported by the AI Core service. + validation { + condition = contains(["eu10-canary", "ap10", "eu10", "eu11", "jp10", "us10"], var.region) + error_message = "Please enter a valid region for the sub account. Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for regions providing the AI Core service." + } +} + +variable "admins" { + type = list(string) + description = "Defines the colleagues who are added to each subaccount as emergency administrators." + + # add validation to check if admins contains a list of valid email addresses + validation { + condition = length([for email in var.admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.admins) + error_message = "Please enter a valid email address for the admins." + } +} From e071c8b3b5fac899b8f408c7c882b7854db224b2 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Tue, 2 Jul 2024 10:00:42 +0000 Subject: [PATCH 02/14] remove modules --- .../discovery_center/mission_4371/main.tf | 124 ++++++++++++++++-- .../mission_4371/modules/ai/ai.tf | 90 ------------- .../mission_4371/modules/ai/ai_outputs.tf | 21 --- .../mission_4371/modules/ai/ai_variables.tf | 70 ---------- .../modules/hana-cloud/hana_cloud.tf | 94 ------------- .../modules/hana-cloud/hana_cloud_outputs.tf | 20 --- .../hana-cloud/hana_cloud_variables.tf | 49 ------- 7 files changed, 112 insertions(+), 356 deletions(-) delete mode 100644 released/discovery_center/mission_4371/modules/ai/ai.tf delete mode 100644 released/discovery_center/mission_4371/modules/ai/ai_outputs.tf delete mode 100644 released/discovery_center/mission_4371/modules/ai/ai_variables.tf delete mode 100644 released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud.tf delete mode 100644 released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_outputs.tf delete mode 100644 released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_variables.tf diff --git a/released/discovery_center/mission_4371/main.tf b/released/discovery_center/mission_4371/main.tf index 0e1c9f21..78780aee 100644 --- a/released/discovery_center/mission_4371/main.tf +++ b/released/discovery_center/mission_4371/main.tf @@ -17,25 +17,125 @@ resource "btp_subaccount" "gen_ai" { # ------------------------------------------------------------------------------------------------------ # Prepare & setup the SAP AI Core service (ensure your global account has the respective entitlements) # ------------------------------------------------------------------------------------------------------ -module "ai_setup" { - source = "./modules/ai" - subaccount_id = btp_subaccount.gen_ai.id - setup_ai_launchpad = var.setup_ai_launchpad - ai_core_plan_name = var.ai_core_plan_name - target_ai_core_model = var.target_ai_core_model - admins = var.admins +# Entitle subaccount for usage of SAP AI Core service +# ------------------------------------------------------------------------------------------------------ +# Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for +# available plans and their region availability +resource "btp_subaccount_entitlement" "ai_core" { + subaccount_id = var.subaccount_id + service_name = "aicore" + plan_name = var.ai_core_plan_name +} + +# Get plan for SAP AI Core service +data "btp_subaccount_service_plan" "ai_core" { + subaccount_id = var.subaccount_id + offering_name = "aicore" + name = var.ai_core_plan_name + depends_on = [btp_subaccount_entitlement.ai_core] +} + +# Create service instance for SAP AI Core service +resource "btp_subaccount_service_instance" "ai_core" { + subaccount_id = var.subaccount_id + serviceplan_id = data.btp_subaccount_service_plan.ai_core.id + name = "my-ai-core-instance" + depends_on = [btp_subaccount_entitlement.ai_core] +} + +# Create service binding to SAP AI Core service (exposed for a specific user group) +resource "btp_subaccount_service_binding" "ai_core_binding" { + subaccount_id = var.subaccount_id + service_instance_id = btp_subaccount_service_instance.ai_core.id + name = "ai-core-key" +} + + +# ------------------------------------------------------------------------------------------------------ +# Entitle subaccount for usage of SAP HANA Cloud tools +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "hana_cloud_tools" { + subaccount_id = var.subaccount_id + service_name = "hana-cloud-tools" + plan_name = "tools" +} + +resource "btp_subaccount_subscription" "hana_cloud_tools" { + subaccount_id = var.subaccount_id + app_name = "hana-cloud-tools" + plan_name = "tools" + depends_on = [btp_subaccount_entitlement.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.admins) + subaccount_id = var.subaccount_id + role_collection_name = "SAP HANA Cloud Administrator" + user_name = each.value + depends_on = [btp_subaccount_subscription.hana_cloud_tools] +} + +# ------------------------------------------------------------------------------------------------------ +# Entitle subaccount for usage of SAP HANA Cloud +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "hana_cloud" { + subaccount_id = var.subaccount_id + service_name = "hana-cloud" + plan_name = "hana" +} +# Get plan for SAP HANA Cloud +data "btp_subaccount_service_plan" "hana_cloud" { + subaccount_id = var.subaccount_id + offering_name = "hana-cloud" + name = "hana" + depends_on = [btp_subaccount_entitlement.hana_cloud] } -module "hana_cloud_setup" { - source = "./modules/hana-cloud" +resource "btp_subaccount_service_instance" "hana_cloud" { + subaccount_id = var.subaccount_id + serviceplan_id = data.btp_subaccount_service_plan.hana_cloud.id + name = "my-hana-cloud-instance" + depends_on = [btp_subaccount_entitlement.hana_cloud] + parameters = jsonencode( + { + "data" : { + "memory" : 32, + "edition" : "cloud", + "systempassword" : "${var.hana_system_password}", + "additionalWorkers" : 0, + "disasterRecoveryMode" : "no_disaster_recovery", + "enabledservices" : { + "docstore" : false, + "dpserver" : true, + "scriptserver" : false + }, + "requestedOperation" : {}, + "serviceStopped" : false, + "slaLevel" : "standard", + "storage" : 120, + "vcpu" : 2, + "whitelistIPs" : ["0.0.0.0/0"] + } + }) - subaccount_id = btp_subaccount.gen_ai.id - hana_system_password = var.hana_system_password - admins = var.admins + timeouts = { + create = "45m" + update = "45m" + delete = "45m" + } } +# Create service binding to SAP HANA Cloud service +resource "btp_subaccount_service_binding" "hana_cloud" { + subaccount_id = var.subaccount_id + service_instance_id = btp_subaccount_service_instance.hana_cloud.id + name = "hana-cloud-key" +} + + resource "local_file" "env_file" { content = join("\n", [module.ai_setup.ai_core_envs, module.hana_cloud_setup.hana_cloud_envs]) filename = ".env" diff --git a/released/discovery_center/mission_4371/modules/ai/ai.tf b/released/discovery_center/mission_4371/modules/ai/ai.tf deleted file mode 100644 index 3f583901..00000000 --- a/released/discovery_center/mission_4371/modules/ai/ai.tf +++ /dev/null @@ -1,90 +0,0 @@ -# ------------------------------------------------------------------------------------------------------ -# Prepare & setup the SAP AI Core service (ensure your global account has the respective entitlements) -# ------------------------------------------------------------------------------------------------------ -terraform { - required_providers { - btp = { - source = "sap/btp" - version = "~> 1.4.0" - } - } -} -# ------------------------------------------------------------------------------------------------------ -# Prepare the list of admins and roles for the AI Launchpad -# ------------------------------------------------------------------------------------------------------ -locals { - role_mapping_admins_ai_launchpad = distinct(flatten([ - for admin in var.admins : [ - for role in var.roles_ai_launchpad : { - user_name = admin - role_name = role - } - ] - ] - )) -} - -# Entitle subaccount for usage of SAP AI Core service -# ------------------------------------------------------------------------------------------------------ -# Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for -# available plans and their region availability -resource "btp_subaccount_entitlement" "ai_core" { - subaccount_id = var.subaccount_id - service_name = "aicore" - plan_name = var.ai_core_plan_name -} - -# Get plan for SAP AI Core service -data "btp_subaccount_service_plan" "ai_core" { - subaccount_id = var.subaccount_id - offering_name = "aicore" - name = var.ai_core_plan_name - depends_on = [btp_subaccount_entitlement.ai_core] -} - -# Create service instance for SAP AI Core service -resource "btp_subaccount_service_instance" "ai_core" { - subaccount_id = var.subaccount_id - serviceplan_id = data.btp_subaccount_service_plan.ai_core.id - name = "my-ai-core-instance" - depends_on = [btp_subaccount_entitlement.ai_core] -} - -# Create service binding to SAP AI Core service (exposed for a specific user group) -resource "btp_subaccount_service_binding" "ai_core_binding" { - subaccount_id = var.subaccount_id - service_instance_id = btp_subaccount_service_instance.ai_core.id - name = "ai-core-key" -} - -# ------------------------------------------------------------------------------------------------------ -# Prepare & setup SAP AI Launchpad -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount_entitlement" "ai_launchpad" { - count = var.setup_ai_launchpad ? 1 : 0 - - subaccount_id = var.subaccount_id - service_name = "ai-launchpad" - plan_name = "standard" -} - -resource "btp_subaccount_subscription" "ai_launchpad" { - count = var.setup_ai_launchpad ? 1 : 0 - - subaccount_id = var.subaccount_id - app_name = "ai-launchpad" - plan_name = "standard" - depends_on = [btp_subaccount_entitlement.ai_launchpad] -} - -# Assign users to Role Collection of SAP AI Launchpad -resource "btp_subaccount_role_collection_assignment" "ai_launchpad_role_mapping" { - - for_each = { for entry in local.role_mapping_admins_ai_launchpad : "${entry.user_name}.${entry.role_name}" => entry - if var.setup_ai_launchpad == true } - - subaccount_id = var.subaccount_id - role_collection_name = each.value.role_name - user_name = each.value.user_name - depends_on = [btp_subaccount_subscription.ai_launchpad] -} diff --git a/released/discovery_center/mission_4371/modules/ai/ai_outputs.tf b/released/discovery_center/mission_4371/modules/ai/ai_outputs.tf deleted file mode 100644 index d6030a9a..00000000 --- a/released/discovery_center/mission_4371/modules/ai/ai_outputs.tf +++ /dev/null @@ -1,21 +0,0 @@ -output "ai_core_service_instance_id" { - value = btp_subaccount_service_instance.ai_core.id - description = "The ID of the AI Core service instance." -} - -output "ai_core_service_instance_name" { - value = btp_subaccount_service_instance.ai_core.name - description = "The ID of the AI Core service instance." -} - -output "ai_core_envs" { - value = <<-EOT - AICORE_AUTH_URL=${jsondecode(btp_subaccount_service_binding.ai_core_binding.credentials)["url"]} - AICORE_CLIENT_ID=${jsondecode(btp_subaccount_service_binding.ai_core_binding.credentials)["clientid"]} - AICORE_CLIENT_SECRET=${jsondecode(btp_subaccount_service_binding.ai_core_binding.credentials)["clientsecret"]} - AICORE_BASE_URL=${jsondecode(btp_subaccount_service_binding.ai_core_binding.credentials)["serviceurls"]["AI_API_URL"]} - AICORE_RESOURCE_GROUP=default - TARGET_AI_CORE_MODEL=${jsonencode(var.target_ai_core_model)} - EOT - description = "The environment variables for the AI Core service." -} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/modules/ai/ai_variables.tf b/released/discovery_center/mission_4371/modules/ai/ai_variables.tf deleted file mode 100644 index a8f0c286..00000000 --- a/released/discovery_center/mission_4371/modules/ai/ai_variables.tf +++ /dev/null @@ -1,70 +0,0 @@ -variable "subaccount_id" { - type = string - description = "The subaccount domain (has to be unique within the BTP region)." -} - -variable "cli_server_url" { - type = string - description = "The BTP CLI server URL." - default = "https://cpcli.cf.sap.hana.ondemand.com" -} - -variable "ai_core_plan_name" { - type = string - description = "The name of the AI Core service plan." - default = "sap-internal" - validation { - condition = contains(["sap-internal", "extended"], var.ai_core_plan_name) - error_message = "Valid values for ai_core_plan_name are: sap-internal, extended." - } -} - - -variable "target_ai_core_model" { - type = list(any) - description = "Defines the target AI core model to be used by the AI Core service" - default = ["gpt-35-turbo"] - - validation { - condition = length([ - for o in var.target_ai_core_model : true - if contains(["gpt-35-turbo", "gpt-35-turbo-16k", "gpt-4", "gpt-4-32k", "text-embedding-ada-002", "tiiuae--falcon-40b-instruct"], o) - ]) == length(var.target_ai_core_model) - error_message = "Please enter a valid entry for the target_ai_core_model of the AI Core service. Valid values are: gpt-35-turbo, gpt-35-turbo-16k, gpt-4, gpt-4-32k, text-embedding-ada-002, tiiuae--falcon-40b-instruct." - } -} - - -variable "admins" { - type = list(string) - description = "Defines the colleagues who are added to each subaccount as emergency administrators." - - # add validation to check if admins contains a list of valid email addresses - validation { - condition = length([for email in var.admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.admins) - error_message = "Please enter a valid email address for the admins." - } - -} - -variable "setup_ai_launchpad" { - type = bool - description = "Switch to enable the setup of the AI Launchpad." - default = false -} - - -# Define roles for a user of the SAP AI Launchpad -variable "roles_ai_launchpad" { - type = list(string) - description = "Defines the list of roles to be assigned to the users in the AI Launchpad." - default = [ - "ailaunchpad_aicore_admin_editor", - "ailaunchpad_allow_all_resourcegroups", - "ailaunchpad_genai_administrator", - "ailaunchpad_mloperations_editor", - "ailaunchpad_connections_editor" - ] - -} - diff --git a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud.tf b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud.tf deleted file mode 100644 index ba771562..00000000 --- a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud.tf +++ /dev/null @@ -1,94 +0,0 @@ -# ------------------------------------------------------------------------------------------------------ -# Prepare & setup SAP HANA Cloud for usage of Vector Engine -# ------------------------------------------------------------------------------------------------------ -terraform { - required_providers { - btp = { - source = "sap/btp" - version = "~> 1.4.0" - } - } -} - -# ------------------------------------------------------------------------------------------------------ -# Entitle subaccount for usage of SAP HANA Cloud tools -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount_entitlement" "hana_cloud_tools" { - subaccount_id = var.subaccount_id - service_name = "hana-cloud-tools" - plan_name = "tools" -} - -resource "btp_subaccount_subscription" "hana_cloud_tools" { - subaccount_id = var.subaccount_id - app_name = "hana-cloud-tools" - plan_name = "tools" - depends_on = [btp_subaccount_entitlement.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.admins) - subaccount_id = var.subaccount_id - role_collection_name = "SAP HANA Cloud Administrator" - user_name = each.value - depends_on = [btp_subaccount_subscription.hana_cloud_tools] -} - -# ------------------------------------------------------------------------------------------------------ -# Entitle subaccount for usage of SAP HANA Cloud -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount_entitlement" "hana_cloud" { - subaccount_id = var.subaccount_id - service_name = "hana-cloud" - plan_name = "hana" -} - -# Get plan for SAP HANA Cloud -data "btp_subaccount_service_plan" "hana_cloud" { - subaccount_id = var.subaccount_id - offering_name = "hana-cloud" - name = "hana" - depends_on = [btp_subaccount_entitlement.hana_cloud] -} - -resource "btp_subaccount_service_instance" "hana_cloud" { - subaccount_id = var.subaccount_id - serviceplan_id = data.btp_subaccount_service_plan.hana_cloud.id - name = "my-hana-cloud-instance" - depends_on = [btp_subaccount_entitlement.hana_cloud] - parameters = jsonencode( - { - "data" : { - "memory" : 32, - "edition" : "cloud", - "systempassword" : "${var.hana_system_password}", - "additionalWorkers" : 0, - "disasterRecoveryMode" : "no_disaster_recovery", - "enabledservices" : { - "docstore" : false, - "dpserver" : true, - "scriptserver" : false - }, - "requestedOperation" : {}, - "serviceStopped" : false, - "slaLevel" : "standard", - "storage" : 120, - "vcpu" : 2, - "whitelistIPs" : ["0.0.0.0/0"] - } - }) - - timeouts = { - create = "45m" - update = "45m" - delete = "45m" - } -} - -# Create service binding to SAP HANA Cloud service -resource "btp_subaccount_service_binding" "hana_cloud" { - subaccount_id = var.subaccount_id - service_instance_id = btp_subaccount_service_instance.hana_cloud.id - name = "hana-cloud-key" -} diff --git a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_outputs.tf b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_outputs.tf deleted file mode 100644 index 7eff1651..00000000 --- a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_outputs.tf +++ /dev/null @@ -1,20 +0,0 @@ - -output "hana_cloud_service_instance_id" { - value = btp_subaccount_service_instance.hana_cloud.id - description = "The ID of the HANA Cloud service instance." -} - -output "hana_cloud_service_instance_name" { - value = btp_subaccount_service_instance.hana_cloud.name - description = "The ID of the HANA Cloud service instance." -} - -output "hana_cloud_envs" { - value = <<-EOT - HANA_DB_ADDRESS=${jsondecode(btp_subaccount_service_binding.hana_cloud.credentials)["host"]} - HANA_DB_PORT=${jsondecode(btp_subaccount_service_binding.hana_cloud.credentials)["port"]} - HANA_DB_USER=DBADMIN - HANA_DB_PASSWORD=${var.hana_system_password} - EOT - description = "Environment variables for the HANA Cloud service." -} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_variables.tf b/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_variables.tf deleted file mode 100644 index d9618592..00000000 --- a/released/discovery_center/mission_4371/modules/hana-cloud/hana_cloud_variables.tf +++ /dev/null @@ -1,49 +0,0 @@ - -variable "subaccount_id" { - type = string - description = "The subaccount id." -} - - -variable "hana_system_password" { - type = string - description = "The password of the database 'superuser' DBADMIN." - sensitive = true - - # add validation to check if the password is at least 8 characters long - validation { - condition = length(var.hana_system_password) > 7 - error_message = "The hana_system_password must be at least 8 characters long." - } - - # add validation to check if the password contains at least one upper case - validation { - condition = can(regex("[A-Z]", var.hana_system_password)) - error_message = "The hana_system_password must contain at least one upper case." - } - - # add validation to check if the password contains at least two lower case characters - validation { - condition = can(regex("[a-z]{2}", var.hana_system_password)) - error_message = "The hana_system_password must contain at least two lower case characters." - } - - # add validation to check if the password contains at least one numeric character - validation { - condition = can(regex("[0-9]", var.hana_system_password)) - error_message = "The hana_system_password must contain at least one numeric character." - } - -} - -variable "admins" { - type = list(string) - description = "Defines the colleagues who are added to each subaccount as emergency administrators." - - # add validation to check if admins contains a list of valid email addresses - validation { - condition = length([for email in var.admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.admins) - error_message = "Please enter a valid email address for the admins." - } - -} From 7e6e51d9fa6a6e2af689d139d518bcbff2d789b2 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Tue, 2 Jul 2024 10:20:53 +0000 Subject: [PATCH 03/14] udpate variables --- .../discovery_center/mission_4371/main.tf | 66 +++++++++--- .../mission_4371/variables.tf | 102 ++++++++++++++---- 2 files changed, 128 insertions(+), 40 deletions(-) diff --git a/released/discovery_center/mission_4371/main.tf b/released/discovery_center/mission_4371/main.tf index 78780aee..25a5c293 100644 --- a/released/discovery_center/mission_4371/main.tf +++ b/released/discovery_center/mission_4371/main.tf @@ -1,19 +1,51 @@ # ------------------------------------------------------------------------------------------------------ # Setup subaccount domain (to ensure uniqueness in BTP global account) # ------------------------------------------------------------------------------------------------------ -resource "random_id" "subaccount_domain_suffix" { - byte_length = 12 -} +resource "random_uuid" "uuid" {} +locals { + random_uuid = random_uuid.uuid.result + subaccount_domain = lower(replace("mission-4371-${local.random_uuid}", "_", "-")) +} # ------------------------------------------------------------------------------------------------------ # Creation of subaccount # ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount" "gen_ai" { +resource "btp_subaccount" "dc_mission" { name = var.subaccount_name - subdomain = join("-", ["genai-starter-kit", random_id.subaccount_domain_suffix.hex]) + subdomain = local.subaccount_domain region = lower(var.region) } +# ------------------------------------------------------------------------------------------------------ +# 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 = btp_subaccount.dc_mission.id + identity_provider = var.custom_idp +} + +# ------------------------------------------------------------------------------------------------------ +# Assignment of users as sub account administrators +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_role_collection_assignment" "subaccount-admins" { + for_each = toset(var.subaccount_admins) + subaccount_id = btp_subaccount.dc_mission.id + role_collection_name = "Subaccount Administrator" + 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 = btp_subaccount.dc_mission.id + role_collection_name = "Subaccount Service Administrator" + user_name = each.value +} + + # ------------------------------------------------------------------------------------------------------ # Prepare & setup the SAP AI Core service (ensure your global account has the respective entitlements) # ------------------------------------------------------------------------------------------------------ @@ -23,14 +55,14 @@ resource "btp_subaccount" "gen_ai" { # Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for # available plans and their region availability resource "btp_subaccount_entitlement" "ai_core" { - subaccount_id = var.subaccount_id + subaccount_id = var.dc_mission.id service_name = "aicore" plan_name = var.ai_core_plan_name } # Get plan for SAP AI Core service data "btp_subaccount_service_plan" "ai_core" { - subaccount_id = var.subaccount_id + subaccount_id = btp_subaccount.dc_mission.id offering_name = "aicore" name = var.ai_core_plan_name depends_on = [btp_subaccount_entitlement.ai_core] @@ -38,7 +70,7 @@ data "btp_subaccount_service_plan" "ai_core" { # Create service instance for SAP AI Core service resource "btp_subaccount_service_instance" "ai_core" { - subaccount_id = var.subaccount_id + subaccount_id = btp_subaccount.dc_mission.id serviceplan_id = data.btp_subaccount_service_plan.ai_core.id name = "my-ai-core-instance" depends_on = [btp_subaccount_entitlement.ai_core] @@ -46,7 +78,7 @@ resource "btp_subaccount_service_instance" "ai_core" { # Create service binding to SAP AI Core service (exposed for a specific user group) resource "btp_subaccount_service_binding" "ai_core_binding" { - subaccount_id = var.subaccount_id + subaccount_id = btp_subaccount.dc_mission.id service_instance_id = btp_subaccount_service_instance.ai_core.id name = "ai-core-key" } @@ -56,13 +88,13 @@ resource "btp_subaccount_service_binding" "ai_core_binding" { # Entitle subaccount for usage of SAP HANA Cloud tools # ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "hana_cloud_tools" { - subaccount_id = var.subaccount_id + subaccount_id = btp_subaccount.dc_mission.id service_name = "hana-cloud-tools" plan_name = "tools" } resource "btp_subaccount_subscription" "hana_cloud_tools" { - subaccount_id = var.subaccount_id + subaccount_id = btp_subaccount.dc_mission.id app_name = "hana-cloud-tools" plan_name = "tools" depends_on = [btp_subaccount_entitlement.hana_cloud_tools] @@ -70,8 +102,8 @@ 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.admins) - subaccount_id = var.subaccount_id + for_each = toset(var.hana_cloud_admins) + subaccount_id = btp_subaccount.dc_mission.id role_collection_name = "SAP HANA Cloud Administrator" user_name = each.value depends_on = [btp_subaccount_subscription.hana_cloud_tools] @@ -81,21 +113,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 = var.subaccount_id + subaccount_id = 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 = var.subaccount_id + subaccount_id = 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 = var.subaccount_id + subaccount_id = 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] @@ -130,7 +162,7 @@ resource "btp_subaccount_service_instance" "hana_cloud" { # Create service binding to SAP HANA Cloud service resource "btp_subaccount_service_binding" "hana_cloud" { - subaccount_id = var.subaccount_id + subaccount_id = btp_subaccount.dc_mission.id service_instance_id = btp_subaccount_service_instance.hana_cloud.id name = "hana-cloud-key" } diff --git a/released/discovery_center/mission_4371/variables.tf b/released/discovery_center/mission_4371/variables.tf index fee2f6cf..48fc5551 100644 --- a/released/discovery_center/mission_4371/variables.tf +++ b/released/discovery_center/mission_4371/variables.tf @@ -1,24 +1,91 @@ +###################################################################### +# Customer account setup +###################################################################### variable "globalaccount" { type = string - description = "The globalaccount subdomain where the sub account shall be created." + description = "Defines the global account" + default = "yourglobalaccount" } -variable "setup_ai_launchpad" { - type = bool - description = "Switch to enable the setup of the AI Launchpad." - default = true +variable "cli_server_url" { + type = string + description = "Defines the CLI server URL" + default = "https://cli.btp.cloud.sap" } +# subaccount variable "subaccount_name" { type = string description = "The subaccount name." - default = "My SAP Build Apps subaccount." + default = "SAP Discovery Center Mission 3774 - Central Inbox with SAP Task Center" +} +variable "subaccount_id" { + type = string + description = "The subaccount ID." + default = "" +} +# Region +variable "region" { + type = string + description = "The region where the project account shall be created in." + default = "us10" } -variable "cli_server_url" { +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 CF space managers." + } +} + +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 + 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 CF space managers." + } +} + +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." + } +} + +variable "custom_idp" { + type = string + description = "Defines the custom IdP" + default = "" +} + +variable "origin_key" { type = string - description = "The BTP CLI server URL." - default = "https://cpcli.cf.sap.hana.ondemand.com" + 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 "create_tfvars_file_for_step2" { + type = bool + description = "Switch to enable the creation of the tfvars file for step 2." + default = false } variable "ai_core_plan_name" { @@ -48,9 +115,9 @@ variable "hana_system_password" { error_message = "The hana_system_password must contain at least one upper case." } - # add validation to check if the password contains at least two lower case characters + # add validation to check if the password contains at least two lower case characters that can occur on arbitrary places in the string (not necessarily in a row) validation { - condition = can(regex("[a-z]{2}", var.hana_system_password)) + condition = length(regexall("[a-z]", var.hana_system_password)) > 1 error_message = "The hana_system_password must contain at least two lower case characters." } @@ -69,7 +136,7 @@ variable "target_ai_core_model" { validation { condition = length([ for o in var.target_ai_core_model : true - if contains(["gpt-35-turbo", "gpt-35-turbo-16k", "gpt-4", "gpt-4-32k", "text-embedding-ada-002", "tiiuae--falcon-40b-instruct"], o) + if contains(["gpt-35-turbo", "gpt-35-turbo-0125", "gpt-35-turbo-16k", "gpt-4", "gpt-4-32k", "text-embedding-ada-002", "gemini-1.0-pro", "text-bison", "chat-bison", "textembedding-gecko-multilingual", "textembedding-gecko", "tiiuae--falcon-40b-instruct"], o) ]) == length(var.target_ai_core_model) error_message = "Please enter a valid entry for the target_ai_core_model of the AI Core service. Valid values are: gpt-35-turbo, gpt-35-turbo-16k, gpt-4, gpt-4-32k, text-embedding-ada-002, tiiuae--falcon-40b-instruct." } @@ -87,14 +154,3 @@ variable "region" { error_message = "Please enter a valid region for the sub account. Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for regions providing the AI Core service." } } - -variable "admins" { - type = list(string) - description = "Defines the colleagues who are added to each subaccount as emergency administrators." - - # add validation to check if admins contains a list of valid email addresses - validation { - condition = length([for email in var.admins : can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email))]) == length(var.admins) - error_message = "Please enter a valid email address for the admins." - } -} From 9b71c0cdd945a3dada33ab06f13b8c613ec2fdc5 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Tue, 2 Jul 2024 10:22:32 +0000 Subject: [PATCH 04/14] update available regions --- released/discovery_center/mission_4371/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/released/discovery_center/mission_4371/variables.tf b/released/discovery_center/mission_4371/variables.tf index 48fc5551..c4dd1cbd 100644 --- a/released/discovery_center/mission_4371/variables.tf +++ b/released/discovery_center/mission_4371/variables.tf @@ -150,7 +150,7 @@ variable "region" { # Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for the latest list of regions # supported by the AI Core service. validation { - condition = contains(["eu10-canary", "ap10", "eu10", "eu11", "jp10", "us10"], var.region) + condition = contains(["ap10", "eu10", "eu11", "eu20", "eu30", "jp10", "us10", "us21", "us30"], var.region) error_message = "Please enter a valid region for the sub account. Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for regions providing the AI Core service." } } From 994738b9824d185b09368366b55d09e99f20caf0 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Tue, 2 Jul 2024 11:08:33 +0000 Subject: [PATCH 05/14] change variable names and update docs --- .../discovery_center/mission_4371/README.md | 29 ++++++++-------- .../discovery_center/mission_4371/main.tf | 7 +--- .../mission_4371/sample.tfvars | 34 ++++++------------- .../mission_4371/variables.tf | 32 ++++++++--------- 4 files changed, 40 insertions(+), 62 deletions(-) diff --git a/released/discovery_center/mission_4371/README.md b/released/discovery_center/mission_4371/README.md index a5b72470..b063c7f2 100644 --- a/released/discovery_center/mission_4371/README.md +++ b/released/discovery_center/mission_4371/README.md @@ -1,31 +1,34 @@ -# Setting up a sub account with the SAP AI Core service deployed +# Discovery Center Mission: Develop a CAP-based (multitenant) application using GenAI and RAG (4371) ## Overview -This script shows how to create a SAP BTP subaccount with the `SAP AI Core` service deployed +This sample shows how to create a landscape for the Discovery Center Mission - [Develop a CAP-based (multitenant) application using GenAI and RAG](https://discovery-center.cloud.sap/missiondetail/4371/) ## Content of setup The setup comprises the following resources: -- Creation of a SAP BTP subaccount -- Entitlement of the SAP AI Core service -- Entitlement and setup of SAP HANA Cloud (incl. hana cloud tools) +- Creation of the SAP BTP subaccount +- Entitlements of services +- Subscriptions to applications - Role collection assignments to users +- Management of users and roles on org and space level ## Deploying the resources To deploy the resources you must: -1. Change the variables in the `sample.tfvars` file to meet your requirements +1. Create a file `secret.auto.tfvars` and maintain the credentials for the BTP and CF provider + ```hcl + username = "" + password = "" + ``` -2. Export the variables for user name and password +2. Change the variables in the `samples.tfvars` file 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`. - ```bash - export BTP_USERNAME='' - export BTP_PASSWORD='' - ``` 3. Initialize your workspace: @@ -45,12 +48,10 @@ To deploy the resources you must: terraform apply -var-file="sample.tfvars" ``` -6. You'll notice, that a `.env` file has been created, containing some environment variables that you can use for your genAI experiments. - ## 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 +terraform destroy -var-file="sample.tfvars" ``` diff --git a/released/discovery_center/mission_4371/main.tf b/released/discovery_center/mission_4371/main.tf index 25a5c293..c7564ca3 100644 --- a/released/discovery_center/mission_4371/main.tf +++ b/released/discovery_center/mission_4371/main.tf @@ -55,7 +55,7 @@ resource "btp_subaccount_role_collection_assignment" "subaccount-service-admins" # Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for # available plans and their region availability resource "btp_subaccount_entitlement" "ai_core" { - subaccount_id = var.dc_mission.id + subaccount_id = btp_subaccount.dc_mission.id service_name = "aicore" plan_name = var.ai_core_plan_name } @@ -167,8 +167,3 @@ resource "btp_subaccount_service_binding" "hana_cloud" { name = "hana-cloud-key" } - -resource "local_file" "env_file" { - content = join("\n", [module.ai_setup.ai_core_envs, module.hana_cloud_setup.hana_cloud_envs]) - filename = ".env" -} diff --git a/released/discovery_center/mission_4371/sample.tfvars b/released/discovery_center/mission_4371/sample.tfvars index 26d67865..8beb14b5 100644 --- a/released/discovery_center/mission_4371/sample.tfvars +++ b/released/discovery_center/mission_4371/sample.tfvars @@ -1,34 +1,20 @@ -# ------------------------------------------------------------------------------------------------------ -# Your BTP user credentials (you can also provide them as environment variables) -# ------------------------------------------------------------------------------------------------------ -#BTP_USERNAME="your.email@test.com" -# ------------------------------------------------------------------------------------------------------ -# Comment out the next line if you want to provide the password here instead of typing it in the console (not recommended for security reasons) -#BTP_PASSWORD="xxxxx" - # ------------------------------------------------------------------------------------------------------ # Provider configuration # ------------------------------------------------------------------------------------------------------ # Your global account subdomain -globalaccount = "xxxxxxxx-xxxxxxx-xxxxxxx-xxxxxxxx-xxxxxx" +globalaccount = "yourglobalaccount" +region = "us10" +subaccount_name = "SAP Discovery Center Mission 4371" -# The CLI server URL (needs to be set to null if you are using the default CLI server) -cli_server_url = null - -# Region for your subaccount -region = "us10" - -# Name of your sub account -subaccount_name = "GenAI on BTP" - -# If set to true, the script will create an app subscription for the AI Launchpad -setup_ai_launchpad = false +# ------------------------------------------------------------------------------------------------------ +# Project specific configuration (please adapt!) +# ------------------------------------------------------------------------------------------------------ -# The model that the AI Core service should use -target_ai_core_model = ["gpt-35-turbo", "text-embedding-ada-002"] +subaccount_admins = ["another.user@test.com"] +subaccount_service_admins = ["another.user@test.com"] +hana_cloud_admins = ["thomas.ziegert@sap.com", "rui.nogueira@sap.com"] -# The admin users -admins = ["jane.doe@test.com", "your.email@test.com"] +custom_idp = "sap.ids" # Comment out the next line if you want to provide the password here instead of typing it in the console (not recommended for security reasons) #hana_system_password = "xxxxxx" diff --git a/released/discovery_center/mission_4371/variables.tf b/released/discovery_center/mission_4371/variables.tf index c4dd1cbd..102cde54 100644 --- a/released/discovery_center/mission_4371/variables.tf +++ b/released/discovery_center/mission_4371/variables.tf @@ -24,12 +24,6 @@ variable "subaccount_id" { description = "The subaccount ID." default = "" } -# Region -variable "region" { - type = string - description = "The region where the project account shall be created in." - default = "us10" -} variable "subaccount_admins" { type = list(string) @@ -55,6 +49,20 @@ variable "subaccount_service_admins" { } } +variable "region" { + type = string + description = "The region where the sub account shall be created in." + default = "us10" + + # Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for the latest list of regions + # supported by the AI Core service with the "extended" service plan. + validation { + condition = contains(["ap10", "eu10", "eu11", "eu20", "eu30", "jp10", "us10", "us21", "us30"], var.region) + error_message = "Please enter a valid region for the sub account. Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for regions providing the AI Core service." + } +} + + variable "hana_cloud_admins" { type = list(string) description = "Defines the colleagues who are added as admins to access the instance of SAP HANA Cloud." @@ -142,15 +150,3 @@ variable "target_ai_core_model" { } } -variable "region" { - type = string - description = "The region where the sub account shall be created in." - default = "us10" - - # Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for the latest list of regions - # supported by the AI Core service. - validation { - condition = contains(["ap10", "eu10", "eu11", "eu20", "eu30", "jp10", "us10", "us21", "us30"], var.region) - error_message = "Please enter a valid region for the sub account. Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for regions providing the AI Core service." - } -} From 90d5732f1abd4d747116993c6fb24896a76dc7a9 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Thu, 4 Jul 2024 15:58:17 +0200 Subject: [PATCH 06/14] initial upload --- .../discovery_center/mission_4371/README.md | 57 ------ .../discovery_center/mission_4371/main.tf | 169 ----------------- .../discovery_center/mission_4371/provider.tf | 13 -- .../mission_4371/sample.tfvars | 21 --- .../mission_4371/step1/locals.tf | 3 + .../mission_4371/step1/main.tf | 90 +++++++++ .../mission_4371/step1/outputs.tf | 110 +++++++++++ .../mission_4371/step1/provider.tf | 20 ++ .../mission_4371/step1/variables.tf | 176 ++++++++++++++++++ .../mission_4371/step2/locals.tf | 3 + .../mission_4371/step2/main.tf | 94 ++++++++++ .../mission_4371/step2/provider.tf | 16 ++ .../mission_4371/step2/variables.tf | 144 ++++++++++++++ .../mission_4371/variables.tf | 152 --------------- 14 files changed, 656 insertions(+), 412 deletions(-) delete mode 100644 released/discovery_center/mission_4371/README.md delete mode 100644 released/discovery_center/mission_4371/main.tf delete mode 100644 released/discovery_center/mission_4371/provider.tf delete mode 100644 released/discovery_center/mission_4371/sample.tfvars create mode 100644 released/discovery_center/mission_4371/step1/locals.tf create mode 100644 released/discovery_center/mission_4371/step1/main.tf create mode 100644 released/discovery_center/mission_4371/step1/outputs.tf create mode 100644 released/discovery_center/mission_4371/step1/provider.tf create mode 100644 released/discovery_center/mission_4371/step1/variables.tf create mode 100644 released/discovery_center/mission_4371/step2/locals.tf create mode 100644 released/discovery_center/mission_4371/step2/main.tf create mode 100644 released/discovery_center/mission_4371/step2/provider.tf create mode 100644 released/discovery_center/mission_4371/step2/variables.tf delete mode 100644 released/discovery_center/mission_4371/variables.tf diff --git a/released/discovery_center/mission_4371/README.md b/released/discovery_center/mission_4371/README.md deleted file mode 100644 index b063c7f2..00000000 --- a/released/discovery_center/mission_4371/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Discovery Center Mission: Develop a CAP-based (multitenant) application using GenAI and RAG (4371) - -## Overview - -This sample shows how to create a landscape for the Discovery Center Mission - [Develop a CAP-based (multitenant) application using GenAI and RAG](https://discovery-center.cloud.sap/missiondetail/4371/) - -## 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 -- Management of users and roles on org and space level - -## Deploying the resources - -To deploy the resources you must: - -1. Create a file `secret.auto.tfvars` and maintain the credentials for the BTP and CF provider - - ```hcl - username = "" - password = "" - ``` - -2. Change the variables in the `samples.tfvars` file 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. 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" -``` diff --git a/released/discovery_center/mission_4371/main.tf b/released/discovery_center/mission_4371/main.tf deleted file mode 100644 index c7564ca3..00000000 --- a/released/discovery_center/mission_4371/main.tf +++ /dev/null @@ -1,169 +0,0 @@ -# ------------------------------------------------------------------------------------------------------ -# Setup subaccount domain (to ensure uniqueness in BTP global account) -# ------------------------------------------------------------------------------------------------------ -resource "random_uuid" "uuid" {} - -locals { - random_uuid = random_uuid.uuid.result - subaccount_domain = lower(replace("mission-4371-${local.random_uuid}", "_", "-")) -} -# ------------------------------------------------------------------------------------------------------ -# Creation of subaccount -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount" "dc_mission" { - name = var.subaccount_name - subdomain = local.subaccount_domain - region = lower(var.region) -} - -# ------------------------------------------------------------------------------------------------------ -# 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 = btp_subaccount.dc_mission.id - identity_provider = var.custom_idp -} - -# ------------------------------------------------------------------------------------------------------ -# Assignment of users as sub account administrators -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount_role_collection_assignment" "subaccount-admins" { - for_each = toset(var.subaccount_admins) - subaccount_id = btp_subaccount.dc_mission.id - role_collection_name = "Subaccount Administrator" - 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 = btp_subaccount.dc_mission.id - role_collection_name = "Subaccount Service Administrator" - user_name = each.value -} - - -# ------------------------------------------------------------------------------------------------------ -# Prepare & setup the SAP AI Core service (ensure your global account has the respective entitlements) -# ------------------------------------------------------------------------------------------------------ - -# Entitle subaccount for usage of SAP AI Core service -# ------------------------------------------------------------------------------------------------------ -# Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for -# available plans and their region availability -resource "btp_subaccount_entitlement" "ai_core" { - subaccount_id = btp_subaccount.dc_mission.id - service_name = "aicore" - plan_name = var.ai_core_plan_name -} - -# Get plan for SAP AI Core service -data "btp_subaccount_service_plan" "ai_core" { - subaccount_id = btp_subaccount.dc_mission.id - offering_name = "aicore" - name = var.ai_core_plan_name - depends_on = [btp_subaccount_entitlement.ai_core] -} - -# Create service instance for SAP AI Core service -resource "btp_subaccount_service_instance" "ai_core" { - subaccount_id = btp_subaccount.dc_mission.id - serviceplan_id = data.btp_subaccount_service_plan.ai_core.id - name = "my-ai-core-instance" - depends_on = [btp_subaccount_entitlement.ai_core] -} - -# Create service binding to SAP AI Core service (exposed for a specific user group) -resource "btp_subaccount_service_binding" "ai_core_binding" { - subaccount_id = btp_subaccount.dc_mission.id - service_instance_id = btp_subaccount_service_instance.ai_core.id - name = "ai-core-key" -} - - -# ------------------------------------------------------------------------------------------------------ -# Entitle subaccount for usage of SAP HANA Cloud tools -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount_entitlement" "hana_cloud_tools" { - subaccount_id = btp_subaccount.dc_mission.id - service_name = "hana-cloud-tools" - plan_name = "tools" -} - -resource "btp_subaccount_subscription" "hana_cloud_tools" { - subaccount_id = btp_subaccount.dc_mission.id - app_name = "hana-cloud-tools" - plan_name = "tools" - depends_on = [btp_subaccount_entitlement.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 = btp_subaccount.dc_mission.id - role_collection_name = "SAP HANA Cloud Administrator" - user_name = each.value - depends_on = [btp_subaccount_subscription.hana_cloud_tools] -} - -# ------------------------------------------------------------------------------------------------------ -# Entitle subaccount for usage of SAP HANA Cloud -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount_entitlement" "hana_cloud" { - subaccount_id = 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 = 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 = 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] - parameters = jsonencode( - { - "data" : { - "memory" : 32, - "edition" : "cloud", - "systempassword" : "${var.hana_system_password}", - "additionalWorkers" : 0, - "disasterRecoveryMode" : "no_disaster_recovery", - "enabledservices" : { - "docstore" : false, - "dpserver" : true, - "scriptserver" : false - }, - "requestedOperation" : {}, - "serviceStopped" : false, - "slaLevel" : "standard", - "storage" : 120, - "vcpu" : 2, - "whitelistIPs" : ["0.0.0.0/0"] - } - }) - - timeouts = { - create = "45m" - update = "45m" - delete = "45m" - } -} - -# Create service binding to SAP HANA Cloud service -resource "btp_subaccount_service_binding" "hana_cloud" { - subaccount_id = btp_subaccount.dc_mission.id - service_instance_id = btp_subaccount_service_instance.hana_cloud.id - name = "hana-cloud-key" -} - diff --git a/released/discovery_center/mission_4371/provider.tf b/released/discovery_center/mission_4371/provider.tf deleted file mode 100644 index 7ceab97d..00000000 --- a/released/discovery_center/mission_4371/provider.tf +++ /dev/null @@ -1,13 +0,0 @@ -terraform { - required_providers { - btp = { - source = "SAP/btp" - version = "~> 1.4.0" - } - } -} - -provider "btp" { - globalaccount = var.globalaccount - cli_server_url = var.cli_server_url -} diff --git a/released/discovery_center/mission_4371/sample.tfvars b/released/discovery_center/mission_4371/sample.tfvars deleted file mode 100644 index 8beb14b5..00000000 --- a/released/discovery_center/mission_4371/sample.tfvars +++ /dev/null @@ -1,21 +0,0 @@ -# ------------------------------------------------------------------------------------------------------ -# Provider configuration -# ------------------------------------------------------------------------------------------------------ -# Your global account subdomain -globalaccount = "yourglobalaccount" -region = "us10" -subaccount_name = "SAP Discovery Center Mission 4371" - -# ------------------------------------------------------------------------------------------------------ -# Project specific configuration (please adapt!) -# ------------------------------------------------------------------------------------------------------ - -subaccount_admins = ["another.user@test.com"] -subaccount_service_admins = ["another.user@test.com"] -hana_cloud_admins = ["thomas.ziegert@sap.com", "rui.nogueira@sap.com"] - -custom_idp = "sap.ids" - -# Comment out the next line if you want to provide the password here instead of typing it in the console (not recommended for security reasons) -#hana_system_password = "xxxxxx" - diff --git a/released/discovery_center/mission_4371/step1/locals.tf b/released/discovery_center/mission_4371/step1/locals.tf new file mode 100644 index 00000000..09136428 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/locals.tf @@ -0,0 +1,3 @@ +locals { + service_name__sac = "analytics-planning-osb" +} diff --git a/released/discovery_center/mission_4371/step1/main.tf b/released/discovery_center/mission_4371/step1/main.tf new file mode 100644 index 00000000..89ad3499 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/main.tf @@ -0,0 +1,90 @@ +### +# Setup of names based on variables +### +resource "random_uuid" "uuid" {} + +locals { + random_uuid = random_uuid.uuid.result + subaccount_domain = lower("${var.subaccount_name}-${local.random_uuid}") + subaccount_name = var.subaccount_name + subaccount_cf_org = substr(replace("${local.subaccount_domain}", "-", ""), 0, 32) +} + +### +# Creation of subaccount +### +resource "btp_subaccount" "sac_subaccount" { + name = local.subaccount_name + subdomain = local.subaccount_domain + region = lower(var.region) +} + + +### +# Assignment of basic entitlements for a SAC setup +### +resource "btp_subaccount_entitlement" "sac__service_instance_plan" { + subaccount_id = btp_subaccount.sac_subaccount.id + service_name = local.service_name__sac + plan_name = var.service_plan__sac +} + + +### +# Creation of Cloud Foundry environment +### + +# Fetch all available environments for the subaccount +data "btp_subaccount_environments" "all" { + subaccount_id = btp_subaccount.sac_subaccount.id +} + +# Take the landscape label from the first CF environment if no environment label is provided +resource "terraform_data" "replacement" { + 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 +} + +# Create the Cloud Foundry environment instance +resource "btp_subaccount_environment_instance" "cf_sac" { + subaccount_id = btp_subaccount.sac_subaccount.id + name = local.subaccount_cf_org + environment_type = "cloudfoundry" + service_name = "cloudfoundry" + plan_name = var.cf_plan_name + landscape_label = terraform_data.replacement.output + + parameters = jsonencode({ + instance_name = local.subaccount_cf_org + }) +} + + +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_sac.labels)["API Endpoint"]}" + cf_org_id = "${btp_subaccount_environment_instance.cf_sac.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)} + + service_plan__sac = "${var.service_plan__sac}" + + sac_param_first_name = ${var.sac_param_first_name} + sac_param_last_name = ${var.sac_param_last_name} + sac_param_email = ${var.sac_param_email} + sac_param_host_name = ${var.sac_param_host_name} + + sac_param_number_of_business_intelligence_licenses = ${var.sac_param_number_of_business_intelligence_licenses} + sac_param_number_of_professional_licenses = ${var.sac_param_number_of_professional_licenses} + sac_param_number_of_business_standard_licenses = ${var.sac_param_number_of_business_standard_licenses} + + EOT + filename = "../step2/terraform.tfvars" +} diff --git a/released/discovery_center/mission_4371/step1/outputs.tf b/released/discovery_center/mission_4371/step1/outputs.tf new file mode 100644 index 00000000..d67d9a68 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/outputs.tf @@ -0,0 +1,110 @@ +output "subaccount_id" { + value = btp_subaccount.sac_subaccount.id + description = "The ID of the subaccount." +} + +output "subaccount_name" { + value = btp_subaccount.sac_subaccount.id + description = "The name of the subaccount." +} + +output "cf_org_name" { + value = local.subaccount_cf_org + description = "The name of the Cloud Foundry org connected to the subaccount." +} + +output "cf_org_id" { + value = btp_subaccount_environment_instance.cf_sac.platform_id + description = "The ID of the Cloud Foundry org connected to the subaccount." +} + +output "cf_api_url" { + value = lookup(jsondecode(btp_subaccount_environment_instance.cf_sac.labels), "API Endpoint", "not found") + description = "API endpoint of the Cloud Foundry environment." +} + +output "cf_landscape_label" { + value = btp_subaccount_environment_instance.cf_sac.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 "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__sac" { + value = var.service_plan__sac + description = "Plan for the service instance of SAC." +} + +output "sac_param_first_name" { + value = var.sac_param_first_name + description = "First name of the SAC responsible" +} + +output "sac_param_last_name" { + value = var.sac_param_last_name + description = "Last name of the SAC responsible" +} + +output "sac_param_email" { + value = var.sac_param_email + description = "Email of the SAC responsible" +} + +output "sac_param_host_name" { + value = var.sac_param_host_name + description = "Host name of the SAC" +} + +output "sac_param_number_of_business_intelligence_licenses" { + value = var.sac_param_number_of_business_intelligence_licenses + description = "Number of business intelligence licenses" +} + + +output "sac_param_number_of_professional_licenses" { + value = var.sac_param_number_of_professional_licenses + description = "Number of business professional licenses" +} + +output "sac_param_number_of_business_standard_licenses" { + value = var.sac_param_number_of_business_standard_licenses + description = "Number of business standard licenses" +} diff --git a/released/discovery_center/mission_4371/step1/provider.tf b/released/discovery_center/mission_4371/step1/provider.tf new file mode 100644 index 00000000..1f3304c4 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/provider.tf @@ -0,0 +1,20 @@ + +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.4.0" + } + } + +} + +# Please checkout documentation on how best to authenticate against SAP BTP +# via the Terraform provider for SAP BTP +provider "btp" { + # 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_4371/step1/variables.tf b/released/discovery_center/mission_4371/step1/variables.tf new file mode 100644 index 00000000..b32b9291 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/variables.tf @@ -0,0 +1,176 @@ +variable "globalaccount" { + type = string + description = "The global account subdomain." +} + +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" { + type = string + description = "The region where the project account shall be created in." + default = "eu11" +} + +variable "cf_plan_name" { + type = string + description = "Desired service plan for the Cloud Foundry environment instance." + default = "standard" +} + +variable "cf_landscape_label" { + type = string + description = "The Cloud Foundry landscape (format example eu10-004)." + 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 "service_plan__sac" { + type = string + description = "Plan for the service instance of ABAP." + default = "free" +} + + +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 "sac_param_first_name" { + type = string + description = "First name of the SAC responsible" +} + +variable "sac_param_last_name" { + type = string + description = "Last name of the SAC responsible" +} + +variable "sac_param_email" { + type = string + description = "Email of the SAC responsible" + + validation { + condition = can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", var.sac_param_email)) + error_message = "Please enter a valid email address for the SAC responsible." + } +} + +variable "sac_param_host_name" { + type = string + description = "Host name of the SAC" +} + +variable "sac_param_number_of_business_intelligence_licenses" { + type = number + description = "Number of business intelligence licenses" + default = 6 +} + + +variable "sac_param_number_of_professional_licenses" { + type = number + description = "Number of business professional licenses" + default = 1 +} + +variable "sac_param_number_of_business_standard_licenses" { + type = number + description = "Number of business standard licenses" + default = 2 +} diff --git a/released/discovery_center/mission_4371/step2/locals.tf b/released/discovery_center/mission_4371/step2/locals.tf new file mode 100644 index 00000000..09136428 --- /dev/null +++ b/released/discovery_center/mission_4371/step2/locals.tf @@ -0,0 +1,3 @@ +locals { + service_name__sac = "analytics-planning-osb" +} diff --git a/released/discovery_center/mission_4371/step2/main.tf b/released/discovery_center/mission_4371/step2/main.tf new file mode 100644 index 00000000..5a37900e --- /dev/null +++ b/released/discovery_center/mission_4371/step2/main.tf @@ -0,0 +1,94 @@ +### +# Assignment of Cloud Foundry org roles +### +resource "cloudfoundry_org_role" "org_managers" { + for_each = toset("${var.cf_org_managers}") + username = each.value + type = "organization_manager" + org = var.cf_org_id + origin = var.origin +} + + +resource "cloudfoundry_org_role" "billing_managers" { + for_each = toset("${var.cf_org_billing_managers}") + username = each.value + type = "organization_billing_manager" + org = var.cf_org_id + origin = var.origin +} + +resource "cloudfoundry_org_role" "org_auditors" { + for_each = toset("${var.cf_org_auditors}") + username = each.value + type = "organization_auditor" + org = var.cf_org_id + origin = var.origin +} + + +### +# Creation of Cloud Foundry space +### +resource "cloudfoundry_space" "sac_space" { + name = var.cf_space_name + org = var.cf_org_id +} + +### +# Assignment of Cloud Foundry org roles +### +resource "cloudfoundry_space_role" "space_managers" { + for_each = toset("${var.cf_space_managers}") + username = each.value + type = "space_manager" + space = cloudfoundry_space.sac_space.id + origin = var.origin +} + +resource "cloudfoundry_space_role" "space_developers" { + for_each = toset("${var.cf_space_developers}") + username = each.value + type = "space_developer" + space = cloudfoundry_space.sac_space.id + origin = var.origin +} + +resource "cloudfoundry_space_role" "space_auditors" { + for_each = toset("${var.cf_space_auditors}") + username = each.value + type = "space_auditor" + space = cloudfoundry_space.sac_space.id + origin = var.origin +} + +### +# Creation of service instance for ABAP +### +data "cloudfoundry_service" "sac_service_plans" { + name = local.service_name__sac +} + +resource "cloudfoundry_service_instance" "sac_si" { + depends_on = [cloudfoundry_space_role.space_managers, cloudfoundry_space_role.space_developers] + name = "service-analytics-planning-osb" + space = cloudfoundry_space.sac_space.id + service_plan = data.cloudfoundry_service.sac_service_plans.service_plans[var.service_plan__sac] + type = "managed" + parameters = jsonencode({ + "first_name" : "${var.sac_param_first_name}", + "last_name" : "${var.sac_param_last_name}", + "email" : "${var.sac_param_email}", + "confirm_email" : "${var.sac_param_email}", + "host_name" : "${var.sac_param_host_name}", + "number_of_business_intelligence_licenses" : var.sac_param_number_of_business_intelligence_licenses, + "number_of_planning_professional_licenses" : var.sac_param_number_of_professional_licenses, + "number_of_planning_standard_licenses" : var.sac_param_number_of_business_standard_licenses + + }) + timeouts = { + create = "2h" + delete = "2h" + update = "2h" + } +} diff --git a/released/discovery_center/mission_4371/step2/provider.tf b/released/discovery_center/mission_4371/step2/provider.tf new file mode 100644 index 00000000..7a11e78f --- /dev/null +++ b/released/discovery_center/mission_4371/step2/provider.tf @@ -0,0 +1,16 @@ +terraform { + required_providers { + cloudfoundry = { + source = "sap/cloudfoundry" + version = "0.2.1-beta" + } + } +} + +# 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_4371/step2/variables.tf b/released/discovery_center/mission_4371/step2/variables.tf new file mode 100644 index 00000000..a437e919 --- /dev/null +++ b/released/discovery_center/mission_4371/step2/variables.tf @@ -0,0 +1,144 @@ +variable "cf_api_url" { + type = string + description = "The API endpoint of the Cloud Foundry environment." +} + +variable "cf_org_id" { + type = string + description = "The Cloud Foundry landscape (format example eu10-004)." +} + +variable "origin" { + type = string + description = "The identity provider for the UAA user." + default = "sap.ids" +} + +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 = [] + + # 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 "service_plan__sac" { + type = string + description = "Plan for the service instance of ABAP." + default = "free" +} + +variable "sac_param_first_name" { + type = string + description = "First name of the SAC responsible" +} + +variable "sac_param_last_name" { + type = string + description = "Last name of the SAC responsible" +} + +variable "sac_param_email" { + type = string + description = "Email of the SAC responsible" + + validation { + condition = can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", var.sac_param_email)) + error_message = "Please enter a valid email address for the SAC responsible." + } +} + +variable "sac_param_host_name" { + type = string + description = "Host name of the SAC" +} + +variable "sac_param_number_of_business_intelligence_licenses" { + type = number + description = "Number of business intelligence licenses" + default = 6 +} + + +variable "sac_param_number_of_professional_licenses" { + type = number + description = "Number of business professional licenses" + default = 1 +} + +variable "sac_param_number_of_business_standard_licenses" { + type = number + description = "Number of business standard licenses" + default = 2 +} diff --git a/released/discovery_center/mission_4371/variables.tf b/released/discovery_center/mission_4371/variables.tf deleted file mode 100644 index 102cde54..00000000 --- a/released/discovery_center/mission_4371/variables.tf +++ /dev/null @@ -1,152 +0,0 @@ -###################################################################### -# Customer account setup -###################################################################### -variable "globalaccount" { - type = string - description = "Defines the global account" - default = "yourglobalaccount" -} - -variable "cli_server_url" { - type = string - description = "Defines the CLI server URL" - default = "https://cli.btp.cloud.sap" -} - -# subaccount -variable "subaccount_name" { - type = string - description = "The subaccount name." - default = "SAP Discovery Center Mission 3774 - Central Inbox with SAP Task Center" -} -variable "subaccount_id" { - type = string - description = "The subaccount ID." - default = "" -} - -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 CF space managers." - } -} - -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 - 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 CF space managers." - } -} - -variable "region" { - type = string - description = "The region where the sub account shall be created in." - default = "us10" - - # Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for the latest list of regions - # supported by the AI Core service with the "extended" service plan. - validation { - condition = contains(["ap10", "eu10", "eu11", "eu20", "eu30", "jp10", "us10", "us21", "us30"], var.region) - error_message = "Please enter a valid region for the sub account. Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for regions providing the AI Core service." - } -} - - -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." - } -} - -variable "custom_idp" { - type = string - description = "Defines the custom IdP" - default = "" -} - -variable "origin_key" { - 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 "create_tfvars_file_for_step2" { - type = bool - description = "Switch to enable the creation of the tfvars file for step 2." - default = false -} - -variable "ai_core_plan_name" { - type = string - description = "The name of the AI Core service plan." - default = "extended" - validation { - condition = contains(["extended"], var.ai_core_plan_name) - error_message = "Valid values for ai_core_plan_name are: extended." - } -} - -variable "hana_system_password" { - type = string - description = "The password of the database 'superuser' DBADMIN." - sensitive = true - - # add validation to check if the password is at least 8 characters long - validation { - condition = length(var.hana_system_password) > 7 - error_message = "The hana_system_password must be at least 8 characters long." - } - - # add validation to check if the password contains at least one upper case - validation { - condition = can(regex("[A-Z]", var.hana_system_password)) - error_message = "The hana_system_password must contain at least one upper case." - } - - # add validation to check if the password contains at least two lower case characters that can occur on arbitrary places in the string (not necessarily in a row) - validation { - condition = length(regexall("[a-z]", var.hana_system_password)) > 1 - error_message = "The hana_system_password must contain at least two lower case characters." - } - - # add validation to check if the password contains at least one numeric character - validation { - condition = can(regex("[0-9]", var.hana_system_password)) - error_message = "The hana_system_password must contain at least one numeric character." - } -} - -variable "target_ai_core_model" { - type = list(any) - description = "Defines the target AI core model to be used by the AI Core service" - default = ["gpt-35-turbo"] - - validation { - condition = length([ - for o in var.target_ai_core_model : true - if contains(["gpt-35-turbo", "gpt-35-turbo-0125", "gpt-35-turbo-16k", "gpt-4", "gpt-4-32k", "text-embedding-ada-002", "gemini-1.0-pro", "text-bison", "chat-bison", "textembedding-gecko-multilingual", "textembedding-gecko", "tiiuae--falcon-40b-instruct"], o) - ]) == length(var.target_ai_core_model) - error_message = "Please enter a valid entry for the target_ai_core_model of the AI Core service. Valid values are: gpt-35-turbo, gpt-35-turbo-16k, gpt-4, gpt-4-32k, text-embedding-ada-002, tiiuae--falcon-40b-instruct." - } -} - From 34f6a71e8fd9d4886becd0ab9bdb0af8453137e5 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Thu, 4 Jul 2024 16:01:01 +0200 Subject: [PATCH 07/14] update format --- .../mission_4371/step1/main.tf | 18 ++++++++-------- .../mission_4371/step2/main.tf | 21 ++++++++----------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/released/discovery_center/mission_4371/step1/main.tf b/released/discovery_center/mission_4371/step1/main.tf index 89ad3499..4afbe398 100644 --- a/released/discovery_center/mission_4371/step1/main.tf +++ b/released/discovery_center/mission_4371/step1/main.tf @@ -1,6 +1,6 @@ -### +# ------------------------------------------------------------------------------------------------------ # Setup of names based on variables -### +# ------------------------------------------------------------------------------------------------------ resource "random_uuid" "uuid" {} locals { @@ -10,9 +10,9 @@ locals { subaccount_cf_org = substr(replace("${local.subaccount_domain}", "-", ""), 0, 32) } -### +# ------------------------------------------------------------------------------------------------------ # Creation of subaccount -### +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount" "sac_subaccount" { name = local.subaccount_name subdomain = local.subaccount_domain @@ -20,9 +20,9 @@ resource "btp_subaccount" "sac_subaccount" { } -### -# Assignment of basic entitlements for a SAC setup -### +# ------------------------------------------------------------------------------------------------------ +# Assignment of basic entitlements for an SAC setup +# ------------------------------------------------------------------------------------------------------ resource "btp_subaccount_entitlement" "sac__service_instance_plan" { subaccount_id = btp_subaccount.sac_subaccount.id service_name = local.service_name__sac @@ -30,9 +30,9 @@ resource "btp_subaccount_entitlement" "sac__service_instance_plan" { } -### +# ------------------------------------------------------------------------------------------------------ # Creation of Cloud Foundry environment -### +# ------------------------------------------------------------------------------------------------------ # Fetch all available environments for the subaccount data "btp_subaccount_environments" "all" { diff --git a/released/discovery_center/mission_4371/step2/main.tf b/released/discovery_center/mission_4371/step2/main.tf index 5a37900e..0499d9c9 100644 --- a/released/discovery_center/mission_4371/step2/main.tf +++ b/released/discovery_center/mission_4371/step2/main.tf @@ -1,6 +1,6 @@ -### +# ------------------------------------------------------------------------------------------------------ # Assignment of Cloud Foundry org roles -### +# ------------------------------------------------------------------------------------------------------ resource "cloudfoundry_org_role" "org_managers" { for_each = toset("${var.cf_org_managers}") username = each.value @@ -9,7 +9,6 @@ resource "cloudfoundry_org_role" "org_managers" { origin = var.origin } - resource "cloudfoundry_org_role" "billing_managers" { for_each = toset("${var.cf_org_billing_managers}") username = each.value @@ -26,18 +25,17 @@ resource "cloudfoundry_org_role" "org_auditors" { origin = var.origin } - -### +# ------------------------------------------------------------------------------------------------------ # Creation of Cloud Foundry space -### +# ------------------------------------------------------------------------------------------------------ resource "cloudfoundry_space" "sac_space" { name = var.cf_space_name org = var.cf_org_id } -### +# ------------------------------------------------------------------------------------------------------ # Assignment of Cloud Foundry org roles -### +# ------------------------------------------------------------------------------------------------------ resource "cloudfoundry_space_role" "space_managers" { for_each = toset("${var.cf_space_managers}") username = each.value @@ -62,9 +60,9 @@ resource "cloudfoundry_space_role" "space_auditors" { origin = var.origin } -### -# Creation of service instance for ABAP -### +# ------------------------------------------------------------------------------------------------------ +# Creation of service instance for SAP Analytics Bloud +# ------------------------------------------------------------------------------------------------------ data "cloudfoundry_service" "sac_service_plans" { name = local.service_name__sac } @@ -84,7 +82,6 @@ resource "cloudfoundry_service_instance" "sac_si" { "number_of_business_intelligence_licenses" : var.sac_param_number_of_business_intelligence_licenses, "number_of_planning_professional_licenses" : var.sac_param_number_of_professional_licenses, "number_of_planning_standard_licenses" : var.sac_param_number_of_business_standard_licenses - }) timeouts = { create = "2h" From ea7c54066f56dec18caf52fd264e026c4a3d4551 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Thu, 4 Jul 2024 16:07:39 +0200 Subject: [PATCH 08/14] fix wrong mission content --- .DS_Store | Bin 0 -> 6148 bytes released/.DS_Store | Bin 0 -> 6148 bytes released/discovery_center/.DS_Store | Bin 0 -> 6148 bytes .../discovery_center/mission_4371/README.md | 57 ++++++ .../discovery_center/mission_4371/main.tf | 168 +++++++++++++++++ .../discovery_center/mission_4371/provider.tf | 13 ++ .../mission_4371/sample.tfvars | 20 ++ .../mission_4371/step1/locals.tf | 3 - .../mission_4371/step1/main.tf | 90 --------- .../mission_4371/step1/outputs.tf | 110 ----------- .../mission_4371/step1/provider.tf | 20 -- .../mission_4371/step1/variables.tf | 176 ------------------ .../mission_4371/step2/locals.tf | 3 - .../mission_4371/step2/main.tf | 91 --------- .../mission_4371/step2/provider.tf | 16 -- .../mission_4371/step2/variables.tf | 144 -------------- .../mission_4371/variables.tf | 151 +++++++++++++++ 17 files changed, 409 insertions(+), 653 deletions(-) create mode 100644 .DS_Store create mode 100644 released/.DS_Store create mode 100644 released/discovery_center/.DS_Store create mode 100644 released/discovery_center/mission_4371/README.md create mode 100644 released/discovery_center/mission_4371/main.tf create mode 100644 released/discovery_center/mission_4371/provider.tf create mode 100644 released/discovery_center/mission_4371/sample.tfvars delete mode 100644 released/discovery_center/mission_4371/step1/locals.tf delete mode 100644 released/discovery_center/mission_4371/step1/main.tf delete mode 100644 released/discovery_center/mission_4371/step1/outputs.tf delete mode 100644 released/discovery_center/mission_4371/step1/provider.tf delete mode 100644 released/discovery_center/mission_4371/step1/variables.tf delete mode 100644 released/discovery_center/mission_4371/step2/locals.tf delete mode 100644 released/discovery_center/mission_4371/step2/main.tf delete mode 100644 released/discovery_center/mission_4371/step2/provider.tf delete mode 100644 released/discovery_center/mission_4371/step2/variables.tf create mode 100644 released/discovery_center/mission_4371/variables.tf diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3ad79ddd2c9bb125823a335bc3f27ddb40ec92b3 GIT binary patch literal 6148 zcmeHKISv9b477n_B^pY~e1RWC2wuPkIF@cDBoO^pyo;wXJ_^u62Mroa&LoZ}QKne0 zMMRg^b|Eqokp^xkHyeg#`{n~1Wki8+oUxOO9Hnh9hi;JlK49EN&R})$C;t9)>THun z1*iZOpaN8Y3Vc<8EU(S_;wJNfx%k<-~?ee%)OTY77GAt zVjqYIOoIvxs%DF!K}Wn~UQO%+gD#rQhvv)>%#YYTh}x12lN40ESo@Nx|Fa*TzQj$ WYhoYhbi|zw?E2E77E+d{^KG(P}vX2LO>!AgzeR0uo&+&c)Fff0`&zt!P$b$#35C z^Ek>BaSXtA@8b>70oc+V@#V|f{N8*cZ-;@#)|a zBLH#3a2WS7OAwm}h<)Ll$Oz4nN=&NNh+#=*yj5ObI433@R>OzYldUEci>I@Gi*#6@ zs8tF`fu#bMdF;IZ-_rk>|Cc14q<|DSD+O$`zuWKlO4VCeFXz3s(I4oZ^G$c-J}6wG l9TTG+^Wg3HI+8N4`JVTE;hY$B#)D4O&w%S9lLG&(zz-G-7(D<0 literal 0 HcmV?d00001 diff --git a/released/discovery_center/.DS_Store b/released/discovery_center/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fc228ca097c4d8d60406de4e91a0bda35ec280c1 GIT binary patch literal 6148 zcmeHK!A`AGp$npzgT_$Urgc|Gr$b26$7Hs@j7iR$@bQz;;7e3)CW`&ipvasrJ$i(F~(9W cuAyo{za#_EwU`-14+?(>Xc~B62L6 ⚠ 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. 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_4371/main.tf b/released/discovery_center/mission_4371/main.tf new file mode 100644 index 00000000..37518dde --- /dev/null +++ b/released/discovery_center/mission_4371/main.tf @@ -0,0 +1,168 @@ +# ------------------------------------------------------------------------------------------------------ +# Setup subaccount domain (to ensure uniqueness in BTP global account) +# ------------------------------------------------------------------------------------------------------ +resource "random_uuid" "uuid" {} + +locals { + random_uuid = random_uuid.uuid.result + subaccount_domain = lower(replace("mission-4371-${local.random_uuid}", "_", "-")) +} +# ------------------------------------------------------------------------------------------------------ +# Creation of subaccount +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount" "dc_mission" { + name = var.subaccount_name + subdomain = local.subaccount_domain + region = lower(var.region) +} + +# ------------------------------------------------------------------------------------------------------ +# 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 = btp_subaccount.dc_mission.id + identity_provider = var.custom_idp +} + +# ------------------------------------------------------------------------------------------------------ +# Assignment of users as sub account administrators +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_role_collection_assignment" "subaccount-admins" { + for_each = toset(var.subaccount_admins) + subaccount_id = btp_subaccount.dc_mission.id + role_collection_name = "Subaccount Administrator" + 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 = btp_subaccount.dc_mission.id + role_collection_name = "Subaccount Service Administrator" + user_name = each.value +} + + +# ------------------------------------------------------------------------------------------------------ +# Prepare & setup the SAP AI Core service (ensure your global account has the respective entitlements) +# ------------------------------------------------------------------------------------------------------ + +# Entitle subaccount for usage of SAP AI Core service +# ------------------------------------------------------------------------------------------------------ +# Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for +# available plans and their region availability +resource "btp_subaccount_entitlement" "ai_core" { + subaccount_id = btp_subaccount.dc_mission.id + service_name = "aicore" + plan_name = var.ai_core_plan_name +} + +# Get plan for SAP AI Core service +data "btp_subaccount_service_plan" "ai_core" { + subaccount_id = btp_subaccount.dc_mission.id + offering_name = "aicore" + name = var.ai_core_plan_name + depends_on = [btp_subaccount_entitlement.ai_core] +} + +# Create service instance for SAP AI Core service +resource "btp_subaccount_service_instance" "ai_core" { + subaccount_id = btp_subaccount.dc_mission.id + serviceplan_id = data.btp_subaccount_service_plan.ai_core.id + name = "my-ai-core-instance" + depends_on = [btp_subaccount_entitlement.ai_core] +} + +# Create service binding to SAP AI Core service (exposed for a specific user group) +resource "btp_subaccount_service_binding" "ai_core_binding" { + subaccount_id = btp_subaccount.dc_mission.id + service_instance_id = btp_subaccount_service_instance.ai_core.id + name = "ai-core-key" +} + + +# ------------------------------------------------------------------------------------------------------ +# Entitle subaccount for usage of SAP HANA Cloud tools +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "hana_cloud_tools" { + subaccount_id = btp_subaccount.dc_mission.id + service_name = "hana-cloud-tools" + plan_name = "tools" +} + +resource "btp_subaccount_subscription" "hana_cloud_tools" { + subaccount_id = btp_subaccount.dc_mission.id + app_name = "hana-cloud-tools" + plan_name = "tools" + depends_on = [btp_subaccount_entitlement.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 = btp_subaccount.dc_mission.id + role_collection_name = "SAP HANA Cloud Administrator" + user_name = each.value + depends_on = [btp_subaccount_subscription.hana_cloud_tools] +} + +# ------------------------------------------------------------------------------------------------------ +# Entitle subaccount for usage of SAP HANA Cloud +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "hana_cloud" { + subaccount_id = 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 = 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 = 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] + parameters = jsonencode( + { + "data" : { + "memory" : 32, + "edition" : "cloud", + "systempassword" : "${var.hana_system_password}", + "additionalWorkers" : 0, + "disasterRecoveryMode" : "no_disaster_recovery", + "enabledservices" : { + "docstore" : false, + "dpserver" : true, + "scriptserver" : false + }, + "requestedOperation" : {}, + "serviceStopped" : false, + "slaLevel" : "standard", + "storage" : 120, + "vcpu" : 2, + "whitelistIPs" : ["0.0.0.0/0"] + } + }) + + timeouts = { + create = "45m" + update = "45m" + delete = "45m" + } +} + +# Create service binding to SAP HANA Cloud service +resource "btp_subaccount_service_binding" "hana_cloud" { + subaccount_id = btp_subaccount.dc_mission.id + service_instance_id = btp_subaccount_service_instance.hana_cloud.id + name = "hana-cloud-key" +} diff --git a/released/discovery_center/mission_4371/provider.tf b/released/discovery_center/mission_4371/provider.tf new file mode 100644 index 00000000..c7a536dd --- /dev/null +++ b/released/discovery_center/mission_4371/provider.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + btp = { + source = "SAP/btp" + version = "~> 1.4.0" + } + } +} + +provider "btp" { + globalaccount = var.globalaccount + cli_server_url = var.cli_server_url +} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/sample.tfvars b/released/discovery_center/mission_4371/sample.tfvars new file mode 100644 index 00000000..865dceb4 --- /dev/null +++ b/released/discovery_center/mission_4371/sample.tfvars @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------------------------------------------ +# Provider configuration +# ------------------------------------------------------------------------------------------------------ +# Your global account subdomain +globalaccount = "yourglobalaccount" +region = "us10" +subaccount_name = "SAP Discovery Center Mission 4371" + +# ------------------------------------------------------------------------------------------------------ +# Project specific configuration (please adapt!) +# ------------------------------------------------------------------------------------------------------ + +subaccount_admins = ["another.user@test.com"] +subaccount_service_admins = ["another.user@test.com"] +hana_cloud_admins = ["thomas.ziegert@sap.com", "rui.nogueira@sap.com"] + +custom_idp = "sap.ids" + +# Comment out the next line if you want to provide the password here instead of typing it in the console (not recommended for security reasons) +#hana_system_password = "xxxxxx" diff --git a/released/discovery_center/mission_4371/step1/locals.tf b/released/discovery_center/mission_4371/step1/locals.tf deleted file mode 100644 index 09136428..00000000 --- a/released/discovery_center/mission_4371/step1/locals.tf +++ /dev/null @@ -1,3 +0,0 @@ -locals { - service_name__sac = "analytics-planning-osb" -} diff --git a/released/discovery_center/mission_4371/step1/main.tf b/released/discovery_center/mission_4371/step1/main.tf deleted file mode 100644 index 4afbe398..00000000 --- a/released/discovery_center/mission_4371/step1/main.tf +++ /dev/null @@ -1,90 +0,0 @@ -# ------------------------------------------------------------------------------------------------------ -# Setup of names based on variables -# ------------------------------------------------------------------------------------------------------ -resource "random_uuid" "uuid" {} - -locals { - random_uuid = random_uuid.uuid.result - subaccount_domain = lower("${var.subaccount_name}-${local.random_uuid}") - subaccount_name = var.subaccount_name - subaccount_cf_org = substr(replace("${local.subaccount_domain}", "-", ""), 0, 32) -} - -# ------------------------------------------------------------------------------------------------------ -# Creation of subaccount -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount" "sac_subaccount" { - name = local.subaccount_name - subdomain = local.subaccount_domain - region = lower(var.region) -} - - -# ------------------------------------------------------------------------------------------------------ -# Assignment of basic entitlements for an SAC setup -# ------------------------------------------------------------------------------------------------------ -resource "btp_subaccount_entitlement" "sac__service_instance_plan" { - subaccount_id = btp_subaccount.sac_subaccount.id - service_name = local.service_name__sac - plan_name = var.service_plan__sac -} - - -# ------------------------------------------------------------------------------------------------------ -# Creation of Cloud Foundry environment -# ------------------------------------------------------------------------------------------------------ - -# Fetch all available environments for the subaccount -data "btp_subaccount_environments" "all" { - subaccount_id = btp_subaccount.sac_subaccount.id -} - -# Take the landscape label from the first CF environment if no environment label is provided -resource "terraform_data" "replacement" { - 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 -} - -# Create the Cloud Foundry environment instance -resource "btp_subaccount_environment_instance" "cf_sac" { - subaccount_id = btp_subaccount.sac_subaccount.id - name = local.subaccount_cf_org - environment_type = "cloudfoundry" - service_name = "cloudfoundry" - plan_name = var.cf_plan_name - landscape_label = terraform_data.replacement.output - - parameters = jsonencode({ - instance_name = local.subaccount_cf_org - }) -} - - -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_sac.labels)["API Endpoint"]}" - cf_org_id = "${btp_subaccount_environment_instance.cf_sac.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)} - - service_plan__sac = "${var.service_plan__sac}" - - sac_param_first_name = ${var.sac_param_first_name} - sac_param_last_name = ${var.sac_param_last_name} - sac_param_email = ${var.sac_param_email} - sac_param_host_name = ${var.sac_param_host_name} - - sac_param_number_of_business_intelligence_licenses = ${var.sac_param_number_of_business_intelligence_licenses} - sac_param_number_of_professional_licenses = ${var.sac_param_number_of_professional_licenses} - sac_param_number_of_business_standard_licenses = ${var.sac_param_number_of_business_standard_licenses} - - EOT - filename = "../step2/terraform.tfvars" -} diff --git a/released/discovery_center/mission_4371/step1/outputs.tf b/released/discovery_center/mission_4371/step1/outputs.tf deleted file mode 100644 index d67d9a68..00000000 --- a/released/discovery_center/mission_4371/step1/outputs.tf +++ /dev/null @@ -1,110 +0,0 @@ -output "subaccount_id" { - value = btp_subaccount.sac_subaccount.id - description = "The ID of the subaccount." -} - -output "subaccount_name" { - value = btp_subaccount.sac_subaccount.id - description = "The name of the subaccount." -} - -output "cf_org_name" { - value = local.subaccount_cf_org - description = "The name of the Cloud Foundry org connected to the subaccount." -} - -output "cf_org_id" { - value = btp_subaccount_environment_instance.cf_sac.platform_id - description = "The ID of the Cloud Foundry org connected to the subaccount." -} - -output "cf_api_url" { - value = lookup(jsondecode(btp_subaccount_environment_instance.cf_sac.labels), "API Endpoint", "not found") - description = "API endpoint of the Cloud Foundry environment." -} - -output "cf_landscape_label" { - value = btp_subaccount_environment_instance.cf_sac.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 "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__sac" { - value = var.service_plan__sac - description = "Plan for the service instance of SAC." -} - -output "sac_param_first_name" { - value = var.sac_param_first_name - description = "First name of the SAC responsible" -} - -output "sac_param_last_name" { - value = var.sac_param_last_name - description = "Last name of the SAC responsible" -} - -output "sac_param_email" { - value = var.sac_param_email - description = "Email of the SAC responsible" -} - -output "sac_param_host_name" { - value = var.sac_param_host_name - description = "Host name of the SAC" -} - -output "sac_param_number_of_business_intelligence_licenses" { - value = var.sac_param_number_of_business_intelligence_licenses - description = "Number of business intelligence licenses" -} - - -output "sac_param_number_of_professional_licenses" { - value = var.sac_param_number_of_professional_licenses - description = "Number of business professional licenses" -} - -output "sac_param_number_of_business_standard_licenses" { - value = var.sac_param_number_of_business_standard_licenses - description = "Number of business standard licenses" -} diff --git a/released/discovery_center/mission_4371/step1/provider.tf b/released/discovery_center/mission_4371/step1/provider.tf deleted file mode 100644 index 1f3304c4..00000000 --- a/released/discovery_center/mission_4371/step1/provider.tf +++ /dev/null @@ -1,20 +0,0 @@ - -terraform { - required_providers { - btp = { - source = "sap/btp" - version = "~> 1.4.0" - } - } - -} - -# Please checkout documentation on how best to authenticate against SAP BTP -# via the Terraform provider for SAP BTP -provider "btp" { - # 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_4371/step1/variables.tf b/released/discovery_center/mission_4371/step1/variables.tf deleted file mode 100644 index b32b9291..00000000 --- a/released/discovery_center/mission_4371/step1/variables.tf +++ /dev/null @@ -1,176 +0,0 @@ -variable "globalaccount" { - type = string - description = "The global account subdomain." -} - -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" { - type = string - description = "The region where the project account shall be created in." - default = "eu11" -} - -variable "cf_plan_name" { - type = string - description = "Desired service plan for the Cloud Foundry environment instance." - default = "standard" -} - -variable "cf_landscape_label" { - type = string - description = "The Cloud Foundry landscape (format example eu10-004)." - 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 "service_plan__sac" { - type = string - description = "Plan for the service instance of ABAP." - default = "free" -} - - -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 "sac_param_first_name" { - type = string - description = "First name of the SAC responsible" -} - -variable "sac_param_last_name" { - type = string - description = "Last name of the SAC responsible" -} - -variable "sac_param_email" { - type = string - description = "Email of the SAC responsible" - - validation { - condition = can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", var.sac_param_email)) - error_message = "Please enter a valid email address for the SAC responsible." - } -} - -variable "sac_param_host_name" { - type = string - description = "Host name of the SAC" -} - -variable "sac_param_number_of_business_intelligence_licenses" { - type = number - description = "Number of business intelligence licenses" - default = 6 -} - - -variable "sac_param_number_of_professional_licenses" { - type = number - description = "Number of business professional licenses" - default = 1 -} - -variable "sac_param_number_of_business_standard_licenses" { - type = number - description = "Number of business standard licenses" - default = 2 -} diff --git a/released/discovery_center/mission_4371/step2/locals.tf b/released/discovery_center/mission_4371/step2/locals.tf deleted file mode 100644 index 09136428..00000000 --- a/released/discovery_center/mission_4371/step2/locals.tf +++ /dev/null @@ -1,3 +0,0 @@ -locals { - service_name__sac = "analytics-planning-osb" -} diff --git a/released/discovery_center/mission_4371/step2/main.tf b/released/discovery_center/mission_4371/step2/main.tf deleted file mode 100644 index 0499d9c9..00000000 --- a/released/discovery_center/mission_4371/step2/main.tf +++ /dev/null @@ -1,91 +0,0 @@ -# ------------------------------------------------------------------------------------------------------ -# Assignment of Cloud Foundry org roles -# ------------------------------------------------------------------------------------------------------ -resource "cloudfoundry_org_role" "org_managers" { - for_each = toset("${var.cf_org_managers}") - username = each.value - type = "organization_manager" - org = var.cf_org_id - origin = var.origin -} - -resource "cloudfoundry_org_role" "billing_managers" { - for_each = toset("${var.cf_org_billing_managers}") - username = each.value - type = "organization_billing_manager" - org = var.cf_org_id - origin = var.origin -} - -resource "cloudfoundry_org_role" "org_auditors" { - for_each = toset("${var.cf_org_auditors}") - username = each.value - type = "organization_auditor" - org = var.cf_org_id - origin = var.origin -} - -# ------------------------------------------------------------------------------------------------------ -# Creation of Cloud Foundry space -# ------------------------------------------------------------------------------------------------------ -resource "cloudfoundry_space" "sac_space" { - name = var.cf_space_name - org = var.cf_org_id -} - -# ------------------------------------------------------------------------------------------------------ -# Assignment of Cloud Foundry org roles -# ------------------------------------------------------------------------------------------------------ -resource "cloudfoundry_space_role" "space_managers" { - for_each = toset("${var.cf_space_managers}") - username = each.value - type = "space_manager" - space = cloudfoundry_space.sac_space.id - origin = var.origin -} - -resource "cloudfoundry_space_role" "space_developers" { - for_each = toset("${var.cf_space_developers}") - username = each.value - type = "space_developer" - space = cloudfoundry_space.sac_space.id - origin = var.origin -} - -resource "cloudfoundry_space_role" "space_auditors" { - for_each = toset("${var.cf_space_auditors}") - username = each.value - type = "space_auditor" - space = cloudfoundry_space.sac_space.id - origin = var.origin -} - -# ------------------------------------------------------------------------------------------------------ -# Creation of service instance for SAP Analytics Bloud -# ------------------------------------------------------------------------------------------------------ -data "cloudfoundry_service" "sac_service_plans" { - name = local.service_name__sac -} - -resource "cloudfoundry_service_instance" "sac_si" { - depends_on = [cloudfoundry_space_role.space_managers, cloudfoundry_space_role.space_developers] - name = "service-analytics-planning-osb" - space = cloudfoundry_space.sac_space.id - service_plan = data.cloudfoundry_service.sac_service_plans.service_plans[var.service_plan__sac] - type = "managed" - parameters = jsonencode({ - "first_name" : "${var.sac_param_first_name}", - "last_name" : "${var.sac_param_last_name}", - "email" : "${var.sac_param_email}", - "confirm_email" : "${var.sac_param_email}", - "host_name" : "${var.sac_param_host_name}", - "number_of_business_intelligence_licenses" : var.sac_param_number_of_business_intelligence_licenses, - "number_of_planning_professional_licenses" : var.sac_param_number_of_professional_licenses, - "number_of_planning_standard_licenses" : var.sac_param_number_of_business_standard_licenses - }) - timeouts = { - create = "2h" - delete = "2h" - update = "2h" - } -} diff --git a/released/discovery_center/mission_4371/step2/provider.tf b/released/discovery_center/mission_4371/step2/provider.tf deleted file mode 100644 index 7a11e78f..00000000 --- a/released/discovery_center/mission_4371/step2/provider.tf +++ /dev/null @@ -1,16 +0,0 @@ -terraform { - required_providers { - cloudfoundry = { - source = "sap/cloudfoundry" - version = "0.2.1-beta" - } - } -} - -# 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_4371/step2/variables.tf b/released/discovery_center/mission_4371/step2/variables.tf deleted file mode 100644 index a437e919..00000000 --- a/released/discovery_center/mission_4371/step2/variables.tf +++ /dev/null @@ -1,144 +0,0 @@ -variable "cf_api_url" { - type = string - description = "The API endpoint of the Cloud Foundry environment." -} - -variable "cf_org_id" { - type = string - description = "The Cloud Foundry landscape (format example eu10-004)." -} - -variable "origin" { - type = string - description = "The identity provider for the UAA user." - default = "sap.ids" -} - -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 = [] - - # 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 "service_plan__sac" { - type = string - description = "Plan for the service instance of ABAP." - default = "free" -} - -variable "sac_param_first_name" { - type = string - description = "First name of the SAC responsible" -} - -variable "sac_param_last_name" { - type = string - description = "Last name of the SAC responsible" -} - -variable "sac_param_email" { - type = string - description = "Email of the SAC responsible" - - validation { - condition = can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", var.sac_param_email)) - error_message = "Please enter a valid email address for the SAC responsible." - } -} - -variable "sac_param_host_name" { - type = string - description = "Host name of the SAC" -} - -variable "sac_param_number_of_business_intelligence_licenses" { - type = number - description = "Number of business intelligence licenses" - default = 6 -} - - -variable "sac_param_number_of_professional_licenses" { - type = number - description = "Number of business professional licenses" - default = 1 -} - -variable "sac_param_number_of_business_standard_licenses" { - type = number - description = "Number of business standard licenses" - default = 2 -} diff --git a/released/discovery_center/mission_4371/variables.tf b/released/discovery_center/mission_4371/variables.tf new file mode 100644 index 00000000..ba76efc9 --- /dev/null +++ b/released/discovery_center/mission_4371/variables.tf @@ -0,0 +1,151 @@ +###################################################################### +# Customer account setup +###################################################################### +variable "globalaccount" { + type = string + description = "Defines the global account" + default = "yourglobalaccount" +} + +variable "cli_server_url" { + type = string + description = "Defines the CLI server URL" + default = "https://cli.btp.cloud.sap" +} + +# subaccount +variable "subaccount_name" { + type = string + description = "The subaccount name." + default = "SAP Discovery Center Mission 3774 - Central Inbox with SAP Task Center" +} +variable "subaccount_id" { + type = string + description = "The subaccount ID." + default = "" +} + +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 CF space managers." + } +} + +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 + 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 CF space managers." + } +} + +variable "region" { + type = string + description = "The region where the sub account shall be created in." + default = "us10" + + # Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for the latest list of regions + # supported by the AI Core service with the "extended" service plan. + validation { + condition = contains(["ap10", "eu10", "eu11", "eu20", "eu30", "jp10", "us10", "us21", "us30"], var.region) + error_message = "Please enter a valid region for the sub account. Checkout https://github.com/SAP-samples/btp-service-metadata/blob/main/v0/developer/aicore.json for regions providing the AI Core service." + } +} + + +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." + } +} + +variable "custom_idp" { + type = string + description = "Defines the custom IdP" + default = "" +} + +variable "origin_key" { + 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 "create_tfvars_file_for_step2" { + type = bool + description = "Switch to enable the creation of the tfvars file for step 2." + default = false +} + +variable "ai_core_plan_name" { + type = string + description = "The name of the AI Core service plan." + default = "extended" + validation { + condition = contains(["extended"], var.ai_core_plan_name) + error_message = "Valid values for ai_core_plan_name are: extended." + } +} + +variable "hana_system_password" { + type = string + description = "The password of the database 'superuser' DBADMIN." + sensitive = true + + # add validation to check if the password is at least 8 characters long + validation { + condition = length(var.hana_system_password) > 7 + error_message = "The hana_system_password must be at least 8 characters long." + } + + # add validation to check if the password contains at least one upper case + validation { + condition = can(regex("[A-Z]", var.hana_system_password)) + error_message = "The hana_system_password must contain at least one upper case." + } + + # add validation to check if the password contains at least two lower case characters that can occur on arbitrary places in the string (not necessarily in a row) + validation { + condition = length(regexall("[a-z]", var.hana_system_password)) > 1 + error_message = "The hana_system_password must contain at least two lower case characters." + } + + # add validation to check if the password contains at least one numeric character + validation { + condition = can(regex("[0-9]", var.hana_system_password)) + error_message = "The hana_system_password must contain at least one numeric character." + } +} + +variable "target_ai_core_model" { + type = list(any) + description = "Defines the target AI core model to be used by the AI Core service" + default = ["gpt-35-turbo"] + + validation { + condition = length([ + for o in var.target_ai_core_model : true + if contains(["gpt-35-turbo", "gpt-35-turbo-0125", "gpt-35-turbo-16k", "gpt-4", "gpt-4-32k", "text-embedding-ada-002", "gemini-1.0-pro", "text-bison", "chat-bison", "textembedding-gecko-multilingual", "textembedding-gecko", "tiiuae--falcon-40b-instruct"], o) + ]) == length(var.target_ai_core_model) + error_message = "Please enter a valid entry for the target_ai_core_model of the AI Core service. Valid values are: gpt-35-turbo, gpt-35-turbo-16k, gpt-4, gpt-4-32k, text-embedding-ada-002, tiiuae--falcon-40b-instruct." + } +} From 9455361fc6d06994587db9d9f2859b63a2c3e5a7 Mon Sep 17 00:00:00 2001 From: Mahesh kumar Palavalli Date: Thu, 4 Jul 2024 19:37:57 +0530 Subject: [PATCH 09/14] refactor: made it to two step and add few other entitlements --- .../discovery_center/mission_4371/README.md | 36 ++-------- .../discovery_center/mission_4371/apply.sh | 14 ++++ .../discovery_center/mission_4371/destroy.sh | 12 ++++ .../{sample.tfvars => samples.tfvars} | 17 +++-- .../mission_4371/{ => step1}/main.tf | 61 ++++++++++++++--- .../mission_4371/step1/output.tf | 15 +++++ .../mission_4371/{ => step1}/provider.tf | 0 .../mission_4371/{ => step1}/variables.tf | 31 +++++++-- .../mission_4371/step2/main.tf | 44 ++++++++++++ .../mission_4371/step2/output.tf | 19 ++++++ .../mission_4371/step2/provider.tf | 16 +++++ .../mission_4371/step2/variables.tf | 67 +++++++++++++++++++ 12 files changed, 279 insertions(+), 53 deletions(-) create mode 100755 released/discovery_center/mission_4371/apply.sh create mode 100755 released/discovery_center/mission_4371/destroy.sh rename released/discovery_center/mission_4371/{sample.tfvars => samples.tfvars} (58%) rename released/discovery_center/mission_4371/{ => step1}/main.tf (78%) create mode 100644 released/discovery_center/mission_4371/step1/output.tf rename released/discovery_center/mission_4371/{ => step1}/provider.tf (100%) rename released/discovery_center/mission_4371/{ => step1}/variables.tf (89%) create mode 100644 released/discovery_center/mission_4371/step2/main.tf create mode 100644 released/discovery_center/mission_4371/step2/output.tf create mode 100644 released/discovery_center/mission_4371/step2/provider.tf create mode 100644 released/discovery_center/mission_4371/step2/variables.tf diff --git a/released/discovery_center/mission_4371/README.md b/released/discovery_center/mission_4371/README.md index b063c7f2..9aaa9709 100644 --- a/released/discovery_center/mission_4371/README.md +++ b/released/discovery_center/mission_4371/README.md @@ -18,40 +18,14 @@ The setup comprises the following resources: To deploy the resources you must: -1. Create a file `secret.auto.tfvars` and maintain the credentials for the BTP and CF provider +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. - ```hcl - username = "" - password = "" - ``` - -2. Change the variables in the `samples.tfvars` file to meet your requirements +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. -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: +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. -```bash -terraform destroy -var-file="sample.tfvars" -``` +5. Clean up by running the destroy.sh script. \ No newline at end of file diff --git a/released/discovery_center/mission_4371/apply.sh b/released/discovery_center/mission_4371/apply.sh new file mode 100755 index 00000000..65e4cfff --- /dev/null +++ b/released/discovery_center/mission_4371/apply.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +cd step1 + +terraform init +terraform apply -var-file='../my_samples.tfvars' -auto-approve +terraform output > ../step2/step1vars.tfvars + +cd ../step2 + +terraform init +terraform apply -var-file=step1vars.tfvars -var-file='../my_samples.tfvars' -auto-approve + +cd .. \ No newline at end of file diff --git a/released/discovery_center/mission_4371/destroy.sh b/released/discovery_center/mission_4371/destroy.sh new file mode 100755 index 00000000..c149b746 --- /dev/null +++ b/released/discovery_center/mission_4371/destroy.sh @@ -0,0 +1,12 @@ +#!/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_4371/sample.tfvars b/released/discovery_center/mission_4371/samples.tfvars similarity index 58% rename from released/discovery_center/mission_4371/sample.tfvars rename to released/discovery_center/mission_4371/samples.tfvars index 8beb14b5..184001d0 100644 --- a/released/discovery_center/mission_4371/sample.tfvars +++ b/released/discovery_center/mission_4371/samples.tfvars @@ -5,17 +5,24 @@ globalaccount = "yourglobalaccount" region = "us10" subaccount_name = "SAP Discovery Center Mission 4371" +cf_org_name = "cf-environment" # ------------------------------------------------------------------------------------------------------ # Project specific configuration (please adapt!) # ------------------------------------------------------------------------------------------------------ -subaccount_admins = ["another.user@test.com"] -subaccount_service_admins = ["another.user@test.com"] -hana_cloud_admins = ["thomas.ziegert@sap.com", "rui.nogueira@sap.com"] +subaccount_admins = ["john.doe@sap.com"] +subaccount_service_admins = ["john.doe@sap.com"] +hana_cloud_admins = ["john.doe@sap.com"] custom_idp = "sap.ids" -# Comment out the next line if you want to provide the password here instead of typing it in the console (not recommended for security reasons) -#hana_system_password = "xxxxxx" +hana_system_password = "Abc12345" +cf_space_developers = ["john.doe@sap.com"] +cf_space_managers = ["john.doe@sap.com"] +cf_org_admins = ["john.doe@sap.com"] +cf_org_users = ["john.doe@sap.com"] + +event_mesh_admins = ["john.doe@sap.com"] +event_mesh_developers = ["john.doe@sap.com"] diff --git a/released/discovery_center/mission_4371/main.tf b/released/discovery_center/mission_4371/step1/main.tf similarity index 78% rename from released/discovery_center/mission_4371/main.tf rename to released/discovery_center/mission_4371/step1/main.tf index c7564ca3..db60d21d 100644 --- a/released/discovery_center/mission_4371/main.tf +++ b/released/discovery_center/mission_4371/step1/main.tf @@ -6,6 +6,7 @@ resource "random_uuid" "uuid" {} locals { random_uuid = random_uuid.uuid.result subaccount_domain = lower(replace("mission-4371-${local.random_uuid}", "_", "-")) + project_subaccount_cf_org = substr(replace("${local.subaccount_domain}", "-", ""), 0, 32) } # ------------------------------------------------------------------------------------------------------ # Creation of subaccount @@ -14,16 +15,7 @@ resource "btp_subaccount" "dc_mission" { name = var.subaccount_name subdomain = local.subaccount_domain region = lower(var.region) -} - -# ------------------------------------------------------------------------------------------------------ -# 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 = btp_subaccount.dc_mission.id - identity_provider = var.custom_idp + usage = "USED_FOR_PRODUCTION" } # ------------------------------------------------------------------------------------------------------ @@ -167,3 +159,52 @@ resource "btp_subaccount_service_binding" "hana_cloud" { name = "hana-cloud-key" } + +# ------------------------------------------------------------------------------------------------------ +# Entitle subaccount for usage of SAP Cloud Management service for SAP BTP - cis +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "cis" { + subaccount_id = btp_subaccount.dc_mission.id + service_name = "cis" + plan_name = "central" +} + +###################################################################### +# Extract list of CF landscape labels from environments +###################################################################### +data "btp_subaccount_environments" "all" { + subaccount_id = btp_subaccount.dc_mission.id +} + +locals { + cf_landscape_labels = [ + for env in data.btp_subaccount_environments.all.values : env.landscape_label + if env.environment_type == "cloudfoundry" + ] +} + + +###################################################################### +# Creation of Cloud Foundry environment +###################################################################### +resource "btp_subaccount_environment_instance" "cloudfoundry" { + subaccount_id = btp_subaccount.dc_mission.id + name = var.cf_org_name + environment_type = "cloudfoundry" + service_name = "cloudfoundry" + plan_name = "standard" + landscape_label =local.cf_landscape_labels[0] + parameters = jsonencode({ + instance_name = local.project_subaccount_cf_org + }) +} + +# ------------------------------------------------------------------------------------------------------ +# Entitle subaccount for usage of SAP Credential Store - credstore +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount_entitlement" "credstore" { + subaccount_id = btp_subaccount.dc_mission.id + service_name = "credstore" + plan_name = var.credstore_plan_name + amount = var.credstore_plan_name == "free" ? 1 : null +} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/step1/output.tf b/released/discovery_center/mission_4371/step1/output.tf new file mode 100644 index 00000000..0648e22b --- /dev/null +++ b/released/discovery_center/mission_4371/step1/output.tf @@ -0,0 +1,15 @@ +output "cf_landscape_label" { + value = btp_subaccount_environment_instance.cloudfoundry.landscape_label +} + +output "cf_api_url" { + value = jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["API Endpoint"] +} + +output "cf_org_id" { + value = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +output "subaccount_id" { + value = btp_subaccount.dc_mission.id +} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/provider.tf b/released/discovery_center/mission_4371/step1/provider.tf similarity index 100% rename from released/discovery_center/mission_4371/provider.tf rename to released/discovery_center/mission_4371/step1/provider.tf diff --git a/released/discovery_center/mission_4371/variables.tf b/released/discovery_center/mission_4371/step1/variables.tf similarity index 89% rename from released/discovery_center/mission_4371/variables.tf rename to released/discovery_center/mission_4371/step1/variables.tf index 102cde54..38772535 100644 --- a/released/discovery_center/mission_4371/variables.tf +++ b/released/discovery_center/mission_4371/step1/variables.tf @@ -81,13 +81,13 @@ variable "custom_idp" { default = "" } -variable "origin_key" { - 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" { +# 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 "create_tfvars_file_for_step2" { @@ -150,3 +150,20 @@ variable "target_ai_core_model" { } } +# cf org name +variable "cf_org_name" { + type = string + description = "Cloud Foundry Org Name" + default = "cloud-foundry" +} + +# credential store +variable "credstore_plan_name" { + type = string + description = "The name of the Credential Store plan." + default = "free" + validation { + condition = contains(["free", "standard"], var.credstore_plan_name) + error_message = "Valid values for Credential Store plan are: free, standard." + } +} diff --git a/released/discovery_center/mission_4371/step2/main.tf b/released/discovery_center/mission_4371/step2/main.tf new file mode 100644 index 00000000..b13a98d3 --- /dev/null +++ b/released/discovery_center/mission_4371/step2/main.tf @@ -0,0 +1,44 @@ +###################################################################### +# Create space using CF provider +###################################################################### +resource "cloudfoundry_space" "dev" { + name = "DEV" + org = var.cf_org_id +} + +###################################################################### +# add org and space users and managers +###################################################################### +resource "cloudfoundry_org_role" "organization_user" { + for_each = toset(var.cf_org_users) + username = each.value + type = "organization_user" + org = var.cf_org_id + # origin = var.origin +} + +resource "cloudfoundry_org_role" "organization_manager" { + for_each = toset(var.cf_org_admins) + username = each.value + type = "organization_manager" + org = var.cf_org_id + # origin = var.origin +} + +resource "cloudfoundry_space_role" "space_developer" { + for_each = toset(var.cf_space_developers) + username = each.value + type = "space_developer" + space = cloudfoundry_space.dev.id + # origin = var.origin + depends_on = [ cloudfoundry_org_role.organization_user, cloudfoundry_org_role.organization_manager ] +} + +resource "cloudfoundry_space_role" "space_manager" { + for_each = toset(var.cf_space_managers) + username = each.value + type = "space_manager" + space = cloudfoundry_space.dev.id + # origin = var.origin + 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_4371/step2/output.tf b/released/discovery_center/mission_4371/step2/output.tf new file mode 100644 index 00000000..9425898f --- /dev/null +++ b/released/discovery_center/mission_4371/step2/output.tf @@ -0,0 +1,19 @@ +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_4371/step2/provider.tf b/released/discovery_center/mission_4371/step2/provider.tf new file mode 100644 index 00000000..a42145c5 --- /dev/null +++ b/released/discovery_center/mission_4371/step2/provider.tf @@ -0,0 +1,16 @@ +terraform { + required_providers { + cloudfoundry = { + source = "SAP/cloudfoundry" + version = "0.2.1-beta" + } + } +} + +###################################################################### +# Configure CF provider +###################################################################### +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_4371/step2/variables.tf b/released/discovery_center/mission_4371/step2/variables.tf new file mode 100644 index 00000000..caeb8520 --- /dev/null +++ b/released/discovery_center/mission_4371/step2/variables.tf @@ -0,0 +1,67 @@ +variable "cf_api_url" { + type = string +} + +variable "cf_landscape_label" { + type = string +} + +variable "cf_org_id" { + type = string +} + +variable "subaccount_id" { + type = string +} + +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 + 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." + } +} + +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" +} From b1d13652a6be830616f301bb0ddbf3683eb78099 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Thu, 4 Jul 2024 16:08:53 +0200 Subject: [PATCH 10/14] fix user names --- released/discovery_center/mission_4371/sample.tfvars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/released/discovery_center/mission_4371/sample.tfvars b/released/discovery_center/mission_4371/sample.tfvars index 865dceb4..aa86c246 100644 --- a/released/discovery_center/mission_4371/sample.tfvars +++ b/released/discovery_center/mission_4371/sample.tfvars @@ -12,7 +12,7 @@ subaccount_name = "SAP Discovery Center Mission 4371" subaccount_admins = ["another.user@test.com"] subaccount_service_admins = ["another.user@test.com"] -hana_cloud_admins = ["thomas.ziegert@sap.com", "rui.nogueira@sap.com"] +hana_cloud_admins = ["another.user@test.com", "you@test.com"] custom_idp = "sap.ids" From 26374a4584b13ac7c37019eb41e24851f8cbf1e2 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Tue, 9 Jul 2024 07:56:47 +0000 Subject: [PATCH 11/14] cleanup --- .../mission_4371/{ => step1}/README.md | 0 .../mission_4371/step1/main.tf | 4 +- .../mission_4371/step1/output.tf | 6 +- .../mission_4371/{ => step1}/samples.tfvars | 0 .../mission_4371/step1/variables.tf | 88 +++++++++++++++++-- .../mission_4371/step2/main.tf | 8 +- .../mission_4371/step2/output.tf | 8 +- .../mission_4371/step2/provider.tf | 4 +- .../mission_4371/step2/variables.tf | 8 +- 9 files changed, 98 insertions(+), 28 deletions(-) rename released/discovery_center/mission_4371/{ => step1}/README.md (100%) rename released/discovery_center/mission_4371/{ => step1}/samples.tfvars (100%) diff --git a/released/discovery_center/mission_4371/README.md b/released/discovery_center/mission_4371/step1/README.md similarity index 100% rename from released/discovery_center/mission_4371/README.md rename to released/discovery_center/mission_4371/step1/README.md diff --git a/released/discovery_center/mission_4371/step1/main.tf b/released/discovery_center/mission_4371/step1/main.tf index f4429c77..65315fb7 100644 --- a/released/discovery_center/mission_4371/step1/main.tf +++ b/released/discovery_center/mission_4371/step1/main.tf @@ -4,8 +4,8 @@ resource "random_uuid" "uuid" {} locals { - random_uuid = random_uuid.uuid.result - subaccount_domain = lower(replace("mission-4371-${local.random_uuid}", "_", "-")) + random_uuid = random_uuid.uuid.result + subaccount_domain = lower(replace("mission-4371-${local.random_uuid}", "_", "-")) project_subaccount_cf_org = substr(replace("${local.subaccount_domain}", "-", ""), 0, 32) } # ------------------------------------------------------------------------------------------------------ diff --git a/released/discovery_center/mission_4371/step1/output.tf b/released/discovery_center/mission_4371/step1/output.tf index 0648e22b..88aec6f0 100644 --- a/released/discovery_center/mission_4371/step1/output.tf +++ b/released/discovery_center/mission_4371/step1/output.tf @@ -3,13 +3,13 @@ output "cf_landscape_label" { } output "cf_api_url" { - value = jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["API Endpoint"] + value = jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["API Endpoint"] } output "cf_org_id" { - value = btp_subaccount_environment_instance.cloudfoundry.platform_id + value = btp_subaccount_environment_instance.cloudfoundry.platform_id } output "subaccount_id" { - value = btp_subaccount.dc_mission.id + value = btp_subaccount.dc_mission.id } \ No newline at end of file diff --git a/released/discovery_center/mission_4371/samples.tfvars b/released/discovery_center/mission_4371/step1/samples.tfvars similarity index 100% rename from released/discovery_center/mission_4371/samples.tfvars rename to released/discovery_center/mission_4371/step1/samples.tfvars diff --git a/released/discovery_center/mission_4371/step1/variables.tf b/released/discovery_center/mission_4371/step1/variables.tf index 1f0a634b..b8a774ea 100644 --- a/released/discovery_center/mission_4371/step1/variables.tf +++ b/released/discovery_center/mission_4371/step1/variables.tf @@ -81,15 +81,6 @@ variable "custom_idp" { default = "" } -# 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 "create_tfvars_file_for_step2" { type = bool description = "Switch to enable the creation of the tfvars file for step 2." @@ -149,3 +140,82 @@ variable "target_ai_core_model" { error_message = "Please enter a valid entry for the target_ai_core_model of the AI Core service. Valid values are: gpt-35-turbo, gpt-35-turbo-16k, gpt-4, gpt-4-32k, text-embedding-ada-002, tiiuae--falcon-40b-instruct." } } + +variable "cf_api_url" { + type = string +} + +variable "cf_landscape_label" { + type = string +} + +variable "cf_org_id" { + type = string +} + +variable "subaccount_id" { + type = string +} + +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 + 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." + } +} + +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 "cf_org_name" { + type = string + description = "Name of the Cloud Foundry org." + default = "mission-3774-sap-task-center" + + validation { + condition = can(regex("^.{1,255}$", var.cf_org_name)) + error_message = "The Cloud Foundry org name must not be emtpy and not exceed 255 characters." + } +} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/step2/main.tf b/released/discovery_center/mission_4371/step2/main.tf index b13a98d3..70e8df36 100644 --- a/released/discovery_center/mission_4371/step2/main.tf +++ b/released/discovery_center/mission_4371/step2/main.tf @@ -2,8 +2,8 @@ # Create space using CF provider ###################################################################### resource "cloudfoundry_space" "dev" { - name = "DEV" - org = var.cf_org_id + name = "DEV" + org = var.cf_org_id } ###################################################################### @@ -31,7 +31,7 @@ resource "cloudfoundry_space_role" "space_developer" { type = "space_developer" space = cloudfoundry_space.dev.id # origin = var.origin - depends_on = [ cloudfoundry_org_role.organization_user, cloudfoundry_org_role.organization_manager ] + depends_on = [cloudfoundry_org_role.organization_user, cloudfoundry_org_role.organization_manager] } resource "cloudfoundry_space_role" "space_manager" { @@ -40,5 +40,5 @@ resource "cloudfoundry_space_role" "space_manager" { type = "space_manager" space = cloudfoundry_space.dev.id # origin = var.origin - depends_on = [ cloudfoundry_org_role.organization_user, cloudfoundry_org_role.organization_manager ] + 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_4371/step2/output.tf b/released/discovery_center/mission_4371/step2/output.tf index 9425898f..ad4178cd 100644 --- a/released/discovery_center/mission_4371/step2/output.tf +++ b/released/discovery_center/mission_4371/step2/output.tf @@ -1,5 +1,5 @@ output "subaccount_id" { - value = var.subaccount_id + value = var.subaccount_id } output "cf_landscape_label" { @@ -7,13 +7,13 @@ output "cf_landscape_label" { } output "cf_org_id" { - value = var.cf_org_id + value = var.cf_org_id } output "cf_api_url" { - value = var.cf_api_url + value = var.cf_api_url } output "cf_space_name" { - value = cloudfoundry_space.dev.name + value = cloudfoundry_space.dev.name } \ No newline at end of file diff --git a/released/discovery_center/mission_4371/step2/provider.tf b/released/discovery_center/mission_4371/step2/provider.tf index a42145c5..9337283b 100644 --- a/released/discovery_center/mission_4371/step2/provider.tf +++ b/released/discovery_center/mission_4371/step2/provider.tf @@ -11,6 +11,6 @@ terraform { # Configure CF provider ###################################################################### provider "cloudfoundry" { - # resolve API URL from environment instance - api_url = var.cf_api_url + # 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_4371/step2/variables.tf b/released/discovery_center/mission_4371/step2/variables.tf index caeb8520..909216f7 100644 --- a/released/discovery_center/mission_4371/step2/variables.tf +++ b/released/discovery_center/mission_4371/step2/variables.tf @@ -1,17 +1,17 @@ variable "cf_api_url" { - type = string + type = string } variable "cf_landscape_label" { - type = string + type = string } variable "cf_org_id" { - type = string + type = string } variable "subaccount_id" { - type = string + type = string } variable "cf_space_developers" { From 464b72b0904b55614a4fd6de44311b86082fbf23 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Tue, 9 Jul 2024 08:11:08 +0000 Subject: [PATCH 12/14] remove .DS_Store files and add to gitignore --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + released/.DS_Store | Bin 6148 -> 0 bytes released/discovery_center/.DS_Store | Bin 6148 -> 0 bytes 4 files changed, 1 insertion(+) delete mode 100644 .DS_Store delete mode 100644 released/.DS_Store delete mode 100644 released/discovery_center/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 3ad79ddd2c9bb125823a335bc3f27ddb40ec92b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKISv9b477n_B^pY~e1RWC2wuPkIF@cDBoO^pyo;wXJ_^u62Mroa&LoZ}QKne0 zMMRg^b|Eqokp^xkHyeg#`{n~1Wki8+oUxOO9Hnh9hi;JlK49EN&R})$C;t9)>THun z1*iZOpaN8Y3Vc<8EU(S_;wJNfx%k<-~?ee%)OTY77GAt zVjqYIOoIvxs%DF!K}Wn~UQO%+gD#rQhvv)>%#YYTh}x12lN40ESo@Nx|Fa*TzQj$ WYhoYhbi|zw?E2E77E+d{^KG(P}vX2LO>!AgzeR0uo&+&c)Fff0`&zt!P$b$#35C z^Ek>BaSXtA@8b>70oc+V@#V|f{N8*cZ-;@#)|a zBLH#3a2WS7OAwm}h<)Ll$Oz4nN=&NNh+#=*yj5ObI433@R>OzYldUEci>I@Gi*#6@ zs8tF`fu#bMdF;IZ-_rk>|Cc14q<|DSD+O$`zuWKlO4VCeFXz3s(I4oZ^G$c-J}6wG l9TTG+^Wg3HI+8N4`JVTE;hY$B#)D4O&w%S9lLG&(zz-G-7(D<0 diff --git a/released/discovery_center/.DS_Store b/released/discovery_center/.DS_Store deleted file mode 100644 index fc228ca097c4d8d60406de4e91a0bda35ec280c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK!A`AGp$npzgT_$Urgc|Gr$b26$7Hs@j7iR$@bQz;;7e3)CW`&ipvasrJ$i(F~(9W cuAyo{za#_EwU`-14+?(>Xc~B62L6 Date: Wed, 10 Jul 2024 12:08:33 +0000 Subject: [PATCH 13/14] apply best practices for tf scripts in QAS --- .../mission_4371/step1/main.tf | 58 +++++++++++++++++-- .../mission_4371/step1/output.tf | 20 ++++--- .../mission_4371/step1/provider.tf | 7 ++- .../mission_4371/step1/samples.tfvars | 25 ++++---- .../mission_4371/step1/variables.tf | 24 ++++---- .../mission_4371/step2/main.tf | 26 ++++----- .../mission_4371/step2/output.tf | 4 -- .../mission_4371/step2/variables.tf | 15 +++-- 8 files changed, 119 insertions(+), 60 deletions(-) diff --git a/released/discovery_center/mission_4371/step1/main.tf b/released/discovery_center/mission_4371/step1/main.tf index 65315fb7..11737739 100644 --- a/released/discovery_center/mission_4371/step1/main.tf +++ b/released/discovery_center/mission_4371/step1/main.tf @@ -1,12 +1,13 @@ # ------------------------------------------------------------------------------------------------------ -# Setup subaccount domain (to ensure uniqueness in BTP global account) +# Setup of names in accordance to naming convention # ------------------------------------------------------------------------------------------------------ resource "random_uuid" "uuid" {} locals { - random_uuid = random_uuid.uuid.result - subaccount_domain = lower(replace("mission-4371-${local.random_uuid}", "_", "-")) - project_subaccount_cf_org = substr(replace("${local.subaccount_domain}", "-", ""), 0, 32) + random_uuid = random_uuid.uuid.result + subaccount_domain = lower(replace("mission-4356-${local.random_uuid}", "_", "-")) + # If a cf_org_name was defined by the user, take that as a subaccount_cf_org. Otherwise create it. + subaccount_cf_org = length(var.cf_org_name) > 0 ? var.cf_org_name : substr(replace("${local.subaccount_domain}", "-", ""), 0, 32) } # ------------------------------------------------------------------------------------------------------ # Creation of subaccount @@ -159,3 +160,52 @@ resource "btp_subaccount_service_binding" "hana_cloud" { name = "hana-cloud-key" } + + +# ------------------------------------------------------------------------------------------------------ +# CLOUDFOUNDRY PREPARATION +# ------------------------------------------------------------------------------------------------------ +# +# Fetch all available environments for the subaccount +data "btp_subaccount_environments" "all" { + subaccount_id = btp_subaccount.dc_mission.id +} +# ------------------------------------------------------------------------------------------------------ +# Take the landscape label from the first CF environment if no environment label is provided +# (this replaces the previous null_resource) +# ------------------------------------------------------------------------------------------------------ +resource "terraform_data" "replacement" { + 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 = btp_subaccount.dc_mission.id + name = local.subaccount_cf_org + environment_type = "cloudfoundry" + service_name = "cloudfoundry" + plan_name = "standard" + landscape_label = terraform_data.replacement.output + parameters = jsonencode({ + instance_name = local.subaccount_cf_org + }) +} +# ------------------------------------------------------------------------------------------------------ +# 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 + subaccount_id = "${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"]}" + origin = "${var.origin}" + cf_space_name = "${var.cf_space_name}" + cf_org_admins = ${jsonencode(var.cf_org_admins)} + cf_org_users = ${jsonencode(var.cf_org_users)} + cf_space_developers = ${jsonencode(var.cf_space_developers)} + cf_space_managers = ${jsonencode(var.cf_space_managers)} + EOT + filename = "../step2/terraform.tfvars" +} \ No newline at end of file diff --git a/released/discovery_center/mission_4371/step1/output.tf b/released/discovery_center/mission_4371/step1/output.tf index 88aec6f0..a06388a1 100644 --- a/released/discovery_center/mission_4371/step1/output.tf +++ b/released/discovery_center/mission_4371/step1/output.tf @@ -1,15 +1,19 @@ -output "cf_landscape_label" { - value = btp_subaccount_environment_instance.cloudfoundry.landscape_label +output "subaccount_id" { + value = btp_subaccount.dc_mission.id + description = "The ID of the subaccount." } output "cf_api_url" { - value = jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["API Endpoint"] + value = jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["API Endpoint"] + description = "The Cloudfoundry API endpoint." } -output "cf_org_id" { - value = btp_subaccount_environment_instance.cloudfoundry.platform_id +output "cf_landscape_label" { + value = terraform_data.replacement.output + description = "The Cloudfoundry landscape label." } -output "subaccount_id" { - value = btp_subaccount.dc_mission.id -} \ No newline at end of file +output "cf_org_id" { + value = jsondecode(btp_subaccount_environment_instance.cloudfoundry.labels)["Org ID"] + description = "The Cloudfoundry org id." +} diff --git a/released/discovery_center/mission_4371/step1/provider.tf b/released/discovery_center/mission_4371/step1/provider.tf index c7a536dd..0728b747 100644 --- a/released/discovery_center/mission_4371/step1/provider.tf +++ b/released/discovery_center/mission_4371/step1/provider.tf @@ -1,7 +1,10 @@ +# ------------------------------------------------------------------------------------------------------ +# Define the required providers for this module +# ------------------------------------------------------------------------------------------------------ terraform { required_providers { btp = { - source = "SAP/btp" + source = "sap/btp" version = "~> 1.4.0" } } @@ -10,4 +13,4 @@ terraform { provider "btp" { globalaccount = var.globalaccount cli_server_url = var.cli_server_url -} \ No newline at end of file +} diff --git a/released/discovery_center/mission_4371/step1/samples.tfvars b/released/discovery_center/mission_4371/step1/samples.tfvars index 184001d0..31d98c90 100644 --- a/released/discovery_center/mission_4371/step1/samples.tfvars +++ b/released/discovery_center/mission_4371/step1/samples.tfvars @@ -5,24 +5,21 @@ globalaccount = "yourglobalaccount" region = "us10" subaccount_name = "SAP Discovery Center Mission 4371" -cf_org_name = "cf-environment" +custom_idp = "sap.ids" # ------------------------------------------------------------------------------------------------------ # Project specific configuration (please adapt!) # ------------------------------------------------------------------------------------------------------ -subaccount_admins = ["john.doe@sap.com"] -subaccount_service_admins = ["john.doe@sap.com"] -hana_cloud_admins = ["john.doe@sap.com"] +# Don't add the user, that is executing the TF script to subaccount_admins or subaccount_service_admins! +subaccount_admins = ["another.user@test.com"] +subaccount_service_admins = ["another.user@test.com"] -custom_idp = "sap.ids" +hana_cloud_admins = ["another.user@test.com"] +hana_system_password = "Abc12345" -hana_system_password = "Abc12345" - -cf_space_developers = ["john.doe@sap.com"] -cf_space_managers = ["john.doe@sap.com"] -cf_org_admins = ["john.doe@sap.com"] -cf_org_users = ["john.doe@sap.com"] - -event_mesh_admins = ["john.doe@sap.com"] -event_mesh_developers = ["john.doe@sap.com"] +# Don't add the user, that is executing the TF script to cf_org_admins or cf_org_users! +cf_org_admins = ["another.user@test.com"] +cf_org_users = ["another.user@test.com"] +cf_space_managers = ["another.user@test.com", "you@test.com"] +cf_space_developers = ["another.user@test.com", "you@test.com"] diff --git a/released/discovery_center/mission_4371/step1/variables.tf b/released/discovery_center/mission_4371/step1/variables.tf index b8a774ea..e344bad3 100644 --- a/released/discovery_center/mission_4371/step1/variables.tf +++ b/released/discovery_center/mission_4371/step1/variables.tf @@ -141,20 +141,22 @@ variable "target_ai_core_model" { } } -variable "cf_api_url" { - type = string -} - variable "cf_landscape_label" { - type = string + type = string + description = "In case there are multiple environments available for a subaccount, you can use this label to choose with which one you want to go. If nothing is given, we take by default the first available." + default = "" } -variable "cf_org_id" { - type = string -} -variable "subaccount_id" { - type = string +variable "cf_space_name" { + type = string + description = "Name of the Cloud Foundry space." + default = "dev" + + validation { + 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_space_developers" { @@ -218,4 +220,4 @@ variable "cf_org_name" { condition = can(regex("^.{1,255}$", var.cf_org_name)) error_message = "The Cloud Foundry org name must not be emtpy and not exceed 255 characters." } -} \ No newline at end of file +} diff --git a/released/discovery_center/mission_4371/step2/main.tf b/released/discovery_center/mission_4371/step2/main.tf index 70e8df36..a72908ab 100644 --- a/released/discovery_center/mission_4371/step2/main.tf +++ b/released/discovery_center/mission_4371/step2/main.tf @@ -2,7 +2,7 @@ # Create space using CF provider ###################################################################### resource "cloudfoundry_space" "dev" { - name = "DEV" + name = var.cf_space_name org = var.cf_org_id } @@ -14,7 +14,7 @@ resource "cloudfoundry_org_role" "organization_user" { username = each.value type = "organization_user" org = var.cf_org_id - # origin = var.origin + origin = var.origin } resource "cloudfoundry_org_role" "organization_manager" { @@ -22,23 +22,23 @@ resource "cloudfoundry_org_role" "organization_manager" { username = each.value type = "organization_manager" org = var.cf_org_id - # origin = var.origin + origin = var.origin } resource "cloudfoundry_space_role" "space_developer" { - for_each = toset(var.cf_space_developers) - username = each.value - type = "space_developer" - space = cloudfoundry_space.dev.id - # origin = var.origin + for_each = toset(var.cf_space_developers) + username = each.value + type = "space_developer" + space = cloudfoundry_space.dev.id + origin = var.origin depends_on = [cloudfoundry_org_role.organization_user, cloudfoundry_org_role.organization_manager] } resource "cloudfoundry_space_role" "space_manager" { - for_each = toset(var.cf_space_managers) - username = each.value - type = "space_manager" - space = cloudfoundry_space.dev.id - # origin = var.origin + for_each = toset(var.cf_space_managers) + username = each.value + type = "space_manager" + space = cloudfoundry_space.dev.id + origin = var.origin 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_4371/step2/output.tf b/released/discovery_center/mission_4371/step2/output.tf index ad4178cd..742f4536 100644 --- a/released/discovery_center/mission_4371/step2/output.tf +++ b/released/discovery_center/mission_4371/step2/output.tf @@ -2,10 +2,6 @@ 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 } diff --git a/released/discovery_center/mission_4371/step2/variables.tf b/released/discovery_center/mission_4371/step2/variables.tf index 909216f7..ed5d0e70 100644 --- a/released/discovery_center/mission_4371/step2/variables.tf +++ b/released/discovery_center/mission_4371/step2/variables.tf @@ -2,10 +2,6 @@ variable "cf_api_url" { type = string } -variable "cf_landscape_label" { - type = string -} - variable "cf_org_id" { type = string } @@ -14,6 +10,17 @@ variable "subaccount_id" { type = string } +variable "cf_space_name" { + type = string + description = "Name of the Cloud Foundry space." + default = "dev" + + validation { + 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_space_developers" { type = list(string) description = "CF Space developers" From 392aa896607cdb16560d91fadd9a10a95fc199b7 Mon Sep 17 00:00:00 2001 From: Rui Nogueira Date: Wed, 10 Jul 2024 12:11:02 +0000 Subject: [PATCH 14/14] remove bash files --- released/discovery_center/mission_4371/apply.sh | 14 -------------- released/discovery_center/mission_4371/destroy.sh | 12 ------------ .../mission_4371/step1/samples.tfvars | 4 ++-- 3 files changed, 2 insertions(+), 28 deletions(-) delete mode 100755 released/discovery_center/mission_4371/apply.sh delete mode 100755 released/discovery_center/mission_4371/destroy.sh diff --git a/released/discovery_center/mission_4371/apply.sh b/released/discovery_center/mission_4371/apply.sh deleted file mode 100755 index 65e4cfff..00000000 --- a/released/discovery_center/mission_4371/apply.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -cd step1 - -terraform init -terraform apply -var-file='../my_samples.tfvars' -auto-approve -terraform output > ../step2/step1vars.tfvars - -cd ../step2 - -terraform init -terraform apply -var-file=step1vars.tfvars -var-file='../my_samples.tfvars' -auto-approve - -cd .. \ No newline at end of file diff --git a/released/discovery_center/mission_4371/destroy.sh b/released/discovery_center/mission_4371/destroy.sh deleted file mode 100755 index c149b746..00000000 --- a/released/discovery_center/mission_4371/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_4371/step1/samples.tfvars b/released/discovery_center/mission_4371/step1/samples.tfvars index 31d98c90..de57e46b 100644 --- a/released/discovery_center/mission_4371/step1/samples.tfvars +++ b/released/discovery_center/mission_4371/step1/samples.tfvars @@ -15,8 +15,8 @@ custom_idp = "sap.ids" subaccount_admins = ["another.user@test.com"] subaccount_service_admins = ["another.user@test.com"] -hana_cloud_admins = ["another.user@test.com"] -hana_system_password = "Abc12345" +hana_cloud_admins = ["another.user@test.com"] +hana_system_password = "Abc12345" # Don't add the user, that is executing the TF script to cf_org_admins or cf_org_users! cf_org_admins = ["another.user@test.com"]