Skip to content

Commit 0bb2d4d

Browse files
committed
first version of namming module
1 parent 33e2606 commit 0bb2d4d

File tree

7 files changed

+310
-0
lines changed

7 files changed

+310
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,8 @@ override.tf.json
3636
.terraformrc
3737
terraform.rc
3838

39+
.DS_Store
40+
3941
*.env
42+
43+
playground/**

sample-setup/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Terraform Samples for SAP BTP Administrator's Guide
2+
3+
## Paradigms
4+
5+
We follow the paradigms of a simpel and clear Terraform configuration as laid out in the [Simple, Clear, Maintainable](https://rosesecurity.dev/blog/2024/11/24/terraform-proverbs) blog post of the [Development Log](https://rosesecurity.dev/) namely:
6+
7+
- Clear is better than clever.
8+
- Version everything.
9+
- Modules should be reusable, not rigid.
10+
- State is a liability; manage it wisely.
11+
- Every apply should be predictable.
12+
- Outputs are for sharing.
13+
- Tags are free; use them liberally.
14+
- Understanding count versus for_each is essential.
15+
- Descriptions are for users.
16+
- Use positive variable names to avoid double negatives.
17+
- Null is not the same as nothing.
18+
- Prefer a single object over many related variables.
19+
- Terraform is declarative; trust it to converge.
20+
- Never output secrets.
21+
- Upgrade deliberately, not impulsively.
22+
- Name with underscores, not dashes.
23+
- Using locals makes code descriptive and maintainable.
24+
25+
These paradigms will be reflected in the code samples provided in this repository and we encourage you to follow them in your own Terraform code.
26+
27+
## Naming Conventions and Tagging
28+
29+
Ensuring naming conventions is one import aspect when provisioing and managing your SAP BTP account. We will align our samples in accordance to the [Naming Conventions for SAP BTP Accounts](https://help.sap.com/docs/btp/btp-admin-guide/naming-conventions-for-sap-btp-accounts).
30+
31+
To ensure consistent naming of your resources, we encapsulate the guidlines in a dedicated module.
32+
33+
Besides the naming we will also include the labels that can be attached to some resources on SAP BTP.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SAP BTP - Naming module
2+
3+
This module encapsulates the naming conventions for SAP BTP accounts and the labels that can be attached to some resources on SAP BTP.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
resource "random_uuid" "self" {
2+
}
3+
4+
locals {
5+
# The length limit for the subdomain is 63 characters.
6+
subdomain_length_limit = 63
7+
costcenter_label_name = "Costcenter"
8+
directory_contact_label_name = "Directory responsibles"
9+
subaccount_contact_label_name = "Subaccount responsibles"
10+
stage_label_name = "Stage"
11+
managedby_label_name = "Managed by"
12+
13+
directory_name = var.region == null ? var.business_unit : format(
14+
"%s%s%s",
15+
upper(var.business_unit),
16+
var.delimiter,
17+
var.region
18+
)
19+
20+
directory_description = var.region == null ? format(
21+
"Directory for business Unit %s",
22+
var.business_unit
23+
) : format(
24+
"Directory for business Unit %s (%s)",
25+
var.business_unit,
26+
var.region
27+
)
28+
29+
costcenter_label_name_formatted = var.label_name_case == "lower" ? lower(local.costcenter_label_name) : var.label_name_case == "title" ? title(local.costcenter_label_name) : upper(local.costcenter_label_name)
30+
directory_contact_label_name_formatted = var.label_name_case == "lower" ? lower(local.directory_contact_label_name) : var.label_name_case == "title" ? title(local.directory_contact_label_name) : upper(local.directory_contact_label_name)
31+
subaccount_contact_label_name_formatted = var.label_name_case == "lower" ? lower(local.subaccount_contact_label_name) : var.label_name_case == "title" ? title(local.subaccount_contact_label_name) : upper(local.subaccount_contact_label_name)
32+
stage_label_name_formatted = var.label_name_case == "lower" ? lower(local.stage_label_name) : var.label_name_case == "title" ? title(local.stage_label_name) : upper(local.stage_label_name)
33+
managedby_label_name_formatted = var.label_name_case == "lower" ? lower(local.managedby_label_name) : var.label_name_case == "title" ? title(local.managedby_label_name) : upper(local.managedby_label_name)
34+
35+
costcenter_label_value_formatted = var.label_value_case == "lower" ? lower(var.costcenter) : var.label_value_case == "title" ? title(var.costcenter) : var.label_value_case == "upper" ? upper(var.costcenter) : var.costcenter
36+
stage_label_value_formatted = var.label_value_case == "lower" ? lower(var.stage) : var.label_value_case == "title" ? title(var.stage) : var.label_value_case == "upper" ? upper(var.stage) : var.stage
37+
management_label_value_formatted = var.label_value_case == "lower" ? lower(var.management_tool) : var.label_value_case == "title" ? title(var.management_tool) : var.label_value_case == "upper" ? upper(var.management_tool) : var.management_tool
38+
39+
basic_labels = {
40+
"${local.costcenter_label_name_formatted}" = [local.costcenter_label_value_formatted]
41+
"${local.stage_label_name_formatted}" = [local.stage_label_value_formatted]
42+
}
43+
44+
basic_labels_final = var.add_managed_by_label ? merge(
45+
local.basic_labels,
46+
{
47+
"${local.managedby_label_name_formatted}" = [local.management_label_value_formatted]
48+
}
49+
) : local.basic_labels
50+
51+
directory_labels = merge(
52+
local.basic_labels_final,
53+
{
54+
"${local.directory_contact_label_name_formatted}" = var.directory_contacts
55+
}
56+
)
57+
58+
subaccount_name = format(
59+
"%s%s%s",
60+
upper(var.business_unit),
61+
var.delimiter,
62+
var.stage)
63+
64+
65+
subaccount_subdomain_base = var.company_name == null ? format(
66+
"%s%s%s",
67+
lower(var.business_unit),
68+
var.delimiter,
69+
lower(var.stage)
70+
) : format(
71+
"%s%s%s%s%s",
72+
lower(var.company_name),
73+
var.delimiter,
74+
lower(var.business_unit),
75+
var.delimiter,
76+
lower(var.stage)
77+
)
78+
79+
subaccount_sudomain_with_UUID = format(
80+
"%s%s%s",
81+
local.subaccount_subdomain_base,
82+
var.delimiter,
83+
random_uuid.self.id
84+
)
85+
86+
subaccount_subdomain = length(local.subaccount_sudomain_with_UUID) > local.subdomain_length_limit ? substr(
87+
local.subaccount_sudomain_with_UUID,
88+
0,
89+
local.subdomain_length_limit
90+
) : local.subaccount_sudomain_with_UUID
91+
92+
93+
subaccount_description = format(
94+
"Subaccount for Business Unit %s (%s)",
95+
upper(var.business_unit),
96+
title(lower(var.stage))
97+
)
98+
99+
subaccount_labels = merge(
100+
local.basic_labels_final,
101+
{
102+
"${local.subaccount_contact_label_name_formatted}" = var.subaccount_contacts
103+
}
104+
)
105+
106+
subaccount_usage = var.stage == "Prod" ? "USED_FOR_PRODUCTIO" : "NOT_USED_FOR_PRODUCTIO"
107+
108+
cloudfoundry_org_name = local.subaccount_subdomain
109+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
output "directory_name" {
2+
value = local.directory_name
3+
description = "Name of the directory"
4+
}
5+
6+
output "directory_description" {
7+
value = local.directory_description
8+
description = "Description of the directory"
9+
}
10+
11+
output "directory_labels" {
12+
value = local.directory_labels
13+
description = "Labels for the directory"
14+
}
15+
16+
output "subaccount_name" {
17+
value = local.subaccount_name
18+
description = "Name of the subaccount"
19+
}
20+
21+
output "subaccount_subdomain" {
22+
value = local.subaccount_subdomain
23+
description = "Subdomain of the subaccount"
24+
}
25+
26+
output "subaccount_description" {
27+
value = local.subaccount_description
28+
description = "Description of the subaccount"
29+
}
30+
31+
output "subaccount_labels" {
32+
value = local.subaccount_labels
33+
description = "Labels for the subaccount"
34+
}
35+
36+
output "subaccount_usage" {
37+
value = local.subaccount_usage
38+
description = "Usage of the subaccount"
39+
}
40+
41+
output "cloudfoundry_org_name" {
42+
value = local.cloudfoundry_org_name
43+
description = "Name of the Cloud Foundry org"
44+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
variable "business_unit" {
2+
type = string
3+
description = "Business unit of the project e.g., HR, IT or Sales"
4+
}
5+
6+
variable "region" {
7+
type = string
8+
default = null
9+
description = <<-EOT
10+
The geographical region for a directory. The parameter is optional
11+
If you set it the possible values are: `EMEA`, `APAC`, `AMER`.
12+
Default value: `null`.
13+
EOT
14+
15+
validation {
16+
condition = var.region == null ? true : contains(["EMEA", "APAC", "AMER"], var.region)
17+
error_message = "Allowed values are: `EMEA`, `APAC`, `AMER`."
18+
}
19+
}
20+
21+
variable "stage" {
22+
type = string
23+
description = <<-EOT
24+
Stage of the environment to be setup up.
25+
Possible values: `Dev`, `Test`, `Prod`.
26+
EOT
27+
28+
validation {
29+
condition = contains(["Dev", "Test", "Prod"], var.stage)
30+
error_message = "Stage must be one of the following: `DEV`, `TEST`, `PROD`, `SBX`"
31+
}
32+
}
33+
34+
variable "company_name" {
35+
type = string
36+
description = <<-EOT
37+
Company name to be used for subaccount subdomains. The parameter is optional
38+
Default value: `null`.
39+
EOT
40+
41+
default = null
42+
}
43+
44+
variable "costcenter" {
45+
type = string
46+
description = "Cost center to be used for subaccounts"
47+
}
48+
49+
variable "directory_contacts" {
50+
type = list(string)
51+
description = "Contact persons to be used for directories, added as label"
52+
}
53+
54+
variable "subaccount_contacts" {
55+
type = list(string)
56+
description = "Contact persons to be used for subaccounts, added as label"
57+
}
58+
59+
variable "add_managed_by_label" {
60+
type = bool
61+
description = "Add label that resource is managed by Terraform"
62+
default = true
63+
}
64+
65+
variable "management_tool" {
66+
type = string
67+
description = <<-EOT
68+
Defines which tool is used for management of infrastructure.
69+
Possible values: `Terraform`, `OpenTofu`.
70+
Default value: `Terraform`.
71+
EOT
72+
73+
validation {
74+
condition = contains(["Terraform", "OpenTofu"], var.management_tool)
75+
error_message = "Allowed values are: `Terraform`, `OpenTofu`."
76+
}
77+
default = "Terraform"
78+
}
79+
80+
variable "delimiter" {
81+
type = string
82+
description = "Delimiter to be used for namings"
83+
default = "-"
84+
}
85+
86+
variable "label_name_case" {
87+
type = string
88+
default = "title"
89+
description = <<-EOT
90+
Controls the letter case of the `label` names for labels generated by this module.
91+
Possible values: `lower`, `title`, `upper`.
92+
Default value: `title`.
93+
EOT
94+
95+
validation {
96+
condition = contains(["lower", "title", "upper"], var.label_name_case)
97+
error_message = "Allowed values are: `lower`, `title`, `upper`."
98+
}
99+
}
100+
101+
variable "label_value_case" {
102+
type = string
103+
default = "lower"
104+
description = <<-EOT
105+
Controls the letter case of the `label` values for labels generated by this module.
106+
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
107+
Default value: `lower`.
108+
EOT
109+
110+
validation {
111+
condition = contains(["lower", "title", "upper", "none"], var.label_value_case)
112+
error_message = "Allowed values are: `lower`, `title`, `upper`, `none`."
113+
}
114+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
terraform {
2+
required_version = ">= 1.11"
3+
}

0 commit comments

Comments
 (0)