10

Automating SAP BTP setup with Terraform – A workaround for Global Account, Direc...

 1 year ago
source link: https://blogs.sap.com/2023/02/21/automating-sap-btp-setup-with-terraform-a-workaround-for-global-account-directories-and-subaccounts-with-btp-cli/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
February 21, 2023 5 minute read

Automating SAP BTP setup with Terraform – A workaround for Global Account, Directories and Subaccounts with btp CLI

In my previous blog, Automating SAP BTP setup with Terraform – Infrastructure as Code for Cloud Foundry and Kyma Environments, I introduced Infrastructure as Code (IaC) and Terraform in SAP BTP context. I explained how Terraform Providers can automate pretty much everything in Cloud Foundry and Kyma (Kubernetes) environments. I described some use cases and showed a step-by-step on how to use Terraform to provision a CF space with services and users configured.

I also said that “At this moment, there isn’t any Terraform provider created specifically for SAP BTP. Which means everything above CF or Kyma isn’t supported, e.g., global account and directories“, and that I’d create my own Terraform Provider for BTP. I still haven’t got there yet, but I bring some good news.

Terraform allows you to run shell scripts, local and/or remote. This capability is called Provisioners and its use case is for anything not supported by Providers, but doable via any CLI. Provisioners don’t work as Providers, they don’t fully control a resource state, they have heaps of limitations and are the last resort for when you need to do something which is impossible via a Provider.

That said, I have managed to use Terraform Provisioners with btp CLI to control everything BTP related that is not supported by a Provider: global accounts, directories, subaccounts, entitlements, platform users, etc.

If you don’t know what btp CLI is, here a brief description from the help page:

Use the SAP BTP command line interface (btp CLI) for all account administration tasks, such as creating or updating subaccounts, authorization management, and working with service brokers and platforms. It is an alternative to the SAP BTP cockpit for all users who like to work in a terminal or want to automate operations using scripts.

How to use it?

Using Terraform Provisioners is quite easy. As we don’t have a proper Provider for SAP BTP, we’ll use resource null_resource, and, because we’re running btp CLI from our local computer, we’ll use provisioner local-exec. The command property is the CLI command you want to execute.

resource "null_resource" "example" {
  provisioner "local-exec" {
    command = "echo 'You can execute any shell command here'"
  }
}

Why should I use it?

With this approach you can have everything in just one place. All your SAP BTP setup managed and versioned in a git repo. No need to have multiple tools nor perform heaps of manual tasks. You can have reusable recipes for common environments such as training space for solution XYZ, on-demand testing instances or a free-for-all development sandbox.

Demo time!

Make sure you have Terraform and btp CLI installed in the computer running the script.

Note that I’m using Terraform variables to make the examples more generic and closer to what we would see in the real world.

The first script will create a BTP subaccount.

variable "username" {}
variable "password" {}
variable "global_account_subdomain" {}
variable "subaccount_region" {}
variable "subaccount_subdomain" {}
variable "subaccount_name" {}

resource "null_resource" "btp_subaccount_creation" {
  provisioner "local-exec" {
    command = "btp login --url https://cpcli.cf.eu10.hana.ondemand.com --user ${var.username} --password ${var.password}"
  }

  provisioner "local-exec" {
    command = "btp target --global-account ${var.global_account_subdomain}"
  }

  provisioner "local-exec" {
    command = "btp create accounts/subaccount --display-name ${var.subaccount_name} --region ${var.subaccount_region} --subdomain ${var.subaccount_subdomain}"
  }
}

The second script assumes a subaccount already exists, it will change its entitlement adding Cloud Foundry to it and then provision the CF environment.

variable "username" {}
variable "password" {}
variable "global_account_subdomain" {}
variable "subaccount_id" {}
variable "cf_org_name" {}

resource "null_resource" "btp_cf_setup" {
  provisioner "local-exec" {
    command = "btp login --url https://cpcli.cf.eu10.hana.ondemand.com --user ${var.username} --password ${var.password}"
  }

  provisioner "local-exec" {
    command = "btp target --global-account ${var.global_account_subdomain}"
  }

  provisioner "local-exec" {
    command = "btp assign accounts/entitlement --to-subaccount ${var.subaccount_id} --for-service cloudfoundry --plan free --amount 1"
  }
  
  provisioner "local-exec" {
    command = "btp create accounts/environment-instance --subaccount ${var.subaccount_id} --display-name ${var.cf_org_name} --environment cloudfoundry --service cloudfoundry --plan free --parameters {\"instance_name\":\"${var.cf_org_name}\"}"
  }
}

The third script assumes subaccount and CF environment have been created, it will change subaccount entitlement and configure SAP Business Application Studio + Audit Log services.

variable "username" {}
variable "password" {}
variable "global_account_subdomain" {}
variable "subaccount_id" {}

resource "null_resource" "btp_subaccount_entitlement" {
  provisioner "local-exec" {
    command = "btp login --url https://cpcli.cf.eu10.hana.ondemand.com --user ${var.username} --password ${var.password}"
  }

  provisioner "local-exec" {
    command = "btp target --global-account ${var.global_account_subdomain}"
  }

  provisioner "local-exec" {
    command = "btp assign accounts/entitlement --to-subaccount ${var.subaccount_id} --for-service sapappstudio --plan free --amount 1"
  }

  provisioner "local-exec" {
    command = "btp assign accounts/entitlement --to-subaccount ${var.subaccount_id} --for-service auditlog-management --plan default --enable"
  }

  provisioner "local-exec" {
    command = "btp assign accounts/entitlement --to-subaccount ${var.subaccount_id} --for-service auditlog-viewer --plan free --enable"
  }
}

resource "null_resource" "btp_subaccount_app_subscription" {
  depends_on = [null_resource.btp_subaccount_entitlement]

  provisioner "local-exec" {
    command = "btp target --subaccount ${var.subaccount_id}"
  }

  provisioner "local-exec" {
    command = "btp subscribe accounts/subaccount --to-app sapappstudio --plan free"
  }

  provisioner "local-exec" {
    command = "btp subscribe accounts/subaccount --to-app auditlog-viewer --plan free"
  }
}

Last script shows everything together, CF Provider + Provisioners with btp CLI manipulating all aspects in your BTP account.

terraform {
  required_providers {
    cloudfoundry = {
      source  = "cloudfoundry-community/cloudfoundry"
      version = "0.50.4"
    }
  }
}

variable "user" {}
variable "password" {}
variable "global_account_subdomain" {}
variable "subaccount_id" {}
variable "cf_org_name" {}
variable "cf_space_name" {}
variable "cf_api_url" {}

resource "null_resource" "btp_subaccount_creation" {
  provisioner "local-exec" {
    command = "btp login --url https://cpcli.cf.eu10.hana.ondemand.com --user ${var.user} --password ${var.password}"
  }

  provisioner "local-exec" {
    command = "btp target --global-account ${var.global_account_subdomain}"
  }

  provisioner "local-exec" {
    command = "btp assign accounts/entitlement --to-subaccount ${var.subaccount_id} --for-service cloudfoundry --plan free --amount 1"
  }
  
  provisioner "local-exec" {
    command = "btp create accounts/environment-instance --subaccount ${var.subaccount_id} --display-name ${var.cf_org_name} --environment cloudfoundry --service cloudfoundry --plan free --parameters {\"instance_name\":\"${var.cf_org_name}\"}"
  }
}

resource "null_resource" "btp_subaccount_entitlement" {
  depends_on = [null_resource.btp_subaccount_creation]

  provisioner "local-exec" {
    command = "btp assign accounts/entitlement --to-subaccount ${var.subaccount_id} --for-service sapappstudio --plan free --amount 1"
  }

  provisioner "local-exec" {
    command = "btp assign accounts/entitlement --to-subaccount ${var.subaccount_id} --for-service auditlog-management --plan default --enable"
  }

  provisioner "local-exec" {
    command = "btp assign accounts/entitlement --to-subaccount ${var.subaccount_id} --for-service auditlog-viewer --plan free --enable"
  }
}

resource "null_resource" "btp_subaccount_app_subscription" {
  depends_on = [null_resource.btp_subaccount_entitlement]

  provisioner "local-exec" {
    command = "btp target --subaccount ${var.subaccount_id}"
  }

  provisioner "local-exec" {
    command = "btp subscribe accounts/subaccount --to-app sapappstudio --plan free"
  }

  provisioner "local-exec" {
    command = "btp subscribe accounts/subaccount --to-app auditlog-viewer --plan free"
  }
}

provider "cloudfoundry" {
  api_url  = var.cf_api_url
  user     = var.user
  password = var.password
}

resource "cloudfoundry_org" "org1" {
  name = var.cf_org_name
}

resource "cloudfoundry_space" "org1-space1" {
  name = var.cf_space_name
  org = cloudfoundry_org.org1.id
}

resource "cloudfoundry_space_users" "org1-space1-users" {
  space      = cloudfoundry_space.org1-space1.id
  managers   = [var.user]
  developers = [var.user]
  auditors   = [var.user]
}

data "cloudfoundry_service" "application-logs" {
  name = "application-logs"
}

resource "cloudfoundry_service_instance" "application-logs-srv" {
  name         = "app-logs-srv"
  space        = cloudfoundry_space.org1-space1.id
  service_plan = data.cloudfoundry_service.application-logs.service_plans["lite"]
  depends_on = [cloudfoundry_space_users.org1-space1-users]
}

As seen above, you can mix and match whatever you want to satisfy your requirements. You don’t have to control everything in the account if you don’t want to. You can alsogng have multiple .tf files: one with proper Providers managing resources and states, another just with Provisioners and btp CLI commands to handle the one-off tasks.

Remember, this is a workaround to be used until we have a proper Terraform Provider for SAP BTP.

What next?

Same as before… Still awaiting SAP to provide us an official Terraform Provider for SAP BTP. Meanwhile, learning the basics of Go 🙃


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK