diff --git a/.gitignore b/.gitignore index 32b15ebb..0dbd3e85 100644 --- a/.gitignore +++ b/.gitignore @@ -178,3 +178,4 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +.DS_Store diff --git a/released/discovery_center/mission_4371/step1/README.md b/released/discovery_center/mission_4371/step1/README.md new file mode 100644 index 00000000..675f8e7c --- /dev/null +++ b/released/discovery_center/mission_4371/step1/README.md @@ -0,0 +1,53 @@ +# 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. Export environment variables BTP_USERNAME, BTP_PASSWORD, CF_USER, and CF_PASSWORD with your username and password for the custom IdP of your global account. + +2. Change the variables in the `samples.tfvars` file in the main folder to meet your requirements + + > ⚠ NOTE: You should pay attention **specifically** to the users defined in the samples.tfvars whether they already exist in your SAP BTP accounts. Otherwise you might get error messages like e.g. `Error: The user could not be found: jane.doe@test.com`. + +3. Execute the apply.sh script. + +4. Verify e.g., in BTP cockpit that a new subaccount with a integration suite, SAP Business Application Studio, CF environment instance and a CF space have been created. + + ```bash + terraform init + ``` + +5. You can check what Terraform plans to apply based on your configuration: + + ```bash + terraform plan -var-file="sample.tfvars" + ``` + +6. 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/step1/main.tf b/released/discovery_center/mission_4371/step1/main.tf new file mode 100644 index 00000000..11737739 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/main.tf @@ -0,0 +1,211 @@ +# ------------------------------------------------------------------------------------------------------ +# Setup of names in accordance to naming convention +# ------------------------------------------------------------------------------------------------------ +resource "random_uuid" "uuid" {} + +locals { + 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 +# ------------------------------------------------------------------------------------------------------ +resource "btp_subaccount" "dc_mission" { + name = var.subaccount_name + subdomain = local.subaccount_domain + region = lower(var.region) + usage = "USED_FOR_PRODUCTION" +} + +# ------------------------------------------------------------------------------------------------------ +# 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" +} + + + +# ------------------------------------------------------------------------------------------------------ +# 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 new file mode 100644 index 00000000..a06388a1 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/output.tf @@ -0,0 +1,19 @@ +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"] + description = "The Cloudfoundry API endpoint." +} + +output "cf_landscape_label" { + value = terraform_data.replacement.output + description = "The Cloudfoundry landscape label." +} + +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 new file mode 100644 index 00000000..0728b747 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/provider.tf @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------------------------------------------ +# Define the required providers for this module +# ------------------------------------------------------------------------------------------------------ +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/step1/samples.tfvars b/released/discovery_center/mission_4371/step1/samples.tfvars new file mode 100644 index 00000000..de57e46b --- /dev/null +++ b/released/discovery_center/mission_4371/step1/samples.tfvars @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------------------------------------------ +# Provider configuration +# ------------------------------------------------------------------------------------------------------ +# Your global account subdomain +globalaccount = "yourglobalaccount" +region = "us10" +subaccount_name = "SAP Discovery Center Mission 4371" +custom_idp = "sap.ids" + +# ------------------------------------------------------------------------------------------------------ +# Project specific configuration (please adapt!) +# ------------------------------------------------------------------------------------------------------ + +# 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"] + +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"] +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 new file mode 100644 index 00000000..e344bad3 --- /dev/null +++ b/released/discovery_center/mission_4371/step1/variables.tf @@ -0,0 +1,223 @@ +###################################################################### +# 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 "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." + } +} + +variable "cf_landscape_label" { + 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_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" + 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." + } +} 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..a72908ab --- /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 = var.cf_space_name + 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..742f4536 --- /dev/null +++ b/released/discovery_center/mission_4371/step2/output.tf @@ -0,0 +1,15 @@ +output "subaccount_id" { + value = var.subaccount_id +} + +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..9337283b --- /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..ed5d0e70 --- /dev/null +++ b/released/discovery_center/mission_4371/step2/variables.tf @@ -0,0 +1,74 @@ +variable "cf_api_url" { + type = string +} + +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" { + 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" +}