<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Fábio Matavelli</title>
    <description>The latest articles on DEV Community by Fábio Matavelli (@fabiomatavelli).</description>
    <link>https://dev.to/fabiomatavelli</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F351898%2F4dd750a2-1e82-4132-bb94-079d3d76e050.jpg</url>
      <title>DEV Community: Fábio Matavelli</title>
      <link>https://dev.to/fabiomatavelli</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fabiomatavelli"/>
    <language>en</language>
    <item>
      <title>Using Terraform setproduct function</title>
      <dc:creator>Fábio Matavelli</dc:creator>
      <pubDate>Fri, 18 Mar 2022 17:55:48 +0000</pubDate>
      <link>https://dev.to/fabiomatavelli/using-terraform-setproduct-function-32c4</link>
      <guid>https://dev.to/fabiomatavelli/using-terraform-setproduct-function-32c4</guid>
      <description>&lt;p&gt;In 2019 one of my contributions for Terraform were published in the 0.12 version, the &lt;code&gt;setproduct&lt;/code&gt; function. It added the capability to calculate the cartesian product of multiple sets of strings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cartesian product
&lt;/h2&gt;

&lt;p&gt;I will try not to be too theoretical in this one, but the cartesian product is a mathematical function that, given two sets, calculates the sets of all ordered pairs, AxB = {(a, b),...}, where &lt;code&gt;a&lt;/code&gt; is in &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; is in &lt;code&gt;B&lt;/code&gt;.&lt;br&gt;
To give you an example, we can use a deck of cards, where you have a rank of a 13-element set and a suit of a four-element set.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A = {A, K, Q, J, 10, 9, 8, 7, 6, 5, 4, 3, 2}
B = {♠, ♥, ♦, ♣}

AxB = {(A, ♠), (A, ♥), (A, ♦), (A, ♣), (K, ♠), ..., (3, ♣), (2, ♠), (2, ♥), (2, ♦), (2, ♣)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find more information about cartesian product on &lt;a href="https://en.wikipedia.org/wiki/Cartesian_product"&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why that?
&lt;/h2&gt;

&lt;p&gt;In 2018, I was working on a project that was using AWS as a cloud provider, and Terraform was responsible to manage the infrastructure as a code (IaC) for AWS. We needed to create multiple queues in SQS with the same purpose, receive data from an ERP to be processed by a lambda consumer and integrate it with an e-commerce platform.&lt;/p&gt;

&lt;p&gt;The main idea was to create a queue for every ERP module that needed to have the message processed by this lambda consumer. We had some modules in the ERP at the beginning of the project, but the idea was to expand it to many more. Products, SKUs, stock, customers, orders, and more, needed to be integrated with the e-commerce platform.&lt;/p&gt;

&lt;p&gt;Since the project wasn't that big in the beginning, we were using the same AWS account for the three environments (what I don't recommend), development, staging, and production. Said that we need to create the queues for every stage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A = {product, sku, stock, customer, order}
B = {dev, stage, prod}

AxB = {(product, dev), (product, stage), (product, prod), (sku, dev)... (order, dev), (order, stage), (order, prod)}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fifteen queues needed to be created and managed by Terraform, and we had the idea to expand it to more modules in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setproduct function
&lt;/h2&gt;

&lt;p&gt;Terraform didn't have an easy way to do that, so I had the idea to create an MR adding the &lt;code&gt;setproduct&lt;/code&gt; function to solve this problem.&lt;br&gt;
&lt;code&gt;Setproduct&lt;/code&gt; is easy to use, and you can pass more than 2 sets to it (AxBxCxN...), and it will return all the possible combinations of the sets.&lt;/p&gt;

&lt;p&gt;So we had the problem, and now we have the solution, how to use it?&lt;/p&gt;

&lt;p&gt;Simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setproduct&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"stock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"order"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"stage"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"prod"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"stage"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"prod"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"prod"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"dev"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"stage"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"prod"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, now we can create the SQS queues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;queues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setproduct&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"stock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"order"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"stage"&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"prod"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_sqs_queue"&lt;/span&gt; &lt;span class="s2"&gt;"queue"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queues&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"${q[0]}-${q[1]}"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;stage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${each.value.module}-${each.value.stage}"&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;
    &lt;span class="nx"&gt;Stage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stage&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the &lt;code&gt;terraform plan&lt;/code&gt;, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Refreshing Terraform state &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="nt"&gt;-memory&lt;/span&gt; prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to &lt;span class="nb"&gt;local &lt;/span&gt;or remote state storage.


&lt;span class="nt"&gt;------------------------------------------------------------------------&lt;/span&gt;

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  &lt;span class="c"&gt;# aws_sqs_queue.queue["customer-dev"] will be created&lt;/span&gt;
  + resource &lt;span class="s2"&gt;"aws_sqs_queue"&lt;/span&gt; &lt;span class="s2"&gt;"queue"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      + arn                               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + content_based_deduplication       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      + delay_seconds                     &lt;span class="o"&gt;=&lt;/span&gt; 0
      + fifo_queue                        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      + &lt;span class="nb"&gt;id&lt;/span&gt;                                &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + kms_data_key_reuse_period_seconds &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + max_message_size                  &lt;span class="o"&gt;=&lt;/span&gt; 262144
      + message_retention_seconds         &lt;span class="o"&gt;=&lt;/span&gt; 345600
      + name                              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"customer-dev"&lt;/span&gt;
      + policy                            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + receive_wait_time_seconds         &lt;span class="o"&gt;=&lt;/span&gt; 0
      + tags                              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          + &lt;span class="s2"&gt;"Module"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"customer"&lt;/span&gt;
          + &lt;span class="s2"&gt;"Stage"&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      + visibility_timeout_seconds        &lt;span class="o"&gt;=&lt;/span&gt; 30
    &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;# aws_sqs_queue.queue["customer-prod"] will be created&lt;/span&gt;
  + resource &lt;span class="s2"&gt;"aws_sqs_queue"&lt;/span&gt; &lt;span class="s2"&gt;"queue"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      + arn                               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + content_based_deduplication       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      + delay_seconds                     &lt;span class="o"&gt;=&lt;/span&gt; 0
      + fifo_queue                        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      + &lt;span class="nb"&gt;id&lt;/span&gt;                                &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + kms_data_key_reuse_period_seconds &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + max_message_size                  &lt;span class="o"&gt;=&lt;/span&gt; 262144
      + message_retention_seconds         &lt;span class="o"&gt;=&lt;/span&gt; 345600
      + name                              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"customer-prod"&lt;/span&gt;
      + policy                            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + receive_wait_time_seconds         &lt;span class="o"&gt;=&lt;/span&gt; 0
      + tags                              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          + &lt;span class="s2"&gt;"Module"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"customer"&lt;/span&gt;
          + &lt;span class="s2"&gt;"Stage"&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"prod"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      + visibility_timeout_seconds        &lt;span class="o"&gt;=&lt;/span&gt; 30
    &lt;span class="o"&gt;}&lt;/span&gt;

...

  &lt;span class="c"&gt;# aws_sqs_queue.queue["stock-stage"] will be created&lt;/span&gt;
  + resource &lt;span class="s2"&gt;"aws_sqs_queue"&lt;/span&gt; &lt;span class="s2"&gt;"queue"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      + arn                               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + content_based_deduplication       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      + delay_seconds                     &lt;span class="o"&gt;=&lt;/span&gt; 0
      + fifo_queue                        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
      + &lt;span class="nb"&gt;id&lt;/span&gt;                                &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + kms_data_key_reuse_period_seconds &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + max_message_size                  &lt;span class="o"&gt;=&lt;/span&gt; 262144
      + message_retention_seconds         &lt;span class="o"&gt;=&lt;/span&gt; 345600
      + name                              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"stock-stage"&lt;/span&gt;
      + policy                            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + receive_wait_time_seconds         &lt;span class="o"&gt;=&lt;/span&gt; 0
      + tags                              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          + &lt;span class="s2"&gt;"Module"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"stock"&lt;/span&gt;
          + &lt;span class="s2"&gt;"Stage"&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"stage"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      + visibility_timeout_seconds        &lt;span class="o"&gt;=&lt;/span&gt; 30
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy no? You have many other possibilities of use of the &lt;code&gt;setproduct&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;Ok Fábio, but if I have more than 2 sets that need to have a combination? No problem, the function resolves it for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setproduct&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ABC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"XYZ"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"000"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"ABC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"ABC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"XYZ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"XYZ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"ABC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"ABC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"ABC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"XYZ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"XYZ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setproduct&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ABC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"XYZ"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"000"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;))&lt;/span&gt;

&lt;span class="mi"&gt;36&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy! Feel free to comment on it and give your suggestion.&lt;/p&gt;

&lt;p&gt;If you want more information, you can check the &lt;a href="https://www.terraform.io/language/functions/setproduct"&gt;Terraform manual for &lt;code&gt;setproduct&lt;/code&gt; function&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>programming</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Setup Gitlab CI with Terraform</title>
      <dc:creator>Fábio Matavelli</dc:creator>
      <pubDate>Mon, 02 Aug 2021 09:24:44 +0000</pubDate>
      <link>https://dev.to/fabiomatavelli/setup-gitlab-ci-with-terraform-26l1</link>
      <guid>https://dev.to/fabiomatavelli/setup-gitlab-ci-with-terraform-26l1</guid>
      <description>&lt;p&gt;Gitlab team is doing such a great job on their CI/CD pipelines. In this post, I will show you how to use its power to deploy infrastructure as code (IaC). For this, we are going to use Terraform, which is a tool for building, changing, and managing infrastructure in a safe, repeatable way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gitlab CI
&lt;/h2&gt;

&lt;p&gt;I imagine that you already have an account on Gitlab (if not just go to &lt;a href="http://gitlab.com"&gt;gitlab.com&lt;/a&gt; and create one) or a Gitlab CE/EE installation. &lt;/p&gt;

&lt;p&gt;So let's understand how the pipeline is configured.&lt;/p&gt;

&lt;p&gt;First, you will need to create a file on the root of your repository called &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;. You can change the name of the file on the repository configuration, but for now, let's keep how it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stages
&lt;/h2&gt;

&lt;p&gt;Let's configure the stages of the pipeline. In this example, I will only define the steps for the Terraform, or Infrastructure As Code (IaC). You can define as many as other stages that you want to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iac_validate&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iac_plan&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iac_apply&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stages will always run in sequence.&lt;/p&gt;

&lt;h3&gt;
  
  
  iac_validate
&lt;/h3&gt;

&lt;p&gt;We will use this stage to validate the Terraform configuration. It will only validate the syntax and the inner reference of resources in the configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  iac_plan
&lt;/h3&gt;

&lt;p&gt;In this stage, Terraform will run the plan of the configuration. It will check all the resources of the configuration against the state and it will show you what will be created, changed or destroyed.&lt;/p&gt;

&lt;h3&gt;
  
  
  iac_apply
&lt;/h3&gt;

&lt;p&gt;This stage will, as the name says, apply the previous plan generated in the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default configuration
&lt;/h2&gt;

&lt;p&gt;For this example, we will use the Terraform official Docker image to run the pipeline. So, let's define it as a default image in the Gitlab CI file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:latest&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/usr/bin/env&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.terraform&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have defined the &lt;code&gt;entrypoint&lt;/code&gt; for the image because Terraform uses &lt;code&gt;terraform&lt;/code&gt; binary as entrypoint. As we are running this in the Gitlab CI pipeline, we need to change it to &lt;code&gt;/usr/bin/env&lt;/code&gt; in order to job execute otherwise it will fail. In Docker, the &lt;code&gt;entrypoint&lt;/code&gt; defines the program that will be executed in the Docker container. You can find more information &lt;a href="https://docs.docker.com/engine/reference/builder/#entrypoint"&gt;here&lt;/a&gt;. If you are running Gitlab Runner as shell you can remove the &lt;code&gt;image&lt;/code&gt; definition.&lt;/p&gt;

&lt;p&gt;Another thing that we have defined in the default configuration is the &lt;code&gt;before_script&lt;/code&gt;. The &lt;code&gt;before_script&lt;/code&gt; will run before every job unless you define it in the job.&lt;/p&gt;

&lt;p&gt;Last but not least, the cache. We defined the &lt;code&gt;.terraform&lt;/code&gt; directory to be cached. This directory is created automatically by Terraform on every execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  iac_validate
&lt;/h2&gt;

&lt;p&gt;As I mentioned before, this stage will only validate the syntax and the inner reference of the resources specified in the configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;terraform_validate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iac_validate&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform validate&lt;/span&gt;
  &lt;span class="na"&gt;except&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;stage&lt;/code&gt; specifies the stage that this job will run. You can define multiple jobs to run in the same stage&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;script&lt;/code&gt; receives all the commands that will be executed in the job. If any command fails, the job will fail&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;except&lt;/code&gt; tells the job to not run on the keys, in this case on the &lt;code&gt;ref master&lt;/code&gt; (the branch &lt;code&gt;master&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will only execute it in the feature or fix branches, not on the &lt;code&gt;master&lt;/code&gt; branch. I am assuming that you don't commit to master, right? ;-)&lt;br&gt;
So it will execute and if there is any error, it will output to you.&lt;/p&gt;

&lt;p&gt;For example, I have defined a wrong argument in the Terraform &lt;code&gt;null_resource&lt;/code&gt;, take a look at the error that &lt;code&gt;terraform validate&lt;/code&gt; thrown to me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;terraform validate
Error: Unsupported argument

  on example.tf line 2, &lt;span class="k"&gt;in &lt;/span&gt;resource &lt;span class="s2"&gt;"null_resource"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt;:
   2:   my_argument &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"NOK"&lt;/span&gt;

An argument named &lt;span class="s2"&gt;"my_argument"&lt;/span&gt; is not expected here.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is ok, it will output the following message to you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;terraform validate
Success! The configuration is valid.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  iac_plan
&lt;/h2&gt;

&lt;p&gt;Here Terraform will compare your configuration with the state and will show you all the resources that need to be created, changed or destroyed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;terraform_plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iac_plan&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform plan --out plan&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;plan&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have two new keys defined in the &lt;code&gt;terraform_plan&lt;/code&gt; job, that is &lt;code&gt;only&lt;/code&gt; and &lt;code&gt;artifacts&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;only&lt;/code&gt; means that this job will only run in those keys, in this case in &lt;code&gt;ref master&lt;/code&gt; (the master branch).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;artifacts&lt;/code&gt; will retain the file that will be created by the &lt;code&gt;terraform plan&lt;/code&gt;, with the parameter &lt;code&gt;--out&lt;/code&gt;. In this case, the &lt;code&gt;plan&lt;/code&gt; file. We will use this file in the next job to apply the infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, using the last example from the &lt;code&gt;terraform validate&lt;/code&gt; but, this time, with a valid configuration, let's see what the plan will output to us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;terraform plan &lt;span class="nt"&gt;--out&lt;/span&gt; plan
Refreshing Terraform state &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="nt"&gt;-memory&lt;/span&gt; prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to &lt;span class="nb"&gt;local &lt;/span&gt;or remote state storage.


&lt;span class="nt"&gt;------------------------------------------------------------------------&lt;/span&gt;

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  &lt;span class="c"&gt;# null_resource.example will be created&lt;/span&gt;
  + resource &lt;span class="s2"&gt;"null_resource"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      + &lt;span class="nb"&gt;id&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;known after apply&lt;span class="o"&gt;)&lt;/span&gt;
      + triggers &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          + &lt;span class="s2"&gt;"my_variable"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"OK"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

Plan: 1 to add, 0 to change, 0 to destroy.

&lt;span class="nt"&gt;------------------------------------------------------------------------&lt;/span&gt;

This plan was saved to: plan

To perform exactly these actions, run the following &lt;span class="nb"&gt;command &lt;/span&gt;to apply:
    terraform apply &lt;span class="s2"&gt;"plan"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will not explain in this article the terraform state, it will be a subject for a future post.&lt;/p&gt;

&lt;p&gt;If there was nothing to create, change or destroy, terraform will output it to you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;terraform plan &lt;span class="nt"&gt;--out&lt;/span&gt; plan
Refreshing Terraform state &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="nt"&gt;-memory&lt;/span&gt; prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to &lt;span class="nb"&gt;local &lt;/span&gt;or remote state storage.


&lt;span class="nt"&gt;------------------------------------------------------------------------&lt;/span&gt;

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's move to our final job.&lt;/p&gt;

&lt;h2&gt;
  
  
  iac_apply
&lt;/h2&gt;

&lt;p&gt;And here is the final job that will apply the infrastructure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;terraform_apply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iac_apply&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform apply --auto-approve plan&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;
  &lt;span class="na"&gt;allow_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, new keys here. Let me explain the &lt;code&gt;when&lt;/code&gt; and &lt;code&gt;allow_failure&lt;/code&gt; keys defined in here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;when&lt;/code&gt; defines when the job will be run. In this case, the job will run manually&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allow_failure&lt;/code&gt; this specifies if the job can fail or not&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This job will apply your infrastructure using the plan that was generated in the last job (&lt;code&gt;terraform_plan&lt;/code&gt;). Take a look at what Terraform will output to you when you execute this job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;terraform apply &lt;span class="nt"&gt;--auto-aprove&lt;/span&gt; plan
null_resource.example: Creating...
null_resource.example: Creation &lt;span class="nb"&gt;complete &lt;/span&gt;after 0s &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5363055958456141136]

Apply &lt;span class="nb"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the &lt;span class="nb"&gt;complete &lt;/span&gt;state
use the &lt;span class="sb"&gt;`&lt;/span&gt;terraform show&lt;span class="sb"&gt;`&lt;/span&gt; command.

State path: terraform.tfstate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We used the &lt;code&gt;--auto-approve&lt;/code&gt; parameter so you don't have to type (well you can't type actually) &lt;code&gt;yes&lt;/code&gt; to apply the configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resume
&lt;/h2&gt;

&lt;p&gt;We reached the end of this post, let's see how our final &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iac_validate&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iac_plan&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iac_apply&lt;/span&gt;

&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/terraform:latest&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/usr/bin/env&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"&lt;/span&gt;
  &lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform init&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.terraform&lt;/span&gt;

&lt;span class="na"&gt;terraform_validate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iac_validate&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform validate&lt;/span&gt;
  &lt;span class="na"&gt;except&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;terraform_plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iac_plan&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform plan --out plan&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;plan&lt;/span&gt;

&lt;span class="na"&gt;terraform_apply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iac_apply&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;terraform apply --auto-approve plan&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;manual&lt;/span&gt;
  &lt;span class="na"&gt;allow_failure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There were few things that I didn't cover in this post but I will do in future ones, so keep visiting me! :-)&lt;br&gt;
I hope you have enjoyed this article. Please leave your comment so I can improve future posts. Enjoy it!&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>gitlab</category>
      <category>cicd</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
