Pages

Showing posts with label terraform. Show all posts
Showing posts with label terraform. Show all posts

Wednesday, October 3, 2018

Understanding Terraform state

Once we successfully create a aws instance by running the “terraform apply” command, we will also see another file generated by terraform with the name “terraform.tfstate”

This file is called state file. What terraform does is not just to create the resource but also save everything it knows about the resource in this special file with “tfstate” extension file. This file is a Json file with all details regarding the resource terraform has created.

The terraform state file is quite explanatory

"version": 3,
"terraform_version": "0.11.7",
"serial": 1,
"lineage": "bda22195-37ed-a63a-cfd3-54e1804fcadf",

The version:3 talks about the version of the state file. This is not a terraform version or the resource version that we created.

The terraform_version:0.11.7 talks about the version of the terraform that this state file is created. 

The serial:1 talks about the version of the of the state file. This value gets increased when ever we change the state. 

The next lines that start from modules talk about the resource specific details.
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {
                "aws_instance.first-instance": {
                    "type": "aws_instance",
                    "depends_on": [],
                    "primary": {
                        "id": "i-0363a956cb5a76b37",
                        "attributes": {
                            "ami": "ami-9c0638f9",
                            "arn": "arn:aws:ec2:us-east-2:161598355066:instance/i-0363a956cb5a76b37",
                            "associate_public_ip_address": "true",
                            "availability_zone": "us-east-2c",
                            "cpu_core_count": "1",
                            "cpu_threads_per_core": "1",
                            "credit_specification.#": "1",
                            "credit_specification.0.cpu_credits": "standard",
                            "disable_api_termination": "false",
                            "ebs_block_device.#": "0",
                            "ebs_optimized": "false",
      ****************

This state file is considered to be very important coz terraform uses this file not just for creating but also for updating and destroying the infrastructure. Terraform knows if the actual state of resources has changed and if parameters in a template have changed, and then it intelligently figures out what the final state should look like and gets your infrastructure to that state.

Terraform provides command line options where we can edit the state file. The below command list all the resources in the state file

jagadishfirstTemplate$Sun Sep 30@ terraform state list
aws_instance.first-instance

The terraform show command will print the state information in a human readable format

jagadishfirstTemplate$Sun Sep 30@ terraform show
aws_instance.first-instance:
  id = i-0363a956cb5a76b37
  ami = ami-9c0638f9
  arn = arn:aws:ec2:us-east-2:161598355066:instance/i-0363a956cb5a76b37
  associate_public_ip_address = true
  availability_zone = us-east-2c
  cpu_core_count = 1
  cpu_threads_per_core = 1
  credit_specification.# = 1
  credit_specification.0.cpu_credits = standard
  disable_api_termination = false
  ebs_block_device.# = 0
  ebs_optimized = false
  ephemeral_block_device.# = 0
  get_password_data = false
  iam_instance_profile = 
  instance_state = running
  instance_type = t2.micro
  ipv6_addresses.# = 0
  key_name = 
  monitoring = false
  network_interface.# = 0
  network_interface_id = eni-08b7d1faa00bbc6fa
  password_data = 
  placement_group = 
  primary_network_interface_id = eni-08b7d1faa00bbc6fa
  private_dns = ip-172-31-38-85.us-east-2.compute.internal
  private_ip = 172.31.38.85
  public_dns = ec2-18-219-108-48.us-east-2.compute.amazonaws.com
  public_ip = 18.219.108.48
  root_block_device.# = 1
  root_block_device.0.delete_on_termination = false
  root_block_device.0.iops = 100
  root_block_device.0.volume_id = vol-0a3175a45d18b7c88
  root_block_device.0.volume_size = 8
  root_block_device.0.volume_type = gp2
  security_groups.# = 1
  security_groups.3814588639 = default
  source_dest_check = true
  subnet_id = subnet-c861a484
  tags.% = 1
  tags.Name = first-instance
  tenancy = default
  volume_tags.% = 0
  vpc_security_group_ids.# = 1
  vpc_security_group_ids.1322522975 = sg-1a83ef77

Updating the ResourceNow lets see how we can update a resource. 

jagadishfirstTemplate$Sun Sep 30@ cat template.tf 
provider "aws" 
{
     region = "us-east-2"
}

resource "aws_instance" "first-instance" 
{
    instance_type = "t2.micro"
    ami = "ami-9c0638f9"

    tags {
      Name = "first-instance-change"
    }

}

I just changed the tag name from “first-instance” to “first-instance-change”. Now before running the “terraform apply” , lets see what happens if we run this. Luckily terraform provides a “terraform plan” command which will give you the state changes that will happen.

jagadishfirstTemplate$Sun Sep 30@ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

aws_instance.first-instance: Refreshing state... (ID: i-0363a956cb5a76b37)
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ aws_instance.first-instance
      tags.Name: "first-instance" => "first-instance-change"


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

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

If we see the action that terraform will do from the below lines,
Terraform will perform the following actions:

  ~ aws_instance.first-instance
      tags.Name: "first-instance" => "first-instance-change"

We can see that it is going to change the tag name from “first-instance” to “first-instance-change”

Terraform also provides ways to validate the template using “terraform validate”. This will validate the file and display any errors

Another nice command provided by terraform is “terraform fmt” which will format the template file to best practices, 

jagadishfirstTemplate$Sun Sep 30@ terraform fmt
template.tf

jagadishfirstTemplate$Sun Sep 30@ cat template.tf 
provider "aws" {
  region = "us-east-2"
}

resource "aws_instance" "first-instance" {
  instance_type = "t2.micro"
  ami           = "ami-9c0638f9"

  tags {
    Name = "first-instance-change"
  }
}

Now apply the changes
jagadishfirstTemplate$Sun Sep 30@ terraform apply
aws_instance.first-instance: Refreshing state... (ID: i-0363a956cb5a76b37)

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  ~ aws_instance.first-instance
      tags.Name: "first-instance" => "first-instance-change"


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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.first-instance: Modifying... (ID: i-0363a956cb5a76b37)
  tags.Name: "first-instance" => "first-instance-change"
aws_instance.first-instance: Still modifying... (ID: i-0363a956cb5a76b37, 10s elapsed)
aws_instance.first-instance: Modifications complete after 12s (ID: i-0363a956cb5a76b37)

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

If you check the state it will changed some thing as below,
jagadishfirstTemplate$Sun Sep 30@ cat terraform.tfstate | head -n 10
{
    "version": 3,
    "terraform_version": "0.11.7",
    "serial": 2,
    "lineage": "bda22195-37ed-a63a-cfd3-54e1804fcadf",
    "modules": [
        {
            "path": [
                "root"
            ],

The serial version is changed if you observe.

Destroy the Instance - To destroy the resource we created, we can just call “terraform destroy” or we can delete the template.tf file and run the “terraform apply” command. Terraform will automatically identify state that we want to destroy and will destroy the instance

jagadishfirstTemplate$Sun Sep 30@ terraform destroy
aws_instance.first-instance: Refreshing state... (ID: i-0363a956cb5a76b37)

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

Terraform will perform the following actions:

  - aws_instance.first-instance


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

Do you really want to destroy?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

aws_instance.first-instance: Destroying... (ID: i-0363a956cb5a76b37)
aws_instance.first-instance: Still destroying... (ID: i-0363a956cb5a76b37, 10s elapsed)
aws_instance.first-instance: Still destroying... (ID: i-0363a956cb5a76b37, 20s elapsed)
aws_instance.first-instance: Still destroying... (ID: i-0363a956cb5a76b37, 30s elapsed)
aws_instance.first-instance: Still destroying... (ID: i-0363a956cb5a76b37, 40s elapsed)
aws_instance.first-instance: Destruction complete after 46s

Destroy complete! Resources: 1 destroyed.

More to Come, Happy learning :-)

Read More

Running Terraform - Playing with Aws ec2 Instances

When we run terraform, it will check in the current working directory for a file with tf extension. We have created a sample file called “template.tf” with no contents.

We will then use a “terraform apply” command. When we run the apply command it will read your templates and will try to configure an infrastructure that we have defined in the template file.

jagadishfirstTemplate$Sun Sep 30@ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

The output will be the number of resources that are added, changed and destroyed.

Terraform providers 
Providers are something that we will configure to get access to a service in order to create resources in that service. Let's say if i want to create a aws instance, i need to first create a aws provider with our credentials and other things to get access to aws.

Now let's see how we can create our aws provider. This will be the first template that we will be writing. The template will be written in a special language called HashiCorp Configuration language ( HCL ).

Create our first aws instance 
Resource are the components or things that exists in the infrastructure. They may range from a virtual server to Dns record. Every resource will belong to a provider. 

The resource definition will be something like this

  resource “provider-name-resource-type” “resource-name” {
         parameter_name =  parameter_name
   }


The parameters that we define inside the resource block can be of three types
Resource specific parameter
Meta parameters
Provisioners

Now lets create our first template for creating a ec2 instance.

Define our provider specific details which includes aws credentials, region details etc.  

#provider configuration
provider “aws” {
    region = “us-east-2b
}  

     Now similar to the region, we can also have access_key and secret_key elements defined with correct values to talk to the aws. It can be something like this,

#provider configuration
provider “aws” {
    access_key = xxxxxxx
    Secret_key = xxxxxxxx
     region = “us-east-2c"
}

This can lead to security breach having the values in the configuration file. If we don’t define the credentials in the provider block, terraform will check the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. If these 2 variables ares set, terraform will use these to connect to aws.

If we dont define the credentials in above ways, we can define a credential file in the ~/.aws location and by default if above both ways are not defined, terraform will use this file to connect to aws.

Now let's create our resource,
resource “aws_instance” “first-instance” {
    Instance_type = “t2.micro”
    ami = “ami-9c0638f9”

    tags {
      Name = “first-instance”
    }

}

The whole configuration will look something like this,
jagadishfirstTemplate$Wed Oct 03@ cat template.tf 
provider "aws" {
  region = "us-east-2"
}

resource "aws_instance" "first-instance" {
  instance_type = "t2.micro"
  ami           = "ami-9c0638f9"

  tags {
    Name = "first-instance-change"
  }
}


First run the "terraform init" to initialise providers which is aws in this case,
jagadishfirstTemplate$Sun Sep 30@ terraform init
Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "aws" (1.38.0)...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 1.38"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.

Run the "terraform apply" command to create the infrastructure as,
jagadishfirstTemplate$Sun Sep 30@ terraform apply

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:

  + aws_instance.first-instance
      id:                          
      ami:                          "ami-9c0638f9"
      arn:                         
      associate_public_ip_address: 
      availability_zone:           
      cpu_core_count:              
      cpu_threads_per_core:        
      ebs_block_device.#:          
      ephemeral_block_device.#:    
      get_password_data:            "false"
      instance_state:              
      instance_type:                "t2.micro"
      ipv6_address_count:          
      ipv6_addresses.#:            
      key_name:                    
      network_interface.#:         
      network_interface_id:        
      password_data:               
      placement_group:             
      primary_network_interface_id:
      private_dns:                 
      private_ip:                  
      public_dns:                  
      public_ip:                   
      root_block_device.#:         
      security_groups.#:           
      source_dest_check:            "true"
      subnet_id:                   
      tags.%:                       "1"
      tags.Name:                    "first-instance"
      tenancy:                     
      volume_tags.%:               
      vpc_security_group_ids.#:    


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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.first-instance: Creating...
  ami:                          "" => "ami-9c0638f9"
  arn:                          "" => ""
  associate_public_ip_address:  "" => ""
  availability_zone:            "" => ""
  cpu_core_count:               "" => ""
  cpu_threads_per_core:         "" => ""
  ebs_block_device.#:           "" => ""
  ephemeral_block_device.#:     "" => ""
  get_password_data:            "" => "false"
  instance_state:               "" => ""
  instance_type:                "" => "t2.micro"
  ipv6_address_count:           "" => ""
  ipv6_addresses.#:             "" => ""
  key_name:                     "" => ""
  network_interface.#:          "" => ""
  network_interface_id:         "" => ""
  password_data:                "" => ""
  placement_group:              "" => ""
  primary_network_interface_id: "" => ""
  private_dns:                  "" => ""
  private_ip:                   "" => ""
  public_dns:                   "" => ""
  public_ip:                    "" => ""
  root_block_device.#:          "" => ""
  security_groups.#:            "" => ""
  source_dest_check:            "" => "true"
  subnet_id:                    "" => ""
  tags.%:                       "" => "1"
  tags.Name:                    "" => "first-instance"
  tenancy:                      "" => ""
  volume_tags.%:                "" => ""
  vpc_security_group_ids.#:     "" => ""
aws_instance.first-instance: Still creating... (10s elapsed)
aws_instance.first-instance: Still creating... (20s elapsed)
aws_instance.first-instance: Still creating... (30s elapsed)
aws_instance.first-instance: Creation complete after 34s (ID: i-0363a956cb5a76b37)

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

While applying , it will ask for a confirmation for which we need to pass "yes". Once the apply is success we can go to the aws console and can see a instance with name first-instance created
More to Come , Happy Learning

Read More