diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/README.md b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/README.md new file mode 100644 index 00000000..e424376d --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/README.md @@ -0,0 +1,80 @@ +# SITBLR DECEMBER 2024 - HandsOn SAP Terraform Provider for SAP BTP + +## Goal of this HandsOn 🎯 + +In this HandsOn you will learn how to use the [Terraform Provider for SAP BTP](https://registry.terraform.io/providers/SAP/cp/latest/docs) to provision and manage resources in SAP BTP. The level of the exercises is beginner. You don't need any prior knowledge about Terraform or the Terraform Provider for SAP BTP. We will guide you through the exercises step by step. + +## Prerequisites 📝 + +Make sure that the following prerequisites are met: + +- You have an SAP BTP Trial Account. If you don't have one yet, you can get one [here](https://developers.sap.com/tutorials/hcp-create-trial-account.html). +- Make sure that your SAP Universal ID is configured correctly. You can find the instructions in [SAP Note 3085908](https://me.sap.com/notes/3085908). +- The Terraform provider does not support SSO or 2FA. Make sure that these options are not enforced for your account. + + +## Tools 🛠️ + +To execute the exercises you have the following options concerning the required tools installed: + +In general you must clone this GitHub repository. You must have the Git client installed on your machine. You can find the installation instructions [here](https://git-scm.com/downloads). + +You can then clone the repository via the following command: + +```bash +git clone https://github.com/SAP-samples/btp-terraform-samples.git +``` + +you find the exercises in the folder `released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises`. + + +You can install the required tools locally on your machine. The following tools are required: + +- [Terraform CLI](https://developer.hashicorp.com/terraform/install?product_intent=terraform) +- An editor of your choice. We recommend [Visual Studio Code](https://code.visualstudio.com/Download) with the [Terraform extension](https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform). + + +## Exporting environment variables + +The last step in the setup is the export of the environment variables that are required to authenticate against the Terraform provider for SAP BTP. Fo that export the following environment variables: + +- Windows: + + ```pwsh + $env:BTP_USERNAME= + $env:BTP_PASSWORD='' + ``` + +- Linux/MacOS/GitHub Codespaces: + + ```bash + export BTP_USERNAME= + export BTP_PASSWORD='' + ``` + +Validate that the values are set via: + +- Windows: `$env:BTP_USERNAME` and `$env:BTP_PASSWORD` +- Linux/MacOS/GitHub Codeapses: `echo $BTP_USERNAME` and `echo $BTP_PASSWORD` + + +## Summary + +You've now prepared your development environment and have all information to finally start using Terraform provider for SAP BTP. + + + +## Exercises 📚 + +In this HandsOn we want to make you familiar with the Terraform Provider for SAP BTP. We will use the provider to provision and manage resources in SAP BTP. To achieve this we will walk through the following steps: + +1. [Exercise 1 - Configure the Terraform Provider for SAP BTP](exercises/EXERCISE1/README.md) +1. [Exercise 2 - Setup of a subaccount](exercises/EXERCISE2/README.md) +1. [Exercise 3 - Assign entitlement,Subscription and its role assignments to a subaccount](exercises/EXERCISE3/README.md) +1. [Exercise 4 - Setup a Cloud Foundry environment](exercises/EXERCISE4/README.md) +1. [Exercise 5 - Create a CloudFoundry Space](exercises/EXERCISE5/README.md) +1. [Exercise 6 - Cleanup](exercises/EXERCISE6/README.md) + + + + diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-creation.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-creation.png new file mode 100644 index 00000000..47028144 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-creation.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-screen.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-screen.png new file mode 100644 index 00000000..1c6d4376 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-screen.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-setup-process.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-setup-process.png new file mode 100644 index 00000000..af3d8b69 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/codespace-setup-process.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/devcontainer-selection.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/devcontainer-selection.png new file mode 100644 index 00000000..a8ed589e Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/devcontainer-selection.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/repo-terraform-samples.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/repo-terraform-samples.png new file mode 100644 index 00000000..9c4afe08 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/assets/repo-terraform-samples.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/README.md b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/README.md new file mode 100644 index 00000000..19c21979 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/README.md @@ -0,0 +1,71 @@ +# Exercise 1 - Configure the Terraform Provider for SAP BTP + +## Goal of this Exercise 🎯 + +The goal of this exercise is to configure the Terraform provider for SAP BTP. In addition we will create a basic setup of the file structure to implement the Terraform configuration. + +## Step 1: Create a new directory + +To make use of Terraform you must create several configuration files using the [Terraform configuration language](https://developer.hashicorp.com/terraform/language). Create a new directory named `my-tf-handson` under the folder `SITBLR2024`. + +Terraform expects a specific file layout for its configurations. Create the following empty files in the directory `my-tf-handson`: + +- `main.tf` - this file will contain the main configuration of the Terraform setup +- `provider.tf` - this file will contain the provider configuration +- `variables.tf` - this file will contain the variables to be used in the Terraform configuration +- `outputs.tf` - this file will contain the outputs of the Terraform configuration +- `terraform.tfvars` - this file will contain your specific variable values + +## Step 2: Create the provider configuration + +Next we must configure the Terraform provider for SAP BTP. This is done by adding the provider configuration to the `provider.tf` file. You find the information about the required parameters in the documentation of the [Terraform Provider for SAP BTP](https://registry.terraform.io/providers/SAP/btp/latest/docs). + +Open the file `provider.tf` and add the following content: + +```terraform +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.8.0" + } + } +} + +provider "btp" { + globalaccount = var.globalaccount +} +``` + +What have we done? First we defined which provider we want to use and which version of the provider we want to use. In this case we want to use the provider `sap/btp` in version `1.8.0` (including potential patch versions). Then we defined the provider configuration. In this case we only need to provide the `globalaccount` parameter where we reference a variable. We will define this variable in the next step. + + > [!NOTE] + > We do not need any authentication information in this file. We provided the authentication information via environment variables. + +Next we must add the required variables to the `variables.tf` file. Open the file `variables.tf` and add the following content: + +```terraform +variable "globalaccount" { + type = string + description = "The subdomain of the SAP BTP global account." +} +``` + +We have now defined the variable `globalaccount` which is required for the provider configuration. We will provide the value for this variable via the `terraform.tfvars` file. Open +the file `terraform.tfvars` and add the following content: + +```terraform +globalaccount = "" +``` + +The SAP BTP Global Account Subdomain can be found in the SAP BTP Cockpit as shown below +SAP BTP Global Account Subdomain + + > [!NOTE] + > We are using here a naming convention of Terraform to define the variable values. The file `terraform.tfvars` is used to define the variable values. The file is not checked into the source code repository. This is important to keep sensitive information out of the source code repository. When you run Terraform, it will automatically load the variable values from this file. + +## Summary + +You've now created a basic setup of the Terraform provider including its configuration. + +Continue to - [Exercise 2 - Setup of a subaccount](../EXERCISE2/README.md). diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/main.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/main.tf new file mode 100644 index 00000000..e69de29b diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/outputs.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/outputs.tf new file mode 100644 index 00000000..e69de29b diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/provider.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/provider.tf new file mode 100644 index 00000000..96cf1596 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/provider.tf @@ -0,0 +1,16 @@ + +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.8.0" + } + } + +} + +# Please checkout documentation on how best to authenticate against SAP BTP +# via the Terraform provider for SAP BTP +provider "btp" { + globalaccount = var.globalaccount +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/terraform.tfvars-sample b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/terraform.tfvars-sample new file mode 100644 index 00000000..c281dae5 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/terraform.tfvars-sample @@ -0,0 +1 @@ +globalaccount = "" diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/variables.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/variables.tf new file mode 100644 index 00000000..4658db07 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/SOLUTION_EX1/variables.tf @@ -0,0 +1,7 @@ +### +# Provider configuration +### +variable "globalaccount" { + type = string + description = "The subdomain of the SAP BTP global account." +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/assets/trial-account.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/assets/trial-account.png new file mode 100644 index 00000000..c0ddfef4 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE1/assets/trial-account.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/README.md b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/README.md new file mode 100644 index 00000000..6a56eaf2 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/README.md @@ -0,0 +1,245 @@ +# Exercise 2 - Setup of a subaccount + +## Goal of this Exercise 🎯 + +The goal of this exercise is to setup a *subaccount* in the SAP BTP using the Terraform provider. Besides that we will learn how to work with `variables` and `outputs` in Terraform. As a cherry on top we will also learn how to validate user input. + +## Create the subaccount configuration + +### Step 1: Input variables + +We want to create a subaccount that follows a specific naming convention and has additional information about the development project like the cost center displayed via labels. To achieve this we will use input variables in Terraform. + +We want to have the following input when creating a subaccount as base information: + +- *region* - The region where the subaccount should be created. We will default this to `us10` for the purpose of this exercise. +- *project name* - The name of the project. We want to validate the input to follow a specific naming convention. +- *stage* - The stage of the project. We want to validate the input to be either `DEV`, `TST` or `PRD`. +- *cost center* - The cost center of the project. We want to validate the input to be a valid number. +- *organization name* - The organization where the subaccount should be created. We want to validate this against several fixed values. + +#### Input variable *region* + +Open the file `variables.tf` and add the following code to define the input variable for *region*: + +```terraform +variable "region" { + type = string + description = "The region where the project account shall be created in." + default = "us10" +} +``` + +As you can see a variable has a name (`region`) so that we can address it from the Terraform configuration. It also has a type (`string`) and a description. The `default` value is optional and will be used if no value is provided when running Terraform. + +#### Input variable *project_name* + +Add the following code to define the *project name* the `variables.tf` file: + +```terraform +variable "project_name" { + type = string + description = "The subaccount name." + default = "proj-1234" + + validation { + condition = can(regex("^[a-zA-Z0-9_\\-]{1,200}", var.project_name)) + error_message = "Provide a valid project name." + } +} +``` + +This variable contains an additional `validation` block. This block contains a `condition` that checks if the input matches the regular expression. If the condition is not met, the `error_message` will be displayed. We use the [`can` expression](https://developer.hashicorp.com/terraform/language/functions/can) to check if the input is valid when compared to a specific regular expression leveraging the [`regex` function](https://developer.hashicorp.com/terraform/language/functions/regex). + +As we will later construct the subdomain based on the project name, change the default value `proj-1234` to something unique by using your name, birthday or something similar. + +#### Input variable *stage* + +Let us continue with the *stage* variable that should be validated against some fixed values. To do so add the following code to the `variables.tf` file: + +```terraform +variable "stage" { + type = string + description = "The stage/tier the account will be used for." + default = "DEV" + + validation { + condition = contains(["DEV", "TST", "PRD"], var.stage) + error_message = "Select a valid stage for the project account." + } +} +``` + +You can see a different type of validation here. We use the [`contains` function](https://developer.hashicorp.com/terraform/language/functions/contains) to check if the input is part of the list of valid stages. + + +#### Input variable *costcenter* + +Let us move on to the *cost center* variable. Add the following code to the `variables.tf` file: + +```terraform +variable "costcenter" { + type = string + description = "The cost center the account will be billed to." + default = "1234567890" + + validation { + condition = can(regex("^[0-9]{10}", var.costcenter)) + error_message = "Provide a valid cost center." + } +} +``` + +Nothing new here that we have not seen before. We use the `can` expression to check if the input is valid when compared to a specific regular expression leveraging the `regex` function. + +> [!NOTE] +> You can also use functions inside of functions to express more complex conditions such as [concat function](https://developer.hashicorp.com/terraform/language/functions/concat) to combine multiple lists into one list and then use the `contains` function to check if the input is part of that list. + +#### Input variable *org_name* + +And last but not least we want to add and validate the *organization name* variable. Add the following code to the `variables.tf` file: + +```terraform +variable "org_name" { + type = string + description = "Defines to which organization the project account shall belong to." + default = "B2C" +} +``` + +As we have all variables in place, you should save the changes now. + +> [!NOTE] +> As you can see you have a lot of possibilities to validate the user input in Terraform in this way ensure that the input is correct and meets your corporate requirements. + +### Step 2: Local values + +Now we want to leverage the input variables to create a subaccount name that follows a specific naming convention. Here are the conditions: + +- The subaccount name shall follow the pattern ` | : CF - `. +- The subaccount domain shall follow the pattern `--`. We must ensure that there are no spaces in the domain name and all letters are lowercase. + +To achieve this we use [local values](https://developer.hashicorp.com/terraform/language/values/locals) to construct the names. Open the file `main.tf` and add the following code to define the local values: + +```terraform +locals { + project_subaccount_name = "${var.org_name} | ${var.project_name}: CF - ${var.stage}" + project_subaccount_domain = lower(replace("${var.org_name}-${var.project_name}-${var.stage}", " ", "")) +} +``` + +For the subaccount name we referenced the values of the variables and combined them to a string using the `${}` syntax. For the subaccount domain we used the [`replace` function](https://developer.hashicorp.com/terraform/language/functions/replace) to remove spaces from the domain name and the [`lower` function](https://developer.hashicorp.com/terraform/language/functions/lower) to bring all letter in lowercase. + +As we have all local values in place, you should save the changes now. + +### Step 3: The subaccount configuration + +As all bits and pieces are in place we can now create the subaccount configuration. Besides the name and domain we also want to add labels to the subaccount to display the stage and cost center. In addition we want to set the usage of the subaccount to `NOT_USED_FOR_PRODUCTION`. + +Add the following code in the `main.tf` file to define the subaccount configuration: + +```terraform +resource "btp_subaccount" "project" { + name = local.project_subaccount_name + subdomain = local.project_subaccount_domain + region = lower(var.region) + labels = { + "stage" = ["${var.stage}"], + "costcenter" = ["${var.costcenter}"] + } +} +``` + +We used the resource [`btp_subaccount`](https://registry.terraform.io/providers/SAP/btp/latest/docs/resources/subaccount) to create the subaccount. We referenced the local values to set the name and domain. We added labels to the subaccount to display the stage and cost center. + +As we have the configuration in place, you should save the changes now. + +### Step 4: Output values + +Before we can finally apply the Terraform configuration we want to add an output value to display the subaccount name id. Add the following code to the `outputs.tf` file to define the output value: + +```terraform +output "subaccount_id" { + value = btp_subaccount.project.id + description = "The ID of the project subaccount." +} + +output "subaccount_name" { + value = btp_subaccount.project.name + description = "The name of the project subaccount." +} +``` + +These output values will display the ID and name of the created subaccount after the Terraform configuration has been successfully applied. + +As we have all output values in place, you should save the changes now. + +### Step 5: Apply the Terraform configuration + +Now the moment has come to apply the Terraform configuration for the first time. Open a terminal window and execute the following commands: + +1. Initialize the Terraform configuration to download the required provider: + + ```bash + terraform init + ``` + + You should see an output similar to the following: + + terraform init output + +> [!NOTE] +> Check your files. You should have a new folder called `.terraform` as well as new file called `.terraform.lock.hcl` in your directory. This means that the Terraform provider has been successfully downloaded and the version constraints are stored for your setup. + +terraform folder after init + +2. Plan the Terraform configuration to see what will be created: + + ```bash + terraform plan + ``` + + You should see an output similar to the following: + + terraform plan output + +3. Apply the Terraform configuration to create the subaccount: + + ```bash + terraform apply + ``` + + You will be prompted to confirm the creation of the subaccount. Type `yes` and press `Enter` to continue. You should see an output similar to the following: + + terraform apply output + + terraform apply output after execution + +After the application you will find a new file called `terraform.tfstate` in your directory. This file contains the [state](https://developer.hashicorp.com/terraform/language/state) of the Terraform configuration and is used to keep track of the resources that have been created: + +terraform state in the file system + +> [!IMPORTANT] +> In real life you would not store this file locally but use a [remote backend](https://developer.hashicorp.com/terraform/language/backend) that is capable of storing the state in a secure and consistent way. For the purpose of this exercise we will use the local backend. + +> [!NOTE] +> In case you are getting an error that the subdomain already exists, you need change the project name in the `variables.tf` file. + +You can also check that everything is in place via the SAP BTP cockpit. You should see a new subaccount that comprises our configuration: + +subaccount in SAP BTP + +## Additional information + +Here you find additional information on the used Terraform features and functions: + +- Terraform documentation on [input variables](https://developer.hashicorp.com/terraform/language/values/variables) +- Terraform documentation on [validation](https://developer.hashicorp.com/terraform/language/expressions/custom-conditions#input-variable-validation) +- Terraform documentation on [output values](https://developer.hashicorp.com/terraform/language/values/outputs) +- Terraform documentation on [local values](https://developer.hashicorp.com/terraform/language/values/locals) + +## Summary + +You've now successfully created a subaccount. + +Continue to - [Exercise 3 - Assign entitlements to a subaccount](../EXERCISE3/README.md). diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/main.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/main.tf new file mode 100644 index 00000000..a80d4665 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/main.tf @@ -0,0 +1,20 @@ +### +# Setup of names in accordance to the company's naming conventions +### +locals { + project_subaccount_name = "${var.org_name} | ${var.project_name}: CF - ${var.stage}" + project_subaccount_domain = lower(replace("${var.org_name}-${var.project_name}-${var.stage}", " ", "-")) +} + +### +# Creation of subaccount +### +resource "btp_subaccount" "project" { + name = local.project_subaccount_name + subdomain = local.project_subaccount_domain + region = lower(var.region) + labels = { + "stage" = ["${var.stage}"], + "costcenter" = ["${var.costcenter}"] + } +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/outputs.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/outputs.tf new file mode 100644 index 00000000..9cc0c349 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/outputs.tf @@ -0,0 +1,9 @@ +output "subaccount_id" { + value = btp_subaccount.project.id + description = "The ID of the project subaccount." +} + +output "subaccount_name" { + value = btp_subaccount.project.name + description = "The name of the project subaccount." +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/provider.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/provider.tf new file mode 100644 index 00000000..96cf1596 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/provider.tf @@ -0,0 +1,16 @@ + +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.8.0" + } + } + +} + +# Please checkout documentation on how best to authenticate against SAP BTP +# via the Terraform provider for SAP BTP +provider "btp" { + globalaccount = var.globalaccount +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/terraform.tfvars-sample b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/terraform.tfvars-sample new file mode 100644 index 00000000..c281dae5 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/terraform.tfvars-sample @@ -0,0 +1 @@ +globalaccount = "" diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/variables.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/variables.tf new file mode 100644 index 00000000..fd3e3a5a --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/SOLUTION_EX2/variables.tf @@ -0,0 +1,55 @@ +### +# Provider configuration +### +variable "globalaccount" { + type = string + description = "The subdomain of the SAP BTP global account." +} + +variable "region" { + type = string + description = "The region where the project account shall be created in." + default = "us10" +} + +### +# Subaccount setup +### +variable "project_name" { + type = string + description = "The subaccount name." + default = "proj-1234" + + validation { + condition = can(regex("^[a-zA-Z0-9_\\-]{1,200}", var.project_name)) + error_message = "Provide a valid project name." + } +} + +variable "stage" { + type = string + description = "The stage/tier the account will be used for." + default = "DEV" + + validation { + condition = contains(["DEV", "TST", "PRD"], var.stage) + error_message = "Select a valid stage for the project account." + } +} + +variable "costcenter" { + type = string + description = "The cost center the account will be billed to." + default = "1234567890" + + validation { + condition = can(regex("^[0-9]{10}", var.costcenter)) + error_message = "Provide a valid cost center." + } +} + +variable "org_name" { + type = string + description = "Defines to which organisation the project account shall belong to." + default = "B2C" +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_1.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_1.png new file mode 100644 index 00000000..98bba7fd Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_1.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_1b.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_1b.png new file mode 100644 index 00000000..76450ef4 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_1b.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_2.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_2.png new file mode 100644 index 00000000..a17766b9 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_2.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_3a.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_3a.png new file mode 100644 index 00000000..8955388e Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_3a.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_3b.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_3b.png new file mode 100644 index 00000000..1e42dca0 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_3b.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_4.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_4.png new file mode 100644 index 00000000..502ec645 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_4.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_5.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_5.png new file mode 100644 index 00000000..e78aa915 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE2/assets/ex2_5.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/README.md b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/README.md new file mode 100644 index 00000000..88c4260f --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/README.md @@ -0,0 +1,128 @@ +# Exercise 3 - Assign entitlement,Subscription and its role assignments to a subaccount + +## Goal of this Exercise 🎯 + +In this exercise, you will learn how add an entitlement to a subaccount using Terraform. + +## Entitle the subaccount with Business Application Stuido (BAS) + +## Step 1: Configure BAS + +Our goal is to configure Business Application Studio (BAS) for the subaccount by defining the necessary resources for entitlement, subscription, and role assignments. + +We will define the variables in the `variable.tf` file. Open the `variable.tf` file and add the following code. + + +```terraform +variable "bas_admins" { + type = list(string) + description = "List of users to assign the Administrator role." + +} +variable "bas_developers" { + type = list(string) + description = "List of users to assign the Developer role." +} +variable "bas_service_name" { + type = string + description = "Service name for Business Application Studio." + default = "sapappstudio" + +} +variable "bas_plan" { + type = string + description = "Plan name for Business Application Studio." + default = "standard" +} +``` + +We define a complex variable type, which is a [list](https://developer.hashicorp.com/terraform/language/expressions/types#lists-tuples) of [objects](https://developer.hashicorp.com/terraform/language/expressions/types#maps-objects). Each object has three attributes: `name`, `plan`, and `amount`. The `name` and `plan` attributes are strings, and the `amount` attribute is a number. We define a default value for the variable, which is an empty list.We will provide values for this parameter via the file `terraform.tfvars` in the next step. Save the changes. + +## Step 2: Add the variable to the tfvars file + +Now we need to specify the entitlements we want to create to the `terraform.tfvars` file. + +We want to add the following entitlements to the subaccount: + +- `sapappstudiotrial` application with the `trial` plan + +Open the `terraform.tfvars` file and add the following code: + +```terraform +bas_service_name = "sapappstudiotrial" +bas_plan = "trial" +bas_admins = ["admin1@example.com", "admin2@example.com"] +bas_developers = ["dev1@example.com", "dev2@example.com"] +``` + +## Step 3: Add the entitlements configuration + +As we have the variable and the values for the `BAS` in place, we can now add the configuration to assign the entitlement to the subaccount. We use the resource [btp_subaccount_entitlement](https://registry.terraform.io/providers/SAP/btp/latest/docs/resources/subaccount_entitlement) to achieve this. Open the `main.tf` file and add the following code: + +```terraform +resource "btp_subaccount_entitlement" "bas" { + subaccount_id = btp_subaccount.project.id + service_name = var.bas_service_name + plan_name = var.bas_plan +} + +resource "btp_subaccount_subscription" "bas" { + subaccount_id = btp_subaccount.project.id + app_name = var.bas_service_name + plan_name = var.bas_plan + depends_on = [btp_subaccount_entitlement.bas] +} + +resource "btp_subaccount_role_collection_assignment" "bas_admin" { + for_each = toset(var.bas_admins) + subaccount_id = btp_subaccount.project.id + role_collection_name = "Business_Application_Studio_Administrator" + user_name = each.value + depends_on = [btp_subaccount_subscription.bas] +} + +resource "btp_subaccount_role_collection_assignment" "bas_developer" { + for_each = toset(var.bas_developers) + subaccount_id = btp_subaccount.project.id + role_collection_name = "Business_Application_Studio_Developer" + user_name = each.value + depends_on = [btp_subaccount_subscription.bas] +} +``` + +We iterate through the list of entitlement and create a resource for `BAS`. We use the[`for_each` meta-argument](https://developer.hashicorp.com/terraform/language/meta-arguments/for_each) to achieve this. The `for_each` argument works on a map, so we must transform our list of users into a map leveraging Terraform's automatic type conversion via the [`for` expression](https://developer.hashicorp.com/terraform/language/expressions/for#result-types) for setting up the map. As for the subaccount administrators we access the value of the current iteration via `each.value` and reference the corresponding attributes of the object. The `subaccount_id` is set to the id of the subaccount we created in the previous exercise. Save the changes. + +## Step 4: Apply the changes + +Now we can apply the changes to our subaccount. Run the following commands: + +> [!NOTE] +> As we did not change the configuration of the provider or add any Terraform [modules](https://developer.hashicorp.com/terraform/language/modules), we do not need to run `terraform init` again. + +1. Plan the Terraform configuration to see what will be created: + + ```bash + terraform plan + ``` + + You should see the following output: + + terraform plan output for entitlements + +2. Apply the Terraform configuration to add the entitlements: + + ```bash + terraform apply + ``` + + You will be prompted to confirm the creation of the entitlements. Type `yes` and press `Enter` to continue. You should see the following output: + + terraform apply output for entitlements + +You can also check that everything is in place via the SAP BTP cockpit. You should see the assigned entitlements in the subaccount. + +## Summary + +You've now successfully entitled services and applications to the subaccount. + +Continue to - [Exercise 4 - Setup a Cloud Foundry environment](../EXERCISE4/README.md). diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/main.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/main.tf new file mode 100644 index 00000000..ecf25620 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/main.tf @@ -0,0 +1,55 @@ +### +# Setup of names in accordance to the company's naming conventions +### +locals { + project_subaccount_name = "${var.org_name} | ${var.project_name}: CF - ${var.stage}" + project_subaccount_domain = lower(replace("${var.org_name}-${var.project_name}-${var.stage}", " ", "-")) + project_subaccount_cf_org = replace("${var.org_name}_${lower(var.project_name)}-${lower(var.stage)}", " ", "_") +} + +### +# Creation of subaccount +### +resource "btp_subaccount" "project" { + name = local.project_subaccount_name + subdomain = local.project_subaccount_domain + region = lower(var.region) + labels = { + "stage" = ["${var.stage}"], + "costcenter" = ["${var.costcenter}"] + } + usage = "NOT_USED_FOR_PRODUCTION" +} + +### +# Entitlement Subscription and Role Assignment for BAS +### + +resource "btp_subaccount_entitlement" "bas" { + subaccount_id = btp_subaccount.project.id + service_name = var.bas_service_name + plan_name = var.bas_plan +} + +resource "btp_subaccount_subscription" "bas" { + subaccount_id = btp_subaccount.project.id + app_name = var.bas_service_name + plan_name = var.bas_plan + depends_on = [btp_subaccount_entitlement.bas] +} + +resource "btp_subaccount_role_collection_assignment" "bas_admin" { + for_each = toset(var.bas_admins) + subaccount_id = btp_subaccount.project.id + role_collection_name = "Business_Application_Studio_Administrator" + user_name = each.value + depends_on = [btp_subaccount_subscription.bas] +} + +resource "btp_subaccount_role_collection_assignment" "bas_developer" { + for_each = toset(var.bas_developers) + subaccount_id = btp_subaccount.project.id + role_collection_name = "Business_Application_Studio_Developer" + user_name = each.value + depends_on = [btp_subaccount_subscription.bas] +} \ No newline at end of file diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/outputs.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/outputs.tf new file mode 100644 index 00000000..9cc0c349 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/outputs.tf @@ -0,0 +1,9 @@ +output "subaccount_id" { + value = btp_subaccount.project.id + description = "The ID of the project subaccount." +} + +output "subaccount_name" { + value = btp_subaccount.project.name + description = "The name of the project subaccount." +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/provider.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/provider.tf new file mode 100644 index 00000000..96cf1596 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/provider.tf @@ -0,0 +1,16 @@ + +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.8.0" + } + } + +} + +# Please checkout documentation on how best to authenticate against SAP BTP +# via the Terraform provider for SAP BTP +provider "btp" { + globalaccount = var.globalaccount +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/terraform.tfvars-sample b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/terraform.tfvars-sample new file mode 100644 index 00000000..50182288 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/terraform.tfvars-sample @@ -0,0 +1,5 @@ +globalaccount = "" +bas_service_name = "sapappstudiotrial" +bas_plan = "trial" +bas_admins = ["admin1@example.com", "admin2@example.com"] +bas_developers = ["dev1@example.com", "dev2@example.com"] \ No newline at end of file diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/variables.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/variables.tf new file mode 100644 index 00000000..96e06fd2 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/SOLUTION_EX3/variables.tf @@ -0,0 +1,91 @@ +### +# Provider configuration +### +variable "globalaccount" { + type = string + description = "The subdomain of the SAP BTP global account." +} + +variable "region" { + type = string + description = "The region where the project account shall be created in." + default = "us10" +} + +### +# Subaccount setup +### +variable "project_name" { + type = string + description = "The subaccount name." + default = "proj-1234" + + validation { + condition = can(regex("^[a-zA-Z0-9_\\-]{1,200}", var.project_name)) + error_message = "Provide a valid project name." + } +} + +variable "stage" { + type = string + description = "The stage/tier the account will be used for." + default = "DEV" + + validation { + condition = contains(["DEV", "TST", "PRD"], var.stage) + error_message = "Select a valid stage for the project account." + } +} + +variable "costcenter" { + type = string + description = "The cost center the account will be billed to." + default = "1234567890" + + validation { + condition = can(regex("^[0-9]{10}", var.costcenter)) + error_message = "Provide a valid cost center." + } +} + +variable "org_name" { + type = string + description = "Defines to which organisation the project account shall belong to." + default = "B2C" + + validation { + condition = contains(concat( + // Cross Development + ["B2B", "B2C", "ECOMMERCE"], + // Internal IT + ["PLATFORMDEV", "INTIT"], + // Financial Services + ["FSIT"], + ), var.org_name) + error_message = "Please select a valid org name for the project account." + } +} + +### +# Entitlement for BAS +### +variable "bas_admins" { + type = list(string) + description = "List of users to assign the Administrator role." + +} +variable "bas_developers" { + type = list(string) + description = "List of users to assign the Developer role." +} +variable "bas_service_name" { + type = string + description = "Service name for Business Application Studio." + default = "sapappstudio" + +} +variable "bas_plan" { + type = string + description = "Plan name for Business Application Studio." + default = "standard" +} \ No newline at end of file diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex3_1.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex3_1.png new file mode 100644 index 00000000..0d25e958 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex3_1.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex3_2.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex3_2.png new file mode 100644 index 00000000..26e46538 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex3_2.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex4_1.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex4_1.png new file mode 100644 index 00000000..0d06e682 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex4_1.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex4_2.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex4_2.png new file mode 100644 index 00000000..0f2f83c7 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE3/assets/ex4_2.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/README.md b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/README.md new file mode 100644 index 00000000..3459ac0e --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/README.md @@ -0,0 +1,90 @@ +# Exercise 4 - Setup a Cloud Foundry environment + +## Goal of this Exercise 🎯 + +In this section, we will create a Cloud Foundry environment in the subaccount using Terraform.We will define the necessary resources directly in the Terraform configuration. This approach allows us to maintain a simple structure while meeting the requirements. + +## Creation of a Cloud Foundry environment + +The Cloud Foundry Application Runtime service needs to be entitled to the subaccount. To achieve this, add the following resource to your Terraform configuration: + +### Step 1: Add the resources to the Terraform configuration for cloudfoundry setup + +First we need to add one more local variable in the `main.tf` file. Open the `main.tf` file and add the following code to the `locals` block: + +```terraform +project_subaccount_cf_org = replace("${var.org_name}_${lower(var.project_name)}-${lower(var.stage)}", " ", "_") +``` +We will define the variables in the `variable.tf` file. Open the `variable.tf` file and add the following code. + + +```terraform +variable "cf_landscape_label" { + type = string + description = "The region where the project account shall be created in." + default = "cf-us10-001" +} +``` + +Then add the following code to the `main.tf` + +```terraform +resource "btp_subaccount_entitlement" "cf_application_runtime" { + subaccount_id = btp_subaccount.project.id + service_name = "APPLICATION_RUNTIME" + plan_name = "MEMORY" +} + +resource "btp_subaccount_environment_instance" "cloudfoundry" { + depends_on = [btp_subaccount_entitlement.cf_application_runtime] + subaccount_id = btp_subaccount.project.id + name = local.project_subaccount_cf_org + landscape_label = var.cf_landscape_label + environment_type = "cloudfoundry" + service_name = "cloudfoundry" + plan_name = "trial" + parameters = jsonencode({ + instance_name = local.project_subaccount_cf_org + }) + timeouts = { + create = "1h" + update = "35m" + delete = "30m" + } +} +``` + +### Step 2: Adjust the output variables + +As we are using the output variables, we need to adjust the output variables in the `outputs.tf` file. Open the `outputs.tf` file and add the following code: + +```terraform +output "cloudfoundry_org_name" { + value = local.project_subaccount_cf_org + description = "The name of the cloudfoundry org connected to the project account." +} +``` +### Step 3: Apply the changes + +1. Plan the Terraform configuration to see what will be created: + + ```bash + terraform plan + ``` + + The output should look like this: + + executing terraform plan with cloud foundry + +2. Apply the Terraform configuration to create the environment: + + ```bash + terraform apply + ``` + + You will be prompted to confirm the creation of the environment. Type `yes` and press `Enter` to continue. +## Summary + +You've now successfully created a Cloud Foundry environment instance as well as a Cloud Foundry space in SAP BTP. + +Continue to - [Exercise 5 - Create a CloudFoundry Space](../EXERCISE5/README.md). \ No newline at end of file diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/main.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/main.tf new file mode 100644 index 00000000..d3bd5d5b --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/main.tf @@ -0,0 +1,86 @@ +### +# Setup of names in accordance to the company's naming conventions +### +locals { + project_subaccount_name = "${var.org_name} | ${var.project_name}: CF - ${var.stage}" + project_subaccount_domain = lower(replace("${var.org_name}-${var.project_name}-${var.stage}", " ", "-")) + project_subaccount_cf_org = replace("${var.org_name}_${lower(var.project_name)}-${lower(var.stage)}", " ", "_") +} + +### +# Creation of subaccount +### +resource "btp_subaccount" "project" { + name = local.project_subaccount_name + subdomain = local.project_subaccount_domain + region = lower(var.region) + labels = { + "stage" = ["${var.stage}"], + "costcenter" = ["${var.costcenter}"] + } +} + + +### +# Creation of Cloud Foundry environment via module +### +resource "btp_subaccount_entitlement" "cf_application_runtime" { + subaccount_id = btp_subaccount.project.id + service_name = "APPLICATION_RUNTIME" + plan_name = "MEMORY" +} + +resource "btp_subaccount_environment_instance" "cloudfoundry" { + depends_on = [btp_subaccount_entitlement.cf_application_runtime] + subaccount_id = btp_subaccount.project.id + name = local.project_subaccount_cf_org + landscape_label = var.cf_landscape_label + environment_type = "cloudfoundry" + service_name = "cloudfoundry" + plan_name = "trial" + parameters = jsonencode({ + instance_name = local.project_subaccount_cf_org + memory = 1024 + }) + timeouts = { + create = "1h" + update = "35m" + delete = "30m" + } +} + +resource "cloudfoundry_org_role" "my_role" { + for_each = var.cf_org_user + username = each.value + type = "organization_user" + org = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +resource "cloudfoundry_space" "space" { + name = var.cf_space_name + org = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +resource "cloudfoundry_space_role" "cf_space_managers" { + for_each = toset(var.cf_space_managers) + username = each.value + type = "space_manager" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} + +resource "cloudfoundry_space_role" "cf_space_developers" { + for_each = toset(var.cf_space_developers) + username = each.value + type = "space_developer" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} + +resource "cloudfoundry_space_role" "cf_space_auditors" { + for_each = toset(var.cf_space_auditors) + username = each.value + type = "space_auditor" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/outputs.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/outputs.tf new file mode 100644 index 00000000..4352f77b --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/outputs.tf @@ -0,0 +1,14 @@ +output "subaccount_id" { + value = btp_subaccount.project.id + description = "The ID of the project subaccount." +} + +output "subaccount_name" { + value = btp_subaccount.project.name + description = "The name of the project subaccount." +} + +output "cloudfoundry_org_name" { + value = local.project_subaccount_cf_org + description = "The name of the cloudfoundry org connected to the project account." +} \ No newline at end of file diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/provider.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/provider.tf new file mode 100644 index 00000000..58cc5158 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/provider.tf @@ -0,0 +1,24 @@ + +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.8.0" + } + cloudfoundry = { + source = "cloudfoundry/cloudfoundry" + version = "~> 1.1.0" + } + } + +} + +# Please checkout documentation on how best to authenticate against SAP BTP +# via the Terraform provider for SAP BTP +provider "btp" { + globalaccount = var.globalaccount +} + +provider "cloudfoundry" { + api_url = "https://api.cf.${var.region}-001.hana.ondemand.com" +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/terraform.tfvars-sample b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/terraform.tfvars-sample new file mode 100644 index 00000000..f6ef2f0a --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/terraform.tfvars-sample @@ -0,0 +1,9 @@ +globalaccount = "" + +region = "us10" + +costcenter = "" + +bas_plan_name = "trial" +bas_admins = ["john.doe@test.com"] +bas_developers = ["john.doe@test.com"] diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/variables.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/variables.tf new file mode 100644 index 00000000..c5a38474 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/SOLUTION_EX4/variables.tf @@ -0,0 +1,130 @@ +### +# Provider configuration +### +variable "globalaccount" { + type = string + description = "The subdomain of the SAP BTP global account." +} + +variable "region" { + type = string + description = "The region where the project account shall be created in." + default = "us10" +} + +### +# Subaccount setup +### +variable "project_name" { + type = string + description = "The subaccount name." + default = "proj-1234" + + validation { + condition = can(regex("^[a-zA-Z0-9_\\-]{1,200}", var.project_name)) + error_message = "Provide a valid project name." + } +} + +variable "stage" { + type = string + description = "The stage/tier the account will be used for." + default = "DEV" + + validation { + condition = contains(["DEV", "TST", "PRD"], var.stage) + error_message = "Select a valid stage for the project account." + } +} + +variable "costcenter" { + type = string + description = "The cost center the account will be billed to." + default = "1234567890" + + validation { + condition = can(regex("^[0-9]{10}", var.costcenter)) + error_message = "Provide a valid cost center." + } +} + +variable "org_name" { + type = string + description = "Defines to which organisation the project account shall belong to." + default = "B2C" + + validation { + condition = contains(concat( + // Cross Development + ["B2B", "B2C", "ECOMMERCE"], + // Internal IT + ["PLATFORMDEV", "INTIT"], + // Financial Services + ["FSIT"], + ), var.org_name) + error_message = "Please select a valid org name for the project account." + } +} + +variable "bas_plan_name" { + description = "BAS plan" + type = string + default = "free" +} + +variable "bas_developers" { + description = "BAS developers" + type = list(string) + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "bas_admins" { + description = "BAS Admininstrators" + type = list(string) + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +### +# Cloud Foundry space setup +### +variable "cf_space_name" { + type = string + description = "The name of the Cloud Foundry space." + default = "dev" +} + +variable "cf_landscape_label" { + type = string + description = "The region where the project account shall be created in." + default = "cf-us10-001" +} + +variable "cf_org_name" { + type = string + description = "The name for the Cloud Foundry Org." + default = "" +} + +variable "cf_org_user" { + type = set(string) + description = "Defines the colleagues who are added to each subaccount as subaccount administrators." + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "cf_space_managers" { + type = list(string) + description = "The list of Cloud Foundry space managers." + default = [] +} + +variable "cf_space_developers" { + type = list(string) + description = "The list of Cloud Foundry space developers." + default = [] +} + +variable "cf_space_auditors" { + type = list(string) + description = "The list of Cloud Foundry space auditors." + default = [] +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_1.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_1.png new file mode 100644 index 00000000..053485a3 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_1.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_2.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_2.png new file mode 100644 index 00000000..40ccd768 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_2.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_3.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_3.png new file mode 100644 index 00000000..c59935d5 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_3.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_4.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_4.png new file mode 100644 index 00000000..a189a3cc Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_4.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_5.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_5.png new file mode 100644 index 00000000..17436037 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_5.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_6.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_6.png new file mode 100644 index 00000000..bd8fde88 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_6.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_7.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_7.png new file mode 100644 index 00000000..0bbe96cb Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_7.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_8.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_8.png new file mode 100644 index 00000000..eb322cd6 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE4/assets/ex7_8.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/README.md b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/README.md new file mode 100644 index 00000000..ea6f4c4e --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/README.md @@ -0,0 +1,232 @@ +# Exercise 5 - Create a CloudFoundry Space + +## Goal of this Exercise 🎯 + +In this exercise you will learn how to use the Terrafomr Provider for CloudFoundry and create a space. + +### Step 3: Adjust the provider configuration + +As we are using an additional provider we must make Terraform aware of this in the `provider.tf` file. Open the `provider.tf` file and add the following code to the `required_provider` block: + +```terraform +cloudfoundry = { + source = "cloudfoundry/cloudfoundry" + version = "1.1.0" + } +``` + +To configure the Cloud Foundry provider add the following lines at the end of the file: + +```terraform +provider "cloudfoundry" { + api_url = "https://api.cf.${var.region}-001.hana.ondemand.com" +} +``` +Save your changes. + +> [!WARNING] +> We assume that the Cloud Foundry environment is deployed to the extension landscape 001. If this is not the case the authentication might fail. In a real-world scenario you would probably have a different boundary of content to the module. + +To fulfill all requirements for the authentication against the Cloud Foundry environment you must export the following environment variables: + +- Windows: + + ```pwsh + $env:CF_USER= + $env:CF_PASSWORD='' + ``` + +- Linux/MacOS/GitHub Codespaces: + + ```bash + export CF_USER= + export CF_PASSWORD='' + ``` + +> [!NOTE] +> Although we do not use the Cloud Foundry part of the module namely the assignment of users to the organization, Terraform will initialize the Cloud Foundry provider and try to authenticate against the Cloud Foundry environment. This is why we need to define the configuration and provide the credentials. + +### Step 3: Apply the changes + +As we have a new provider in place, we need to re-initialize the setup to download the required provider and module. Run the following command: + +```bash +terraform init +``` + +The output should look like this: + +executing terraform init with cloud foundry provider + +> [!NOTE] +> There is also a command parameter called `--upgrade` for the `terraform init` command. This parameter will *upgrade* the provider to the latest version. As we are adding new providers, we do not need to use this parameter. + +You know the drill by now: + +1. Plan the Terraform configuration to see what will be created: + + ```bash + terraform plan + ``` + + The output should look like this: + + executing terraform plan with cloud foundry + +2. Apply the Terraform configuration to create the environment: + + ```bash + terraform apply + ``` + + You will be prompted to confirm the creation of the environment. Type `yes` and press `Enter` to continue. + +The result should look like this: + +executing terraform apply with cloud foundry provider + +You can also check that everything is in place via the SAP BTP cockpit. You should see the Cloud Foundry environment in the subaccount: + + SAP BTP Cockpit with Cloud Foundry environment + +## Creation of a Cloud Foundry space + +As a last task we also want to add a Cloud Foundry space to the Cloud Foundry environment. + +### Step 1: Add the variable to the configuration for Space creation + +First we need to add more variable in the `variables.tf` file. Open the `variables.tf` file and add the following code: + +```terraform +variable "cf_space_name" { + type = string + description = "The name of the Cloud Foundry space." + default = "dev" +} + +variable "cf_landscape_label" { + type = string + description = "The region where the project account shall be created in." + default = "cf-us10-001" +} + +variable "cf_org_name" { + type = string + description = "The name for the Cloud Foundry Org." + default = "" +} + +variable "cf_org_user" { + type = set(string) + description = "Defines the colleagues who are added to each subaccount as subaccount administrators." + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "cf_space_managers" { + type = list(string) + description = "The list of Cloud Foundry space managers." + default = [] +} + +variable "cf_space_developers" { + type = list(string) + description = "The list of Cloud Foundry space developers." + default = [] +} + +variable "cf_space_auditors" { + type = list(string) + description = "The list of Cloud Foundry space auditors." + default = [] +} +``` + +This allows us to specify the name of the Cloud Foundry space. We also define a default value (`dev`) for the variable. Save the changes. + +### Step 2: Cloudfoundry Space Creation and Role Assignments + +To trigger the creation of a Cloud Foundry space and space roles, Open the `main.tf` file and add the following code: + +```terraform +resource "cloudfoundry_org_role" "my_role" { + for_each = var.cf_org_user + username = each.value + type = "organization_user" + org = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +resource "cloudfoundry_space" "space" { + name = var.name + org = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +resource "cloudfoundry_space_role" "cf_space_managers" { + for_each = toset(var.cf_space_managers) + username = each.value + type = "space_manager" + space = cloudfoundry_space.space.id + depends_on = [ cloudfoundry_org_role.my_role ] +} + +resource "cloudfoundry_space_role" "cf_space_developers" { + for_each = toset(var.cf_space_developers) + username = each.value + type = "space_developer" + space = cloudfoundry_space.space.id + depends_on = [ cloudfoundry_org_role.my_role ] +} + +resource "cloudfoundry_space_role" "cf_space_auditors" { + for_each = toset(var.cf_space_auditors) + username = each.value + type = "space_auditor" + space = cloudfoundry_space.space.id + depends_on = [ cloudfoundry_org_role.my_role ] +} +``` + +### Step 3: Add the variables to tfvar file + +Now we can add `space developers` and `space managers` to the space we created, Add following variables to your `tfvars` file. + +```terraform +cf_org_user = ["john.doe@test.com"] +cf_space_developers = ["john.doe@test.com"] +``` +Save the changes. + +### Step 4: Apply the changes + +As we have all prerequisites already in place when it comes to provider configuration and authentication, we can proceed with applying the changes. + +1. Plan the Terraform configuration to see what will be created: + + ```bash + terraform plan + ``` + + The output should look like this: + + executing terraform plan for cloud foundry space creation + +2. Apply the Terraform configuration to create the space: + + ```bash + terraform apply + ``` + + You will be prompted to confirm the creation of the space. Type `yes` and press `Enter` to continue. + +The result should look like this: + +executing terraform apply for cloud foundry space creation + +You can also check that everything is in place via the SAP BTP cockpit. You should see the Cloud Foundry space in the subaccount: + + SAP BTP Cockpit with Cloud Foundry space + +## Summary + +You've now successfully created a Cloud Foundry environment instance as well as a Cloud Foundry space in SAP BTP. + +Continue to - [Exercise 6 - Cleanup](../EXERCISE6/README.md). \ No newline at end of file diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/main.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/main.tf new file mode 100644 index 00000000..4b2b125c --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/main.tf @@ -0,0 +1,102 @@ +locals { + project_subaccount_name = "${var.org_name} | ${var.project_name}: CF - ${var.stage}" + project_subaccount_domain = lower(replace("${var.org_name}-${var.project_name}-${var.stage}", " ", "-")) + project_subaccount_cf_org = replace("${var.org_name}_${lower(var.project_name)}-${lower(var.stage)}", " ", "_") +} + +resource "btp_subaccount" "project" { + name = local.project_subaccount_name + subdomain = local.project_subaccount_domain + region = lower(var.region) + labels = { + "stage" = ["${var.stage}"], + "costcenter" = ["${var.costcenter}"] + } +} + +resource "btp_subaccount_entitlement" "bas" { + subaccount_id = btp_subaccount.project.id + service_name = "sapappstudiotrial" + plan_name = var.bas_plan_name +} +resource "btp_subaccount_subscription" "bas-subscribe" { + subaccount_id = btp_subaccount.project.id + app_name = "sapappstudiotrial" + plan_name = var.bas_plan_name + depends_on = [btp_subaccount_entitlement.bas] +} +resource "btp_subaccount_role_collection_assignment" "Business_Application_Studio_Administrator" { + for_each = toset(var.bas_admins) + subaccount_id = btp_subaccount.project.id + role_collection_name = "Business_Application_Studio_Administrator" + user_name = each.value + depends_on = [btp_subaccount_subscription.bas-subscribe] +} + +resource "btp_subaccount_role_collection_assignment" "Business_Application_Studio_Developer" { + subaccount_id = btp_subaccount.project.id + role_collection_name = "Business_Application_Studio_Developer" + for_each = toset(var.bas_developers) + user_name = each.value + depends_on = [btp_subaccount_subscription.bas-subscribe] +} + +resource "btp_subaccount_entitlement" "cf_application_runtime" { + subaccount_id = btp_subaccount.project.id + service_name = "APPLICATION_RUNTIME" + plan_name = "MEMORY" +} + +resource "btp_subaccount_environment_instance" "cloudfoundry" { + depends_on = [btp_subaccount_entitlement.cf_application_runtime] + subaccount_id = btp_subaccount.project.id + name = local.project_subaccount_cf_org + landscape_label = var.cf_landscape_label + environment_type = "cloudfoundry" + service_name = "cloudfoundry" + plan_name = "trial" + parameters = jsonencode({ + instance_name = local.project_subaccount_cf_org + }) + timeouts = { + create = "1h" + update = "35m" + delete = "30m" + } +} + +resource "cloudfoundry_org_role" "my_role" { + for_each = var.cf_org_user + username = each.value + type = "organization_user" + org = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +resource "cloudfoundry_space" "space" { + name = var.name + org = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +resource "cloudfoundry_space_role" "cf_space_managers" { + for_each = toset(var.cf_space_managers) + username = each.value + type = "space_manager" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} + +resource "cloudfoundry_space_role" "cf_space_developers" { + for_each = toset(var.cf_space_developers) + username = each.value + type = "space_developer" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} + +resource "cloudfoundry_space_role" "cf_space_auditors" { + for_each = toset(var.cf_space_auditors) + username = each.value + type = "space_auditor" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/outputs.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/outputs.tf new file mode 100644 index 00000000..4352f77b --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/outputs.tf @@ -0,0 +1,14 @@ +output "subaccount_id" { + value = btp_subaccount.project.id + description = "The ID of the project subaccount." +} + +output "subaccount_name" { + value = btp_subaccount.project.name + description = "The name of the project subaccount." +} + +output "cloudfoundry_org_name" { + value = local.project_subaccount_cf_org + description = "The name of the cloudfoundry org connected to the project account." +} \ No newline at end of file diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/provider.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/provider.tf new file mode 100644 index 00000000..021cbfa8 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/provider.tf @@ -0,0 +1,21 @@ +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.8.0" + } + cloudfoundry = { + source = "cloudfoundry/cloudfoundry" + version = "~> 1.1.0" + } + } + +} + +provider "btp" { + globalaccount = var.globalaccount +} + +provider "cloudfoundry" { + api_url = "https://api.cf.${var.region}-001.hana.ondemand.com" +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/terraform.tfvars-sample b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/terraform.tfvars-sample new file mode 100644 index 00000000..c281dae5 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/terraform.tfvars-sample @@ -0,0 +1 @@ +globalaccount = "" diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/variables.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/variables.tf new file mode 100644 index 00000000..772e3754 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/SOLUTION_EX5/variables.tf @@ -0,0 +1,115 @@ +variable "globalaccount" { + type = string + description = "The subdomain of the SAP BTP global account." +} + +variable "region" { + type = string + description = "The region where the project account shall be created in." + default = "us10" +} + +variable "project_name" { + type = string + description = "The subaccount name." + default = "myproj-1234" + + validation { + condition = can(regex("^[a-zA-Z0-9_\\-]{1,200}", var.project_name)) + error_message = "Provide a valid project name." + } +} + +variable "stage" { + type = string + description = "The stage/tier the account will be used for." + default = "DEV" + + validation { + condition = contains(["DEV", "TST", "PRD"], var.stage) + error_message = "Select a valid stage for the project account." + } +} + +variable "costcenter" { + type = string + description = "The cost center the account will be billed to." + default = "1234567890" + + validation { + condition = can(regex("^[0-9]{10}", var.costcenter)) + error_message = "Provide a valid cost center." + } +} + +variable "bas_plan_name" { + description = "BAS plan" + type = string + default = "free" +} + +variable "bas_developers" { + description = "BAS developers" + type = list(string) + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "bas_admins" { + description = "BAS Admininstrators" + type = list(string) + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "org_name" { + type = string + description = "Defines to which organisation the project account shall belong to." + default = "B2C" +} + +variable "cf_space_name" { + type = string + description = "The name of the Cloud Foundry space." + default = "dev" +} + +variable "cf_landscape_label" { + type = string + description = "The region where the project account shall be created in." + default = "cf-us10-001" +} + +variable "cf_org_name" { + type = string + description = "The name for the Cloud Foundry Org." + default = "" +} + +variable "cf_org_user" { + type = set(string) + description = "Defines the colleagues who are added to each subaccount as subaccount administrators." + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "name" { + type = string + description = "The name of the Cloud Foundry space." + default = "dev" +} + +variable "cf_space_managers" { + type = list(string) + description = "The list of Cloud Foundry space managers." + default = [] +} + +variable "cf_space_developers" { + type = list(string) + description = "The list of Cloud Foundry space developers." + default = [] +} + +variable "cf_space_auditors" { + type = list(string) + description = "The list of Cloud Foundry space auditors." + default = [] +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_1.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_1.png new file mode 100644 index 00000000..c9472698 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_1.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_2.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_2.png new file mode 100644 index 00000000..f276a956 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_2.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_3.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_3.png new file mode 100644 index 00000000..b8f5c4af Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex3_3.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_1.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_1.png new file mode 100644 index 00000000..053485a3 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_1.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_2.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_2.png new file mode 100644 index 00000000..40ccd768 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_2.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_3.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_3.png new file mode 100644 index 00000000..c59935d5 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_3.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_4.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_4.png new file mode 100644 index 00000000..a189a3cc Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_4.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_5.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_5.png new file mode 100644 index 00000000..17436037 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_5.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_6.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_6.png new file mode 100644 index 00000000..bd8fde88 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_6.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_7.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_7.png new file mode 100644 index 00000000..0bbe96cb Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_7.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_8.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_8.png new file mode 100644 index 00000000..eb322cd6 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE5/assets/ex7_8.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/README.md b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/README.md new file mode 100644 index 00000000..3c3919a4 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/README.md @@ -0,0 +1,47 @@ +# Exercise 6 - Cleanup + +## Goal of this Exercise 🎯 + +The goal of this exercise is to delete the resources that were created in the previous exercises. This is important to avoid unnecessary costs and to keep the environment clean. + +## Step 1: Trigger the deletion of the resources + +You can delete the resources by running the following command: + +```bash +terraform destroy +``` + +The output of the command will look similar to this: + +executing terraform destroy + +Take also a look at the summary. This will show how the number of resources to be deleted: + +overview of deleted resources + +Terraform will calculate the changes it will execute, namely the deletion of the resources. You will be prompted to confirm the deletion. Check the output of the plan. Type `yes` and hit `Enter` to confirm the deletion. + +This will now recursively delete all resources that were created by Terraform. This might take a bit of time. At the end you should see a message like this: + +result of terraform destroy + +## Step 2: Verify the deletion of the resources + +After the deletion was executed successfully, verify that the resources were deleted. You can check the status of the resources in the SAP BTP cockpit. + +## Step 3: Check the Terraform state + +After the deletion of the resources, check the Terraform state. Walk through the following questions: + +- Did the state file disappear or is it still there? +- If it is still there what is the content of the state file? + +> [!TIP] +> You can also use the `terraform state list` command to inspect the state of the resources. You find more information about that command in the [Terraform documentation](https://developer.hashicorp.com/terraform/cli/state/inspect). + +## Summary + +Congrats - you've successfully completed the HandsOn. You've now learned how to use Terraform to manage resources in SAP BTP, how to deal with drift and also how to delete the resources again. + +Happy Terraforming! diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_1.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_1.png new file mode 100644 index 00000000..97da4780 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_1.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_2.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_2.png new file mode 100644 index 00000000..5ea31113 Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_2.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_3.png b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_3.png new file mode 100644 index 00000000..d21861cf Binary files /dev/null and b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/exercises/EXERCISE6/assets/ex8_3.png differ diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/main.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/main.tf new file mode 100644 index 00000000..ef0d278d --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/main.tf @@ -0,0 +1,110 @@ +locals { + project_subaccount_name = "${var.org_name} | ${var.project_name}: CF - ${var.stage}" + project_subaccount_domain = lower(replace("${var.org_name}-${var.project_name}-${var.stage}", " ", "")) + project_subaccount_cf_org = replace("${var.org_name}_${lower(var.project_name)}-${lower(var.stage)}", " ", "_") +} + +resource "btp_subaccount" "project" { + name = local.project_subaccount_name + subdomain = local.project_subaccount_domain + region = lower(var.region) + labels = { + "stage" = ["${var.stage}"], + "costcenter" = ["${var.costcenter}"] + } +} + +resource "btp_subaccount_role_collection_assignment" "subaccount_users" { + for_each = toset(var.emergency_admins) + subaccount_id = btp_subaccount.project.id + role_collection_name = "Subaccount Administrator" + user_name = each.value +} + +resource "btp_subaccount_entitlement" "bas" { + subaccount_id = btp_subaccount.project.id + service_name = "sapappstudiotrial" + plan_name = var.bas_plan_name +} +resource "btp_subaccount_subscription" "bas-subscribe" { + subaccount_id = btp_subaccount.project.id + app_name = "sapappstudiotrial" + plan_name = var.bas_plan_name + depends_on = [btp_subaccount_entitlement.bas] +} +resource "btp_subaccount_role_collection_assignment" "Business_Application_Studio_Administrator" { + for_each = toset(var.bas_admins) + subaccount_id = btp_subaccount.project.id + role_collection_name = "Business_Application_Studio_Administrator" + user_name = each.value + depends_on = [btp_subaccount_subscription.bas-subscribe] +} + +resource "btp_subaccount_role_collection_assignment" "Business_Application_Studio_Developer" { + subaccount_id = btp_subaccount.project.id + role_collection_name = "Business_Application_Studio_Developer" + for_each = toset(var.bas_developers) + user_name = each.value + depends_on = [btp_subaccount_subscription.bas-subscribe] +} + +resource "btp_subaccount_entitlement" "cf_application_runtime" { + subaccount_id = btp_subaccount.project.id + service_name = "APPLICATION_RUNTIME" + plan_name = "MEMORY" +} + +resource "btp_subaccount_environment_instance" "cloudfoundry" { + depends_on = [btp_subaccount_entitlement.cf_application_runtime] + subaccount_id = btp_subaccount.project.id + name = local.project_subaccount_cf_org + landscape_label = var.cf_landscape_label + environment_type = "cloudfoundry" + service_name = "cloudfoundry" + plan_name = "trial" + parameters = jsonencode({ + instance_name = local.project_subaccount_cf_org + memory = 1024 + }) + timeouts = { + create = "1h" + update = "35m" + delete = "30m" + } +} + +resource "cloudfoundry_org_role" "my_role" { + for_each = var.cf_org_user + username = each.value + type = "organization_user" + org = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +resource "cloudfoundry_space" "space" { + name = var.name + org = btp_subaccount_environment_instance.cloudfoundry.platform_id +} + +resource "cloudfoundry_space_role" "cf_space_managers" { + for_each = toset(var.cf_space_managers) + username = each.value + type = "space_manager" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} + +resource "cloudfoundry_space_role" "cf_space_developers" { + for_each = toset(var.cf_space_developers) + username = each.value + type = "space_developer" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} + +resource "cloudfoundry_space_role" "cf_space_auditors" { + for_each = toset(var.cf_space_auditors) + username = each.value + type = "space_auditor" + space = cloudfoundry_space.space.id + depends_on = [cloudfoundry_org_role.my_role] +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/outputs.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/outputs.tf new file mode 100644 index 00000000..77ccfb21 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/outputs.tf @@ -0,0 +1,14 @@ +output "subaccount_id" { + value = btp_subaccount.project.id + description = "The ID of the project subaccount." +} + +output "subaccount_name" { + value = btp_subaccount.project.name + description = "The name of the project subaccount." +} + +output "cloudfoundry_org_name" { + value = local.project_subaccount_cf_org + description = "The name of the cloudfoundry org connected to the project account." +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/provider.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/provider.tf new file mode 100644 index 00000000..021cbfa8 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/provider.tf @@ -0,0 +1,21 @@ +terraform { + required_providers { + btp = { + source = "sap/btp" + version = "~> 1.8.0" + } + cloudfoundry = { + source = "cloudfoundry/cloudfoundry" + version = "~> 1.1.0" + } + } + +} + +provider "btp" { + globalaccount = var.globalaccount +} + +provider "cloudfoundry" { + api_url = "https://api.cf.${var.region}-001.hana.ondemand.com" +} diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/terraform.tfvars-sample b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/terraform.tfvars-sample new file mode 100644 index 00000000..d7fcc6ca --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/terraform.tfvars-sample @@ -0,0 +1,8 @@ +globalaccount = "" + +bas_plan_name = "trial" +bas_admins = ["john.doe@test.com"] +bas_developers = ["john.doe@test.com"] + +cf_org_user = ["john.doe@test.com"] +cf_space_developers = ["john.doe@test.com"] \ No newline at end of file diff --git a/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/variables.tf b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/variables.tf new file mode 100644 index 00000000..ddbfec18 --- /dev/null +++ b/released/SAP-Inside-Tracks/SITBLR_DEC_2024/solution/variables.tf @@ -0,0 +1,121 @@ +variable "globalaccount" { + type = string + description = "The subdomain of the SAP BTP global account." +} + +variable "region" { + type = string + description = "The region where the project account shall be created in." + default = "us10" +} + +variable "project_name" { + type = string + description = "The subaccount name." + default = "myproj-1234" + + validation { + condition = can(regex("^[a-zA-Z0-9_\\-]{1,200}", var.project_name)) + error_message = "Provide a valid project name." + } +} + +variable "stage" { + type = string + description = "The stage/tier the account will be used for." + default = "DEV" + + validation { + condition = contains(["DEV", "TST", "PRD"], var.stage) + error_message = "Select a valid stage for the project account." + } +} + +variable "costcenter" { + type = string + description = "The cost center the account will be billed to." + default = "1234567890" + + validation { + condition = can(regex("^[0-9]{10}", var.costcenter)) + error_message = "Provide a valid cost center." + } +} + +variable "bas_plan_name" { + description = "BAS plan" + type = string + default = "free" +} + +variable "bas_developers" { + description = "BAS developers" + type = list(string) + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "bas_admins" { + description = "BAS Admininstrators" + type = list(string) + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "org_name" { + type = string + description = "Defines to which organisation the project account shall belong to." + default = "B2C" +} + +variable "emergency_admins" { + type = list(string) + description = "Defines the colleagues who are added to each subaccount as emergency administrators." + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "cf_space_name" { + type = string + description = "The name of the Cloud Foundry space." + default = "dev" +} + +variable "cf_landscape_label" { + type = string + description = "The region where the project account shall be created in." + default = "cf-us10-001" +} + +variable "cf_org_name" { + type = string + description = "The name for the Cloud Foundry Org." + default = "" +} + +variable "cf_org_user" { + type = set(string) + description = "Defines the colleagues who are added to each subaccount as subaccount administrators." + default = ["jane.doe@test.com", "john.doe@test.com"] +} + +variable "name" { + type = string + description = "The name of the Cloud Foundry space." + default = "dev" +} + +variable "cf_space_managers" { + type = list(string) + description = "The list of Cloud Foundry space managers." + default = [] +} + +variable "cf_space_developers" { + type = list(string) + description = "The list of Cloud Foundry space developers." + default = [] +} + +variable "cf_space_auditors" { + type = list(string) + description = "The list of Cloud Foundry space auditors." + default = [] +}