How add standard attributes with space contain - terraform

standard attributes
how to add
given name
family name
schema {
attribute_data_type = "Sring"
developer_only_attribute = false
mutable = false
name = "famil name"
required = false
string_attribute_constraints {
min_length = 7
max_length = 150
}

Related

How to convert list to map in terraform?

string vals=var.vals // which will contain string in the format below
//"hr:recruitment,department:human,tool:sap,fruit:apple"
labels={
hostname=var.hostname
monitored=var.monitored
customer=var.cust1
machine-type=var.machinetype
}
I need to set labels(key,value) pairs for google_compute_instance by combining the above 2 properties to form a map.
So i converted vals to list by this code split(",",var.vals)
This gives me a list
tolist([
"hr:recruitment",
"department:human",
"tool:sap",
"fruit:apple",
])
Expected Output consisting of only map(string) combining labels and vals
labels:
{
hostname:var.hostname
monitored:var.monitored
customer:var.cust1
machine-type:var.machinetype
hr:"recruitment",
department:"human",
tool:"sap",
fruit:"apple"
}
How to convert this list to a map and combine it with labels?
I tried below & it seems to be working but it heavily relies on data quality of vals string (shouldn't contain duplicate keys). At it's core it relies on zipmap to build the map from keys & values lists.
// Having vals as a string variable
variable "vals" {
description = "The name of availability set"
type = string
default = "hr:recruitment,department:human,tool:sap,fruit:apple"
}
// hostname, monitored, cust1 & machinetype vars
variable "hostname" {
type = string
default = "dummy.net"
}
variable "monitored" {
type = bool
default = true
}
variable "cust1" {
type = string
default = "xyz"
}
variable "machinetype" {
type = string
default = "linux"
}
locals {
// parsing locally to split the vals string to fetch the keys
keys = [
for s in split(",", var.vals) : split(":", s)[0]
]
// parsing locally to split the vals string to fetch the values
values = [
for s in split(",", var.vals) : split(":", s)[1]
]
//I used labels also as vars
labels = {
hostname = var.hostname
monitored = var.monitored
customer = var.cust1
machine-type = var.machinetype
}
}
// Finally, zipmap to construct map from keys & values & merge with local.labels
output "final_map" {
value = merge(local.labels, zipmap(local.keys, local.values))
}
Finally, the output looks like below ::
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
final_map = {
"customer" = "xyz"
"department" = "human"
"fruit" = "apple"
"hostname" = "dummy.net"
"hr" = "recruitment"
"machine-type" = "linux"
"monitored" = true
"tool" = "sap"
}

Update Terraform map function to "tomap"

I inherited some older TF code and I noticed that some of the code is using deprecated functions like map(object){}. I would like to update this code since map is no longer used as per this document.
Here is an excerpt from the old code:
variable "application_gateways" {
type = map(object({
name = string
webapp_firewall_policy_key = string
zones = list(string)
enable_http2 = bool
sku = object({
name = string
tier = string
capacity = number
})
Can I update it using tomap like this or is it more complicated?
variable "application_gateways" {
type = tomap({
name = string
webapp_firewall_policy_key = string
zones = list(string)
enable_http2 = bool
sku = object({
name = string
tier = string
capacity = number
})
Yes, that is all you need to do.
No further config is needed.
I think we need to use just 'object' keyword outside as well:
variable "application_gateways" {
type = object({
variable "application_gateways" {
type = object({
name = string
webapp_firewall_policy_key = string
zones = list(string)
enable_http2 = bool
sku = object({
name = string
tier = string
capacity = number
})
})

Terraform Loop with Range

Is there a way to loop through a range or list for a variable in terraform.
Below is what I would like to accomplish but I am not sure how to do it.
module "vlan_list" {
depends_on = [module.vlan_pools]
source = "../modules/add_vlans"
vlan_list = {
for i in range(1,100): {
"access" = {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = i
to = i
}
}
}
}
Let me add more information to it because unfortunately that didn't work. I get:
Error: Invalid value for module argument
on pools_vlan.tf line 34, in module "vlan_list":
34: vlan_list = {
35: for i in range(1, 100):
36: "access" => {
37: vlan_pool = module.vlan_pools.vlan_pool["access"]
38: from = i
39: to = i
40: }...
41: }
The given value is not suitable for child module variable "vlan_list" defined
at ../modules/add_vlans/variables.tf:5,1-21: element "access": object
required.
So I have created a module with the following
resource "aci_ranges" "add_vlan" {
for_each = local.vlan_list
alloc_mode = each.value["alloc_mode"]
annotation = each.value["annotation"]
name_alias = each.value["name_alias"]
vlan_pool_dn = each.value["vlan_pool"]
role = each.value["role"]
from = "vlan-${each.value["from"]}"
to = "vlan-${each.value["to"]}"
}
From Here I have defined a variables file to make it so users don't have to enter every variable... they can accept defaults
terraform {
experiments = [module_variable_optional_attrs]
}
variable "vlan_list" {
description = "Add VLANs to VLAN Pools"
type = map(object({
alloc_mode = optional(string)
annotation = optional(string)
from = optional(number)
name_alias = optional(string)
role = optional(string)
to = optional(number)
vlan_pool = optional(string)
}))
}
locals {
vlan_list = {
for k, v in var.vlan_list : k => {
alloc_mode = coalesce(v.alloc_mode, "static")
annotation = (v.annotation != null ? v.annotation : "")
from = (v.from != null ? v.from : 1)
name_alias = (v.name_alias != null ? v.name_alias : "")
role = coalesce(v.role, "external")
to = coalesce(v.to, 1)
vlan_pool = (v.vlan_pool != null ? v.vlan_pool : "")
}
}
}
So what I shared above is what someone would enter to consume the module... Here is a more complete example that I would like to do:
module "vlan_list" {
depends_on = [module.vlan_pools]
source = "../modules/add_vlans"
vlan_list = {
for i in range(1, 100):
"access" => {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = i
to = i
}...
for i in ranges([1000-1200], [1300-1400]):
"vmm_dynamic" => {
alloc_mode = "dynamic"
vlan_pool = module.vlan_pools.vlan_pool["vmm_dynamic"]
from = i
to = i
}...
for i in list[4, 100, 101]:
"l3out" => {
vlan_pool = module.vlan_pools.vlan_pool["l3out"]
from = i
to = i
}...
}
}
I know the second range on the vmm_dynamic key is not correct at all... I am just trying to show what I would like to be able to do if possible.
When the resource creates the entries, from the API, if I do it in a range as shown below; if someone needed to change the range for the first pool (in example) to 1-50,52-99, it would delete the entry and re-create it. whereas if they are creating the entry with each entry being created individually it wouldn't delete all of the individual entries, optimally.
I can do the following and it works fine... but being able to add the VLANs individually from a loop would be preferable.
module "vlan_list" {
depends_on = [module.vlan_pools]
source = "../modules/add_vlans"
vlan_list = {
"access" = {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = 1
to = 99
},
"vmm_dynamic" = {
alloc_mode = "dynamic"
vlan_pool = module.vlan_pools.vlan_pool["vmm_dynamic"]
from = 1000
to = 1199
},
"l3out_1" = {
vlan_pool = module.vlan_pools.vlan_pool["l3out"]
from = 4
to = 4
},
"l3out_2" = {
vlan_pool = module.vlan_pools.vlan_pool["l3out"]
from = 100
to = 101
},
}
}
Thanks in advance for help on this.
Just as one more point of reference... This is how I had previously accomplished this with Python, but I am trying to move this to native Terraform
def vlan_list_full(vlan_list):
full_vlan_list = []
if re.search(r',', str(vlan_list)):
vlist = vlan_list.split(',')
for v in vlist:
if re.fullmatch('^\\d{1,4}\\-\\d{1,4}$', v):
a,b = v.split('-')
a = int(a)
b = int(b)
vrange = range(a,b+1)
for vl in vrange:
full_vlan_list.append(vl)
elif re.fullmatch('^\\d{1,4}$', v):
full_vlan_list.append(v)
elif re.search('\\-', str(vlan_list)):
a,b = vlan_list.split('-')
a = int(a)
b = int(b)
vrange = range(a,b+1)
for v in vrange:
full_vlan_list.append(v)
else:
full_vlan_list.append(vlan_list)
return full_vlan_list
def vlan_pool
for z in range(1, 3):
vgroup = 'VLAN_Grp%s' % (z)
vgrp = 'VGRP%s_Allocation' % (z)
templateVars['Allocation_Mode'] = templateVars[vgrp]
if re.search(r'\d+', str(templateVars[vgroup])):
vlan_list = vlan_list_full(templateVars[vgroup])
for v in vlan_list:
vlan = str(v)
if re.fullmatch(r'\d+', vlan):
templateVars['VLAN_ID'] = int(vlan)
# Add VLAN to VLAN Pool File
create_tf_file('a+', dest_dir, dest_file, template, **templateVars)
I can't seem to find any examples of how to do this without Python.
If you want to create a map with a single key of access and a list of values, then you can use ellipsis operator (...). Also your syntax is incorrect. Thus, the following should be used in this case:
vlan_list = {
for i in range(1, 100):
"access" => {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = i
to = i
}...
}
Here is how I recently accomplished what I asked above. It was about a year to figure it out but this is the way I could accomplish it.
# Map of Object input Variables is as shown below
variable "vlan_pools" {
default = {
"default" = {
alias = ""
allocation_mode = "dynamic"
description = ""
encap_blocks = {
"default" = {
allocation_mode = "inherit"
description = ""
role = "external"
vlan_range = "**REQUIRED**"
}
}
}
}
description = <<-EOT
key - name of the VLAN Pool
* alias: A changeable name for a given object. While the name of an object, once created, cannot be changed, the alias is a field that can be changed.
* allocation_mode: The allocation mode. The values can be:
- dynamic (default): Managed internally by the APIC to allocate VLANs for endpoint groups (EPGs). A vCenter Domain can associate only to a dynamic pool.
- static: One or more EPGs are associated with a domain, and that domain is associated with a static range of VLANs. You must configure statically deployed EPGs within that range of VLANs.
When you create VLAN ranges, you can also assign the allocation mode to be inherited from the parent.
* description: Description to add to the Object. The description can be up to 128 alphanumeric characters.
* encap_blocks:
- allocation_mode: The allocation mode. The values can be:
* dynamic: Managed internally by the APIC to allocate VLANs for endpoint groups (EPGs). A vCenter Domain can associate only to a dynamic pool.
* inherit (default): The inherited mode from the parent device.
* static: One or more EPGs are associated with a domain, and that domain is associated with a static range of VLANs. You must configure statically deployed EPGs within that range of VLANs.
- description: Description to add to the Object. The description can be up to 128 alphanumeric characters.
- role: Role of the VLAN range. The options are:
* external (Default): Used for allocating VLANs for each EPG assigned to the domain. The VLANs are used when packets are sent to or from leafs.
* Internal: Used for private VLAN allocations in the internal vSwitch by the Cisco ACI Virtual Edge (AVE). The VLANs are not seen outside the ESX host or on the wire.
- vlan_range: single vlan; i.e. 1. range of vlans; i.e. 1-5. Or List of Vlans; i.e. 1-5,10-15
EOT
type = map(object(
{
alias = optional(string)
allocation_mode = optional(string)
description = optional(string)
encap_blocks = map(object(
{
allocation_mode = optional(string)
description = optional(string)
role = optional(string)
vlan_range = string
}
))
}
))
}
# Which I then run some conditional modifications in locals to format the variables.
locals {
#__________________________________________________________
#
# VLAN Pools Variables
#__________________________________________________________
# This first loop is to handle optional attributes and return
# default values if the user doesn't enter a value.
vlan_pools = {
for k, v in var.vlan_pools : k => {
alias = v.alias != null ? v.alias : ""
allocation_mode = v.allocation_mode != null ? v.allocation_mode : "dynamic"
description = v.description != null ? v.description : ""
encap_blocks = v.encap_blocks != null ? v.encap_blocks : {}
}
}
# Loop 1 is to determine if the encap_blocks are:
# A Single number 1
# A Range of numbers 1-5
# A List of numbers 1-5,10-15
# And then to return these values as a list
vlan_ranges_loop_1 = flatten([
for key, value in local.vlan_pools : [
for k, v in value.encap_blocks : {
allocation_mode = v.allocation_mode != null ? v.allocation_mode : "inherit"
description = v.description != null ? v.description : ""
key1 = key
key2 = k
role = v.role != null ? v.role : "external"
vlan_split = length(regexall("-", v.vlan_range)) > 0 ? tolist(split(",", v.vlan_range)) : length(
regexall(",", v.vlan_range)) > 0 ? tolist(split(",", v.vlan_range)
) : [v.vlan_range]
vlan_range = v.vlan_range
}
]
])
# Loop 2 takes a list that contains a "-" or a "," and expands those values
# into a full list. So [1-5] becomes [1, 2, 3, 4, 5]
vlan_ranges_loop_2 = {
for k, v in local.vlan_ranges_loop_1 : "${v.key1}_${v.key2}" => {
allocation_mode = v.allocation_mode
description = v.description
key1 = v.key1
key2 = v.key2
role = v.role
vlan_list = length(regexall("(,|-)", jsonencode(v.vlan_range))) > 0 ? flatten([
for s in v.vlan_split : length(regexall("-", s)) > 0 ? [for v in range(tonumber(
element(split("-", s), 0)), (tonumber(element(split("-", s), 1)) + 1)
) : tonumber(v)] : [s]
]) : v.vlan_split
}
}
# Loop 3 will take the vlan_list created in Loop 2 and expand this
# out to a map of objects per vlan.
vlan_ranges_loop_3 = flatten([
for k, v in local.vlan_ranges_loop_2 : [
for s in v.vlan_list : {
allocation_mode = v.allocation_mode
description = v.description
key1 = v.key1
role = v.role
vlan = s
}
]
])
# And lastly loop3's list is converted back to a map of objects
vlan_ranges = { for k, v in local.vlan_ranges_loop_3 : "${v.key1}_${v.vlan}" => v }
# End of Local Loops
}
# And lastly these values are consumed by the resources with for_each loops.
resource "aci_vlan_pool" "vlan_pools" {
for_each = local.vlan_pools
alloc_mode = each.value.allocation_mode
description = each.value.description
name = each.key
name_alias = each.value.alias
}
resource "aci_ranges" "vlans" {
depends_on = [
aci_vlan_pool.vlan_pools
]
for_each = local.vlan_ranges
description = each.value.description
alloc_mode = each.value.allocation_mode
from = "vlan-${each.value.vlan}"
to = "vlan-${each.value.vlan}"
role = each.value.role
vlan_pool_dn = aci_vlan_pool.vlan_pools[each.value.key1].id
}
I am sure someone with more experience might be able to accomplish this with fewer steps in locals but this worked for me at least.

Alicloud CMS alarm not showing data

I have created alibaba cms alarm using terraform but it does not show any data. Below is my code.
resource "alicloud_cms_alarm" "scaleOut-alarm" {
contact_groups = ["example"]
dimensions = {
region = "shanghai"
queue = "queue"
}
enabled = true
metric = "ActiveMessages"
name = "alarm-name"
period = 300
project = "acs_mns_new"
silence_time = 300
operator = ">"
threshold = 300
statistics = "Average"
}
Any help will be appreciated.
this is basic example
resource "alicloud_cms_alarm" "basic" {
name = "tf-testAccCmsAlarm_basic"
project = "acs_ecs_dashboard"
metric = "disk_writebytes"
dimensions = {
instanceId = "i-bp1247,i-bp11gd"
device = "/dev/vda1,/dev/vdb1"
}
statistics = "Average"
period = 900
operator = "<="
threshold = 35
triggered_count = 2
contact_groups = ["test-group"]
effective_interval = "0:00-2:00"
notify_type = 1
webhook = "https://${data.alicloud_account.current.id}.eu-central-1.fc.aliyuncs.com/2016-08-15/proxy/Terraform/AlarmEndpointMock/"
}

Row BGCOLOR Sets for ENTIRE Dynamic Browse, not Just 1 Row

Using the ROW-DISPLAY trigger when creating a dynamic OpenEdge browse. The problem is, when the data is displayed, all rows have the BGCOLOR determined by the data buffer's content of the LAST row only. Never had this problem with a static browse.
Browse code looks like this:
CREATE BROWSE l-browse-wh IN WIDGET-POOL "pool"
ASSIGN X = 1
Y = l-browse-y
FONT = INT(get-fn("browsedat-fnt"))
HEIGHT-PIXELS = l-h
WIDTH-PIXELS = FRAME f-data:WIDTH-PIXELS - 20
QUERY = hQuery
HIDDEN = FALSE
ROW-HEIGHT-CHARS = 0.67
READ-ONLY = FALSE
ROW-MARKERS = FALSE
SEPARATORS = TRUE
COLUMN-RESIZABLE = TRUE
COLUMN-SCROLLING = TRUE
FIT-LAST-COLUMN = FALSE
SCROLLBAR-VERTICAL = FALSE
FRAME = FRAME f-data:HANDLE
VISIBLE = TRUE
SENSITIVE = TRUE
TRIGGERS:
ON ROW-DISPLAY
PERSISTENT RUN row-color-ip IN THIS-PROCEDURE.
END TRIGGERS.
PROCEDURE row-color-ip:
DEF VAR l-bgcolor AS INT NO-UNDO.
IF tt-sold.t-exclude-sw /* <-- always uses value from last browse row */
THEN ASSIGN l-bgcolor = 8.
ELSE ASSIGN l-bgcolor = 15.
FOR EACH tt-col-handles
NO-LOCK:
ASSIGN tt-col-handles.t-wh:BGCOLOR = l-bgcolor.
END. /* of "FOR EACH tt-col-handles" */
END PROCEDURE.
It's something with your code (the part you're not showing). I used 10.2B Windows and replicated your code, filling the blanks. This little program alternates the colors, as I expected.
DEFINE VARIABLE l-browse-wh AS HANDLE NO-UNDO.
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
define temp-table tt-sold
field cod as int
field name as char
field t-exclude-sw as logical.
create query hQuery.
hQuery:set-buffers(temp-table tt-sold:default-buffer-handle).
hQuery:query-prepare('for each tt-sold').
define temp-table tt-col-handles
field i as int
field t-wh as handle.
create widget-pool 'pool'.
define frame f-data with size 75 by 20.
CREATE BROWSE l-browse-wh IN WIDGET-POOL "pool"
ASSIGN X = 1
width = 60
height = 10
QUERY = hQuery
HIDDEN = FALSE
ROW-HEIGHT-CHARS = 0.67
READ-ONLY = FALSE
ROW-MARKERS = FALSE
SEPARATORS = TRUE
COLUMN-RESIZABLE = TRUE
COLUMN-SCROLLING = TRUE
FIT-LAST-COLUMN = FALSE
SCROLLBAR-VERTICAL = FALSE
FRAME = FRAME f-data:HANDLE
VISIBLE = TRUE
SENSITIVE = TRUE
TRIGGERS:
ON ROW-DISPLAY
PERSISTENT RUN row-color-ip IN THIS-PROCEDURE.
END TRIGGERS.
create tt-sold.
assign tt-sold.cod = 1 tt-sold.name = 'ABC' tt-sold.t-exclude-sw = yes.
create tt-sold.
assign tt-sold.cod = 2 tt-sold.name = 'DEF' tt-sold.t-exclude-sw = no.
create tt-sold.
assign tt-sold.cod = 3 tt-sold.name = 'GHI' tt-sold.t-exclude-sw = yes.
create tt-sold.
assign tt-sold.cod = 4 tt-sold.name = 'JKL' tt-sold.t-exclude-sw = no.
create tt-col-handles.
assign tt-col-handles.i = 1 tt-col-handles.t-wh = l-browse-wh:add-like-column('tt-sold.cod').
create tt-col-handles.
assign tt-col-handles.i = 2 tt-col-handles.t-wh = l-browse-wh:add-like-column('tt-sold.name').
create tt-col-handles.
assign tt-col-handles.i = 3 tt-col-handles.t-wh = l-browse-wh:add-like-column('tt-sold.t-exclude-sw').
hQuery:query-open().
l-browse-wh:refresh().
wait-for close of this-procedure.
PROCEDURE row-color-ip:
DEF VAR l-bgcolor AS INT NO-UNDO.
IF tt-sold.t-exclude-sw /* <-- always uses value from last browse row */
THEN ASSIGN l-bgcolor = 8.
ELSE ASSIGN l-bgcolor = 15.
FOR EACH tt-col-handles
NO-LOCK:
ASSIGN tt-col-handles.t-wh:BGCOLOR = l-bgcolor.
END. /* of "FOR EACH tt-col-handles" */
END PROCEDURE.
I apologize for the large chunk, but I couldn't just put my finger on where you're going wrong. Maybe this example will help you in some way. Hope it helps!

Resources