SlideShare ist ein Scribd-Unternehmen logo
1 von 41
Downloaden Sie, um offline zu lesen
Lead DevOps Engineer - Salesforce
Robert Blumen
The 'Data,
Transformations,
Resources' Pattern in
Terraform
Outline
● Terraform anti-patterns
● New features in versions 12 and 13
● The "Data + Transforms + Resources" Pattern
What Terraform 11 Can Not Do
● Looping
● Conditional
● Nested loops
● Data structures
Data Types in Terraform
12 & 13
structured data types
● list
● map
● set
● tuple
● object
list(string)
list(tuple[string,number,bool])
map(string)
map(object({ id=string, cidr_block=string }))
composition of data types
variable group_members {
type = list(string)
description = "list of emails of the group members"
}
example
variable people {
type = list(object({ name=string, age=number }))
default = [
{
name = "John"
age = 32
}
]
}
type checking (continued)
~/Devel/devops-tools (rblumen) $ /opt/hashi/terraform-0.12.20 
apply -var 'people=[ { name="Job", age=71 } ]'
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
~/Devel/devops-tools (rblumen) $ /opt/hashi/terraform-0.12.20 
apply -var 'people=[ { name="Job", age=true } ]'
Error: Invalid value for input variable
The argument -var="people=..." does not contain a valid value for variable
"people": element 0: attribute "name": string required.
groups = [
{
"key" : "value"
},
{
"key-2": "value-2"
}
]
all_groups = merge(local.groups...)
###
{
"key": "value",
"key-2": "value"
}
python-style splatting
Collections and
Iterations
terraform 11 - indexed lists
resource providerX web_thing {
count = var.num_servers
name = element(var.server_names,count.index)
}
#####
web_thing[0]
web_thing[1]
web_thing[2]
web_thing[3]
locals {
server_names = [ "db", "front-end", "back-end" ]
}
terraform 12+ - maps
web_srv["db"]
web_srv["front-end"]
web_srv["back-end"]
resource providerY web_srv {
for_each = toset(var.server_names)
name = each.value
}
old - (count based):
aws_iam_policy.aws_admin_access[3]
new - (for_each):
aws_iam_policy.aws_admin_access["AmazonS3FullAccess"]
indexing
locals {
administrator_policies = [
"AmazonEC2FullAccess",
"AmazonS3FullAccess",
"AWSKeyManagementServicePowerUser",
"AWSLambdaFullAccess",
]
}
data aws_iam_policy aws_admin_access {
for_each = toset(local.administrator_policies)
arn = "arn:aws:iam::aws:policy/${each.value}"
}
for_each - iterating over a list
resource heroku_app_feature app_feature {
for_each = {
for f, e in {
spaces-tls-legacy : false,
spaces-tls-modern : true
spaces-strict-tls : false
} :
f => e
}
app = heroku_app.app.name
name = each.key
enabled = each.value
}
for_each - iterating over a map
data aws_iam_policy_document access {
for_each = toset(local.groups)
statement {
effect = "Allow"
actions = ["s3:PutObject", ]
resources = data.aws_s3_bucket.devel.arn
}
}
chaining iteration
resource aws_iam_policy access {
for_each = data.aws_iam_policy_document.access
name = "${each.key}Access"
policy = each.value.json
}
resource aws_iam_group_policy_attachment group_access {
for_each = aws_iam_policy.access
group = each.key
policy_arn = each.value.arn
}
● 12: for_each does not work with modules
● 13: for_each supports modules
terraform 12 versus 13
set operations
functions on sets
● setintersection
● setproduct
● setsubtract
● setunion
locals {
all_groups = toset([ "dev", "core", "admin", "ops", "chat" ])
some_groups = toset(["dev", "voice"])
other_groups = setsubtract(all_groups, some_groups) # in 12.21
}
resource aws_iam_group groups {
for_each = local.all_groups
name = each.value
}
resource aws_thing thing_one {
for_each = local.some_groups
group = aws_iam_group.groups[each.value]
}
resource aws_thing thing_two {
for_each = local.other_groups
group = aws_iam_group.groups[each.value]
}
implementing conditionals with sets
locals {
test_envs = [ "test1", "test2" ]
}
resource saas_thing_one test_only {
foreach = setintersection(toset([var.environment]), local.test_envs)
…
}
conditionals (2)
for expressions
for expressions
users = [ "achman", "aziss", "bwong", "cshah", ]
# list
emails = [
for u in local.users : "${replace(u, "-", ".")}@pagerduty.com"
]
# map
emails_by_user = {
for u in local.users :
u => "${replace(u, "-", ".")}@pagerduty.com"
}
[for s in var.list :
upper(s)
if s != ""]
for expressions - conditionals
var user_email_assn {
type = map(string)
default = { ... }
}
local {
labels = [ for user, email in var.user_email_assn: "${user}:${email} ]
}
for expressions - map
{
for s in [ "abc", "def", "aef", "dps" ] :
substr(s, 0, 1) => s...
}
{
"a" = [
"abc",
"aef",
]
"d" = [
"def",
"dps",
]
}
for expressions - group by
putting it together
resource backend_foo left_hand_thing {
for_each = ...
}
resource backend_bar right_hand_thing {
for_each = ..
}
resource backend_foo_bar left_right_assn {
for_each = ??
left_hand_thing = each.value.left
right_hand_thing = each.value.right
}
many-to-many
# groups have multiple members
# user may belong to more than one group
resource pagerduty_user { … }
resource pagerduty_team { … }
resource pagerduty_team_membership {
for_each = ??
user_id = ??
team_id = ??
}
example: PagerDuty
for g in groups {
create group
for u in groups.users {
create user
create create user_group_membership
}
}
conventional imperative language
locals {
on_call_teams = {
tier_1 = [ "abe", "jaxel", "beldon" ]
tier_2 = [ "abe", "janpax", "fanlo" ]
escalation = [ "adam", "shefty", "fanlo" ]
}
}
terraform solution
resource pagerduty_team teams {
for_each = keys(local.on_call_teams)
name = each.value
}
resource pagerduty_user users {
for_each = distinct(flatten(values(local.on_call_teams)))
name = each.value
email = "${each.value}@companyx.com"
}
locals {
team_user_pairs = [
for team, users in local.on_call_teams: [
for for user in users: {
user: user
team: team
}
]
]
team_users = {
for pair in flatten(local.team_user_pairs):
"${pair.team}-${pair.user}" => {
team_id: pagerduty_team[pair.team].id,
user_id: pagerduty_user[pair.user].id
}
}
}
resource pagerduty_team_membership membership {
for_each = local.team_users
team_id = each.value.team_id
user_id = each.value.user_id
}
locals {
on_call_teams = {
tier_1 = [ "abe", "jaxel", "beldon" ]
tier_2 = [ "abe", "janpax", "fanlo" ]
escalation = [ "adam", "shefty", "fanlo" ]
}
}
###
resource saas_team_membership membership {
for_each = ??
user = each.key
groups = each.value
}
one:many inverting
user_group_pairs = flatten([
for group, members in local.group_memberships : [
for user in members : {
user = user
group = group
}
]
])
groups_by_user = {
for pair in local.user_group_pairs :
pair.user => pair.group...
}
}
resource saas_team_membership membership {
for_each = local.groups_by_user
user = each.key
groups = each.value
}
The
"Data
+ Transformations
+ Resources"
Pattern
objectives
● understandable
● easy to change
● economical (DRY)
● data
○ structure according to your domain
○ use data structures
○ normalize/minimize duplication
○ optimize for frequent changes
● transform
○ use for, if and set functions
○ inputs: your data
○ outputs: what your provider's resources need
● resources
○ create each resource once
○ chain resources
pattern for code organization
Thank You

Weitere ähnliche Inhalte

Was ist angesagt?

Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)
Leonardo Soto
 

Was ist angesagt? (19)

MongoDB
MongoDB MongoDB
MongoDB
 
Apache Spark - Key-Value RDD | Big Data Hadoop Spark Tutorial | CloudxLab
Apache Spark - Key-Value RDD | Big Data Hadoop Spark Tutorial | CloudxLabApache Spark - Key-Value RDD | Big Data Hadoop Spark Tutorial | CloudxLab
Apache Spark - Key-Value RDD | Big Data Hadoop Spark Tutorial | CloudxLab
 
The Aggregation Framework
The Aggregation FrameworkThe Aggregation Framework
The Aggregation Framework
 
Is there a perfect data-parallel programming language? (Experiments with More...
Is there a perfect data-parallel programming language? (Experiments with More...Is there a perfect data-parallel programming language? (Experiments with More...
Is there a perfect data-parallel programming language? (Experiments with More...
 
Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)Pragmatic Real-World Scala (short version)
Pragmatic Real-World Scala (short version)
 
Python for Data Science and Scientific Computing
Python for Data Science and Scientific ComputingPython for Data Science and Scientific Computing
Python for Data Science and Scientific Computing
 
Should I Use Scalding or Scoobi or Scrunch?
Should I Use Scalding or Scoobi or Scrunch? Should I Use Scalding or Scoobi or Scrunch?
Should I Use Scalding or Scoobi or Scrunch?
 
Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)Jython: Python para la plataforma Java (EL2009)
Jython: Python para la plataforma Java (EL2009)
 
Spark Dataframe - Mr. Jyotiska
Spark Dataframe - Mr. JyotiskaSpark Dataframe - Mr. Jyotiska
Spark Dataframe - Mr. Jyotiska
 
Scalding - Hadoop Word Count in LESS than 70 lines of code
Scalding - Hadoop Word Count in LESS than 70 lines of codeScalding - Hadoop Word Count in LESS than 70 lines of code
Scalding - Hadoop Word Count in LESS than 70 lines of code
 
JS OO and Closures
JS OO and ClosuresJS OO and Closures
JS OO and Closures
 
30 分鐘學會實作 Python Feature Selection
30 分鐘學會實作 Python Feature Selection30 分鐘學會實作 Python Feature Selection
30 分鐘學會實作 Python Feature Selection
 
PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007PHP and MySQL Tips and tricks, DC 2007
PHP and MySQL Tips and tricks, DC 2007
 
Advanced Django ORM techniques
Advanced Django ORM techniquesAdvanced Django ORM techniques
Advanced Django ORM techniques
 
Data profiling with Apache Calcite
Data profiling with Apache CalciteData profiling with Apache Calcite
Data profiling with Apache Calcite
 
Django Pro ORM
Django Pro ORMDjango Pro ORM
Django Pro ORM
 
Advanced geoprocessing with Python
Advanced geoprocessing with PythonAdvanced geoprocessing with Python
Advanced geoprocessing with Python
 
ORM in Django
ORM in DjangoORM in Django
ORM in Django
 
Chris Mc Glothen Sql Portfolio
Chris Mc Glothen Sql PortfolioChris Mc Glothen Sql Portfolio
Chris Mc Glothen Sql Portfolio
 

Ähnlich wie Patterns in Terraform 12+13: Data, Transformations and Resources

Introduction to R
Introduction to RIntroduction to R
Introduction to R
agnonchik
 

Ähnlich wie Patterns in Terraform 12+13: Data, Transformations and Resources (20)

WordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPress
 
India software developers conference 2013 Bangalore
India software developers conference 2013 BangaloreIndia software developers conference 2013 Bangalore
India software developers conference 2013 Bangalore
 
Functional es6
Functional es6Functional es6
Functional es6
 
Dynamic languages, for software craftmanship group
Dynamic languages, for software craftmanship groupDynamic languages, for software craftmanship group
Dynamic languages, for software craftmanship group
 
Scala
ScalaScala
Scala
 
DataMapper
DataMapperDataMapper
DataMapper
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
React.js Basics - ConvergeSE 2015
React.js Basics - ConvergeSE 2015React.js Basics - ConvergeSE 2015
React.js Basics - ConvergeSE 2015
 
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
Icsug dev day2014_road to damascus - conversion experience-lotusscript and @f...
 
Where's My SQL? Designing Databases with ActiveRecord Migrations
Where's My SQL? Designing Databases with ActiveRecord MigrationsWhere's My SQL? Designing Databases with ActiveRecord Migrations
Where's My SQL? Designing Databases with ActiveRecord Migrations
 
Groovy On Trading Desk (2010)
Groovy On Trading Desk (2010)Groovy On Trading Desk (2010)
Groovy On Trading Desk (2010)
 
Thinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in PythonThinking in Functions: Functional Programming in Python
Thinking in Functions: Functional Programming in Python
 
Professional-grade software design
Professional-grade software designProfessional-grade software design
Professional-grade software design
 
Querying your database in natural language by Daniel Moisset PyData SV 2014
Querying your database in natural language by Daniel Moisset PyData SV 2014Querying your database in natural language by Daniel Moisset PyData SV 2014
Querying your database in natural language by Daniel Moisset PyData SV 2014
 
Quepy
QuepyQuepy
Quepy
 
Introduction to R
Introduction to RIntroduction to R
Introduction to R
 
Using Scala Slick at FortyTwo
Using Scala Slick at FortyTwoUsing Scala Slick at FortyTwo
Using Scala Slick at FortyTwo
 
The journey of an (un)orthodox optimization
The journey of an (un)orthodox optimizationThe journey of an (un)orthodox optimization
The journey of an (un)orthodox optimization
 
PGConf APAC 2018 - Lightening Talk #2 - Centralizing Authorization in PostgreSQL
PGConf APAC 2018 - Lightening Talk #2 - Centralizing Authorization in PostgreSQLPGConf APAC 2018 - Lightening Talk #2 - Centralizing Authorization in PostgreSQL
PGConf APAC 2018 - Lightening Talk #2 - Centralizing Authorization in PostgreSQL
 
Centralising Authorisation in PostgreSQL
Centralising Authorisation in PostgreSQLCentralising Authorisation in PostgreSQL
Centralising Authorisation in PostgreSQL
 

Kürzlich hochgeladen

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 

Kürzlich hochgeladen (20)

Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 

Patterns in Terraform 12+13: Data, Transformations and Resources

  • 1. Lead DevOps Engineer - Salesforce Robert Blumen The 'Data, Transformations, Resources' Pattern in Terraform
  • 2. Outline ● Terraform anti-patterns ● New features in versions 12 and 13 ● The "Data + Transforms + Resources" Pattern
  • 3. What Terraform 11 Can Not Do ● Looping ● Conditional ● Nested loops ● Data structures
  • 4. Data Types in Terraform 12 & 13
  • 5. structured data types ● list ● map ● set ● tuple ● object
  • 7. variable group_members { type = list(string) description = "list of emails of the group members" } example
  • 8. variable people { type = list(object({ name=string, age=number })) default = [ { name = "John" age = 32 } ] } type checking (continued)
  • 9. ~/Devel/devops-tools (rblumen) $ /opt/hashi/terraform-0.12.20 apply -var 'people=[ { name="Job", age=71 } ]' Apply complete! Resources: 0 added, 0 changed, 0 destroyed. ~/Devel/devops-tools (rblumen) $ /opt/hashi/terraform-0.12.20 apply -var 'people=[ { name="Job", age=true } ]' Error: Invalid value for input variable The argument -var="people=..." does not contain a valid value for variable "people": element 0: attribute "name": string required.
  • 10. groups = [ { "key" : "value" }, { "key-2": "value-2" } ] all_groups = merge(local.groups...) ### { "key": "value", "key-2": "value" } python-style splatting
  • 12. terraform 11 - indexed lists resource providerX web_thing { count = var.num_servers name = element(var.server_names,count.index) } ##### web_thing[0] web_thing[1] web_thing[2] web_thing[3]
  • 13. locals { server_names = [ "db", "front-end", "back-end" ] } terraform 12+ - maps web_srv["db"] web_srv["front-end"] web_srv["back-end"] resource providerY web_srv { for_each = toset(var.server_names) name = each.value }
  • 14. old - (count based): aws_iam_policy.aws_admin_access[3] new - (for_each): aws_iam_policy.aws_admin_access["AmazonS3FullAccess"] indexing
  • 15. locals { administrator_policies = [ "AmazonEC2FullAccess", "AmazonS3FullAccess", "AWSKeyManagementServicePowerUser", "AWSLambdaFullAccess", ] } data aws_iam_policy aws_admin_access { for_each = toset(local.administrator_policies) arn = "arn:aws:iam::aws:policy/${each.value}" } for_each - iterating over a list
  • 16. resource heroku_app_feature app_feature { for_each = { for f, e in { spaces-tls-legacy : false, spaces-tls-modern : true spaces-strict-tls : false } : f => e } app = heroku_app.app.name name = each.key enabled = each.value } for_each - iterating over a map
  • 17. data aws_iam_policy_document access { for_each = toset(local.groups) statement { effect = "Allow" actions = ["s3:PutObject", ] resources = data.aws_s3_bucket.devel.arn } } chaining iteration resource aws_iam_policy access { for_each = data.aws_iam_policy_document.access name = "${each.key}Access" policy = each.value.json } resource aws_iam_group_policy_attachment group_access { for_each = aws_iam_policy.access group = each.key policy_arn = each.value.arn }
  • 18. ● 12: for_each does not work with modules ● 13: for_each supports modules terraform 12 versus 13
  • 20. functions on sets ● setintersection ● setproduct ● setsubtract ● setunion
  • 21. locals { all_groups = toset([ "dev", "core", "admin", "ops", "chat" ]) some_groups = toset(["dev", "voice"]) other_groups = setsubtract(all_groups, some_groups) # in 12.21 } resource aws_iam_group groups { for_each = local.all_groups name = each.value } resource aws_thing thing_one { for_each = local.some_groups group = aws_iam_group.groups[each.value] } resource aws_thing thing_two { for_each = local.other_groups group = aws_iam_group.groups[each.value] } implementing conditionals with sets
  • 22. locals { test_envs = [ "test1", "test2" ] } resource saas_thing_one test_only { foreach = setintersection(toset([var.environment]), local.test_envs) … } conditionals (2)
  • 24. for expressions users = [ "achman", "aziss", "bwong", "cshah", ] # list emails = [ for u in local.users : "${replace(u, "-", ".")}@pagerduty.com" ] # map emails_by_user = { for u in local.users : u => "${replace(u, "-", ".")}@pagerduty.com" }
  • 25. [for s in var.list : upper(s) if s != ""] for expressions - conditionals
  • 26. var user_email_assn { type = map(string) default = { ... } } local { labels = [ for user, email in var.user_email_assn: "${user}:${email} ] } for expressions - map
  • 27. { for s in [ "abc", "def", "aef", "dps" ] : substr(s, 0, 1) => s... } { "a" = [ "abc", "aef", ] "d" = [ "def", "dps", ] } for expressions - group by
  • 29. resource backend_foo left_hand_thing { for_each = ... } resource backend_bar right_hand_thing { for_each = .. } resource backend_foo_bar left_right_assn { for_each = ?? left_hand_thing = each.value.left right_hand_thing = each.value.right } many-to-many
  • 30. # groups have multiple members # user may belong to more than one group resource pagerduty_user { … } resource pagerduty_team { … } resource pagerduty_team_membership { for_each = ?? user_id = ?? team_id = ?? } example: PagerDuty
  • 31. for g in groups { create group for u in groups.users { create user create create user_group_membership } } conventional imperative language
  • 32. locals { on_call_teams = { tier_1 = [ "abe", "jaxel", "beldon" ] tier_2 = [ "abe", "janpax", "fanlo" ] escalation = [ "adam", "shefty", "fanlo" ] } } terraform solution
  • 33. resource pagerduty_team teams { for_each = keys(local.on_call_teams) name = each.value } resource pagerduty_user users { for_each = distinct(flatten(values(local.on_call_teams))) name = each.value email = "${each.value}@companyx.com" }
  • 34. locals { team_user_pairs = [ for team, users in local.on_call_teams: [ for for user in users: { user: user team: team } ] ] team_users = { for pair in flatten(local.team_user_pairs): "${pair.team}-${pair.user}" => { team_id: pagerduty_team[pair.team].id, user_id: pagerduty_user[pair.user].id } } } resource pagerduty_team_membership membership { for_each = local.team_users team_id = each.value.team_id user_id = each.value.user_id }
  • 35. locals { on_call_teams = { tier_1 = [ "abe", "jaxel", "beldon" ] tier_2 = [ "abe", "janpax", "fanlo" ] escalation = [ "adam", "shefty", "fanlo" ] } } ### resource saas_team_membership membership { for_each = ?? user = each.key groups = each.value } one:many inverting
  • 36. user_group_pairs = flatten([ for group, members in local.group_memberships : [ for user in members : { user = user group = group } ] ]) groups_by_user = { for pair in local.user_group_pairs : pair.user => pair.group... } }
  • 37. resource saas_team_membership membership { for_each = local.groups_by_user user = each.key groups = each.value }
  • 39. objectives ● understandable ● easy to change ● economical (DRY)
  • 40. ● data ○ structure according to your domain ○ use data structures ○ normalize/minimize duplication ○ optimize for frequent changes ● transform ○ use for, if and set functions ○ inputs: your data ○ outputs: what your provider's resources need ● resources ○ create each resource once ○ chain resources pattern for code organization