Skip to content

Commit 1a72bc6

Browse files
authored
feat: improved user experience for validating input variable values<br>* updated required terraform to be >= 1.9.0 (#162)
1 parent 6bb4f71 commit 1a72bc6

File tree

8 files changed

+152
-104
lines changed

8 files changed

+152
-104
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ You will also need `Administrator` access for any service which you are creating
9696

9797
| Name | Version |
9898
|------|---------|
99-
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
99+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.0 |
100100
| <a name="requirement_ibm"></a> [ibm](#requirement\_ibm) | >= 1.76.1, < 2.0.0 |
101101

102102
### Modules
@@ -117,10 +117,10 @@ No modules.
117117

118118
| Name | Description | Type | Default | Required |
119119
|------|-------------|------|---------|:--------:|
120-
| <a name="input_trusted_profile_claim_rules"></a> [trusted\_profile\_claim\_rules](#input\_trusted\_profile\_claim\_rules) | A list of Trusted Profile Claim Rule objects that are applied to the Trusted Profile created by the module. | <pre>list(object({<br/> # required arguments<br/> conditions = list(object({<br/> claim = string<br/> operator = string<br/> value = string<br/> }))<br/><br/> type = string<br/><br/> # optional arguments<br/> cr_type = optional(string)<br/> expiration = optional(number)<br/> name = optional(string)<br/> realm_name = optional(string)<br/> }))</pre> | `null` | no |
120+
| <a name="input_trusted_profile_claim_rules"></a> [trusted\_profile\_claim\_rules](#input\_trusted\_profile\_claim\_rules) | A list of Trusted Profile Claim Rule objects that are applied to the Trusted Profile created by the module. | <pre>list(object({<br/> # required arguments<br/> conditions = list(object({<br/> claim = string<br/> operator = string<br/> value = string<br/> }))<br/><br/> type = string<br/><br/> # optional arguments<br/> cr_type = optional(string)<br/> expiration = optional(number)<br/> name = optional(string)<br/> realm_name = optional(string)<br/> }))</pre> | `[]` | no |
121121
| <a name="input_trusted_profile_description"></a> [trusted\_profile\_description](#input\_trusted\_profile\_description) | Description of the trusted profile. | `string` | `null` | no |
122122
| <a name="input_trusted_profile_identity"></a> [trusted\_profile\_identity](#input\_trusted\_profile\_identity) | The identity to trust (use only if needed) | <pre>object({<br/> identifier = string<br/> identity_type = string<br/> accounts = optional(list(string))<br/> description = optional(string)<br/> })</pre> | `null` | no |
123-
| <a name="input_trusted_profile_links"></a> [trusted\_profile\_links](#input\_trusted\_profile\_links) | A list of Trusted Profile Link objects that are applied to the Trusted Profile created by the module. | <pre>list(object({<br/> # required arguments<br/> cr_type = string<br/> links = list(object({<br/> crn = string<br/> namespace = optional(string)<br/> name = optional(string)<br/> }))<br/><br/> # optional arguments<br/> name = optional(string)<br/> }))</pre> | `null` | no |
123+
| <a name="input_trusted_profile_links"></a> [trusted\_profile\_links](#input\_trusted\_profile\_links) | A list of Trusted Profile Link objects that are applied to the Trusted Profile created by the module. | <pre>list(object({<br/> # required arguments<br/> cr_type = string<br/> links = list(object({<br/> crn = string<br/> namespace = optional(string)<br/> name = optional(string)<br/> }))<br/><br/> # optional arguments<br/> name = optional(string)<br/> }))</pre> | `[]` | no |
124124
| <a name="input_trusted_profile_name"></a> [trusted\_profile\_name](#input\_trusted\_profile\_name) | Name of the trusted profile. | `string` | n/a | yes |
125125
| <a name="input_trusted_profile_policies"></a> [trusted\_profile\_policies](#input\_trusted\_profile\_policies) | A list of Trusted Profile Policy objects that are applied to the Trusted Profile created by the module. | <pre>list(object({<br/> roles = list(string)<br/> account_management = optional(bool)<br/> description = optional(string)<br/><br/> resources = optional(list(object({<br/> service = optional(string)<br/> service_type = optional(string)<br/> resource_instance_id = optional(string)<br/> region = optional(string)<br/> resource_type = optional(string)<br/> resource = optional(string)<br/> resource_group_id = optional(string)<br/> service_group_id = optional(string)<br/> attributes = optional(map(any))<br/> })), null)<br/><br/> resource_attributes = optional(list(object({<br/> name = string<br/> value = string<br/> operator = optional(string)<br/> })))<br/><br/> resource_tags = optional(list(object({<br/> name = string<br/> value = string<br/> operator = optional(string)<br/> })))<br/><br/> rule_conditions = optional(list(object({<br/> key = string<br/> operator = string<br/> value = list(any)<br/> })))<br/><br/> rule_operator = optional(string)<br/> pattern = optional(string)<br/> }))</pre> | n/a | yes |
126126

examples/basic/version.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
terraform {
2-
required_version = ">= 1.3.0"
2+
required_version = ">= 1.9.0"
33

44
# Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main
55
# module's version.tf (usually a basic example), and 1 example that will always use the latest provider version.

examples/complete/version.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
terraform {
2-
required_version = ">= 1.3.0"
2+
required_version = ">= 1.9.0"
33

44
# Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main
55
# module's version.tf (usually a basic example), and 1 example that will always use the latest provider version.

main.tf

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,6 @@ resource "ibm_iam_trusted_profile" "profile" {
88
}
99

1010
locals {
11-
# Validation of variables
12-
# tflint-ignore: terraform_unused_declarations
13-
validate_policies_one_and_only_one = [
14-
for i, policy in var.trusted_profile_policies : (
15-
(lookup(policy, "account_management", null) != null && lookup(policy, "resources", null) == null && lookup(policy, "resource_attributes", null) == null) ||
16-
(lookup(policy, "account_management", null) == null && lookup(policy, "resources", null) != null && lookup(policy, "resource_attributes", null) == null) ||
17-
(lookup(policy, "account_management", null) == null && lookup(policy, "resources", null) == null && lookup(policy, "resource_attributes", null) != null)
18-
) && (policy.account_management != null || policy.resources != null || policy.resource_attributes != null) ? true :
19-
tobool("Values for `var.trusted_profile_policies[${i}].account_management`, `var.trusted_profile_policies[${i}].resource_attributes`, and `var.trusted_profile_policies[${i}].resources` are mutually exclusive.")
20-
]
21-
22-
# Transformation of maps
2311
policy_map = {
2412
for i, obj in var.trusted_profile_policies :
2513
"${var.trusted_profile_name}-${i}" => {
@@ -106,49 +94,6 @@ resource "ibm_iam_trusted_profile_policy" "policy" {
10694
}
10795

10896
locals {
109-
# tflint-ignore: terraform_unused_declarations
110-
validate_claim_type = var.trusted_profile_claim_rules == null ? [] : [
111-
for i, claim in var.trusted_profile_claim_rules : (
112-
contains(["Profile-SAML", "Profile-CR"], claim.type) ? true : tobool("Value for `var.trusted_profile_claim_rules[${i}].type must be either `Profile-SAML` or `Profile-CR`.")
113-
)
114-
]
115-
# tflint-ignore: terraform_unused_declarations
116-
validate_claim_condition_operator = var.trusted_profile_claim_rules == null ? [] : [
117-
for i, claim in var.trusted_profile_claim_rules : [
118-
for j, condition in claim.conditions : (
119-
contains(["EQUALS", "NOT_EQUALS", "EQUALS_IGNORE_CASE", "NOT_EQUALS_IGNORE_CASE", "CONTAINS", "IN"], condition.operator) ?
120-
true : tobool("Value for `var.trusted_profile_claim_rules[${i}].conditions[${j}].operator` must be one of the following: `EQUALS`, `NOT_EQUALS`, `EQUALS_IGNORE_CASE`, `NOT_EQUALS_IGNORE_CASE`, `CONTAINS`, `IN`.")
121-
)
122-
]
123-
]
124-
# tflint-ignore: terraform_unused_declarations
125-
validate_claim_cr_type = var.trusted_profile_claim_rules == null ? [] : [
126-
for i, claim in var.trusted_profile_claim_rules :
127-
lookup(claim, "cr_type", null) == null ? true : (
128-
claim.type == "Profile-CR" ? true : tobool("Value for `var.trusted_profile_claim_rules[${i}].cr_type` should only be provided when `var.trusted_profile_claim_rules[${i}].type` is `Profile-CR`.")
129-
)
130-
]
131-
# tflint-ignore: terraform_unused_declarations
132-
validate_claim_cr_type_matches = var.trusted_profile_claim_rules == null ? [] : [
133-
for i, claim in var.trusted_profile_claim_rules :
134-
lookup(claim, "cr_type", null) == null ? true : (
135-
contains(["VSI", "IKS_SA", "ROKS_SA"], claim.cr_type) ? true : tobool("Value for `var.trusted_profile_claim_rules[${i}].cr_type` must be one of the following: `VSI`, `IKS_SA`, `ROKS_SA`.")
136-
)
137-
]
138-
# tflint-ignore: terraform_unused_declarations
139-
validate_claim_expiration = var.trusted_profile_claim_rules == null ? [] : [
140-
for i, claim in var.trusted_profile_claim_rules :
141-
lookup(claim, "expiration", null) == null ? true : (
142-
claim.type == "Profile-SAML" ? true : tobool("Value for `var.trusted_profile_claim_rules[${i}].expiration` should only be provided when `var.trusted_profile_claim_rules[${i}].type` is `Profile-SAML`.")
143-
)
144-
]
145-
# tflint-ignore: terraform_unused_declarations
146-
validate_claim_realm_name = var.trusted_profile_claim_rules == null ? [] : [
147-
for i, claim in var.trusted_profile_claim_rules :
148-
lookup(claim, "realm_name", null) == null ? true : (
149-
claim.type == "Profile-SAML" ? true : tobool("Value for `var.trusted_profile_claim_rules[${i}].realm_name` should only be provided when `var.trusted_profile_claim_rules[${i}].type` is `Profile-SAML`.")
150-
)
151-
]
15297
claim_map = var.trusted_profile_claim_rules == null ? {} : {
15398
for i, obj in var.trusted_profile_claim_rules :
15499
"${var.trusted_profile_name}-${i}" => {
@@ -186,29 +131,6 @@ resource "ibm_iam_trusted_profile_claim_rule" "claim_rule" {
186131
}
187132

188133
locals {
189-
# tflint-ignore: terraform_unused_declarations
190-
validate_link_cr_type = var.trusted_profile_links == null ? [] : [
191-
for i, link in var.trusted_profile_links :
192-
contains(["VSI", "IKS_SA", "ROKS_SA"], link.cr_type) ? true :
193-
tobool("Value for `var.trusted_profile_links[${i}].cr_type must be one of the following: `VSI`, `IKS_SA`, `ROKS_SA`.")
194-
]
195-
# tflint-ignore: terraform_unused_declarations
196-
validate_link_namespace = var.trusted_profile_links == null ? [] : [
197-
for i, link in var.trusted_profile_links : [
198-
for j, obj in link.links : (
199-
(lookup(obj, "namespace", null) == null && link.cr_type == "VSI") || link.cr_type == "ROKS_SA" || link.cr_type == "IKS_SA" ? true :
200-
tobool("Value for `var.trusted_profile_links[${i}].link[${j}].namespace` should only be provided if `var.trusted_profile_links[${i}].cr_type` is `IKS_SA` or `ROKS_SA`.")
201-
)
202-
]
203-
]
204-
# tflint-ignore: terraform_unused_declarations
205-
validate_link_name = var.trusted_profile_links == null ? [] : [
206-
for i, link in var.trusted_profile_links : [
207-
for j, obj in link.links :
208-
(lookup(obj, "name", null) == null && link.cr_type == "VSI") || link.cr_type == "ROKS_SA" || link.cr_type == "IKS_SA" ? true :
209-
tobool("Value for `var.trusted_profile_links[${i}].link[${j}].name` should only be provided if `var.trusted_profile_links[${i}].cr_type` is `IKS_SA` or `ROKS_SA`.")
210-
]
211-
]
212134
link_map = var.trusted_profile_links == null ? {} : merge([
213135
for i, obj in var.trusted_profile_links : {
214136
for j, link in obj.links :

tests/other_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,21 @@ func TestRunBasicExample(t *testing.T) {
2929
assert.Nil(t, err, "This should not have errored")
3030
assert.NotNil(t, output, "Expected some output")
3131
}
32+
33+
func TestRunTemplateExample(t *testing.T) {
34+
35+
options := setupTemplateOptions(t, "tp-template", templateExampleDir)
36+
output, err := options.RunTestConsistency()
37+
assert.Nil(t, err, "This should not have errored")
38+
assert.NotNil(t, output, "Expected some output")
39+
}
40+
41+
func TestRunTemplateUpgrade(t *testing.T) {
42+
43+
options := setupTemplateOptions(t, "tp-template-upg", templateExampleDir)
44+
output, err := options.RunTestUpgrade()
45+
if !options.UpgradeTestSkipped {
46+
assert.Nil(t, err, "This should not have errored")
47+
assert.NotNil(t, output, "Expected some output")
48+
}
49+
}

tests/pr_test.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,3 @@ func TestRunUpgradeExample(t *testing.T) {
5757
assert.NotNil(t, output, "Expected some output")
5858
}
5959
}
60-
61-
func TestRunTemplateExample(t *testing.T) {
62-
63-
options := setupTemplateOptions(t, "tp-template", templateExampleDir)
64-
output, err := options.RunTestConsistency()
65-
assert.Nil(t, err, "This should not have errored")
66-
assert.NotNil(t, output, "Expected some output")
67-
}
68-
69-
func TestRunTemplateUpgrade(t *testing.T) {
70-
71-
options := setupTemplateOptions(t, "tp-template-upg", templateExampleDir)
72-
output, err := options.RunTestUpgrade()
73-
if !options.UpgradeTestSkipped {
74-
assert.Nil(t, err, "This should not have errored")
75-
assert.NotNil(t, output, "Expected some output")
76-
}
77-
}

variables.tf

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ variable "trusted_profile_policies" {
8282
pattern = optional(string)
8383
}))
8484
description = "A list of Trusted Profile Policy objects that are applied to the Trusted Profile created by the module."
85+
86+
87+
validation {
88+
condition = alltrue([
89+
for i, policy in var.trusted_profile_policies : (
90+
length(compact([
91+
(lookup(policy, "account_management", null) != null ? "account_management" : null),
92+
(lookup(policy, "resources", null) != null ? "resources" : null),
93+
(lookup(policy, "resource_attributes", null) != null ? "resource_attributes" : null)
94+
])) == 1
95+
)
96+
])
97+
error_message = "Each trusted_profile_policy must have exactly one of `account_management`, `resources`, or `resource_attributes` set and non-null. These are mutually exclusive."
98+
}
99+
100+
85101
}
86102

87103
variable "trusted_profile_claim_rules" {
@@ -104,7 +120,77 @@ variable "trusted_profile_claim_rules" {
104120

105121
description = "A list of Trusted Profile Claim Rule objects that are applied to the Trusted Profile created by the module."
106122

107-
default = null
123+
default = []
124+
125+
validation {
126+
condition = var.trusted_profile_claim_rules == null ? true : (
127+
length([
128+
for i, claim in var.trusted_profile_claim_rules : (
129+
contains(["Profile-SAML", "Profile-CR"], claim.type)
130+
)
131+
]) == length(var.trusted_profile_claim_rules)
132+
)
133+
error_message = "Each value in `var.trusted_profile_claim_rules.type` must be either `Profile-SAML` or `Profile-CR`."
134+
}
135+
136+
validation {
137+
condition = (
138+
alltrue(flatten([
139+
for claim in var.trusted_profile_claim_rules : [
140+
for condition in claim.conditions :
141+
contains(["EQUALS", "NOT_EQUALS", "EQUALS_IGNORE_CASE", "NOT_EQUALS_IGNORE_CASE", "CONTAINS", "IN"], condition.operator)
142+
]
143+
]))
144+
)
145+
error_message = "Each item in `var.trusted_profile_claim_rules.conditions.operator` must be one of the following: `EQUALS`, `NOT_EQUALS`, `EQUALS_IGNORE_CASE`, `NOT_EQUALS_IGNORE_CASE`, `CONTAINS`, `IN`."
146+
}
147+
148+
validation {
149+
condition = (
150+
var.trusted_profile_claim_rules == null ? true :
151+
alltrue([
152+
for i, claim in var.trusted_profile_claim_rules :
153+
!(try(claim.cr_type != null && claim.type != "Profile-CR", false))
154+
])
155+
)
156+
error_message = "Field `cr_type` should only be set when `type` is `Profile-CR`."
157+
}
158+
159+
validation {
160+
condition = (
161+
var.trusted_profile_claim_rules == null ? true :
162+
alltrue([
163+
for claim in var.trusted_profile_claim_rules :
164+
claim.cr_type == null || try(contains(["VSI", "IKS_SA", "ROKS_SA"], claim.cr_type), false)
165+
])
166+
)
167+
error_message = "If `cr_type` is provided, it must be one of: `VSI`, `IKS_SA`, `ROKS_SA`."
168+
}
169+
170+
validation {
171+
condition = (
172+
var.trusted_profile_claim_rules == null ? true :
173+
alltrue([
174+
for claim in var.trusted_profile_claim_rules :
175+
(
176+
claim.expiration == null || claim.type == "Profile-SAML"
177+
)
178+
])
179+
)
180+
error_message = "If `expiration` is provided, then `type` must be `Profile-SAML`."
181+
}
182+
183+
184+
validation {
185+
condition = (
186+
var.trusted_profile_claim_rules == null ? true :
187+
alltrue([
188+
for claim in var.trusted_profile_claim_rules :
189+
claim.realm_name == null || claim.type == "Profile-SAML"
190+
])
191+
)
192+
error_message = "If `realm_name` is provided, then `type` must be `Profile-SAML`."
193+
}
108194
}
109195

110196
variable "trusted_profile_links" {
@@ -123,5 +209,45 @@ variable "trusted_profile_links" {
123209

124210
description = "A list of Trusted Profile Link objects that are applied to the Trusted Profile created by the module."
125211

126-
default = null
212+
default = []
213+
214+
validation {
215+
condition = (
216+
var.trusted_profile_links == null || alltrue([
217+
for link in var.trusted_profile_links :
218+
contains(["VSI", "IKS_SA", "ROKS_SA"], link.cr_type)
219+
])
220+
)
221+
error_message = "Each `cr_type` in `trusted_profile_links` must be one of the following: `VSI`, `IKS_SA`, `ROKS_SA`."
222+
}
223+
224+
validation {
225+
condition = (
226+
var.trusted_profile_links == null || alltrue(flatten([
227+
for link in var.trusted_profile_links : [
228+
for obj in link.links :
229+
(
230+
(lookup(obj, "namespace", null) == null && link.cr_type == "VSI") ||
231+
(link.cr_type == "ROKS_SA" || link.cr_type == "IKS_SA")
232+
)
233+
]
234+
]))
235+
)
236+
error_message = "A `namespace` in `links` should only be provided if `cr_type` is `IKS_SA` or `ROKS_SA`."
237+
}
238+
239+
240+
validation {
241+
condition = (
242+
var.trusted_profile_links == null || alltrue(flatten([
243+
for i, link in var.trusted_profile_links : [
244+
for j, obj in link.links :
245+
(lookup(obj, "name", null) == null && link.cr_type == "VSI") || link.cr_type == "ROKS_SA" || link.cr_type == "IKS_SA"
246+
]
247+
]))
248+
)
249+
error_message = "A `name` in `links` should only be provided if `cr_type` is `IKS_SA` or `ROKS_SA`."
250+
}
251+
252+
127253
}

version.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
terraform {
2-
required_version = ">= 1.3.0"
2+
required_version = ">= 1.9.0"
33
# If your module requires any terraform providers, uncomment the "required_providers" section below and add all required providers.
44
# Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions.
55

0 commit comments

Comments
 (0)