Ravindra BagaleCourses & study guides मराठी

Chapter 38: Terraform CLI Commands fmt validate plan apply state and more

38.7 refresh-only and graph

Story. An Infosys client support engineer changed a tag in the console during an incident, and the team wanted state to record reality without changing AWS. apply -refresh-only updates state from the real resources and makes no infrastructure changes. terraform graph prints the dependency graph so you can see why things build in a certain order.

console change plan -refresh -only review apply -refresh -only state matches AWS
refresh-only updates state to match AWS; graph shows the build order.
terraform plan -refresh-only
terraform apply -refresh-only
terraform graph | dot -Tsvg > graph.svg

What each line does

  • terraform plan -refresh-only — Shows what changed in AWS since the last apply, without proposing fixes.
  • terraform apply -refresh-only — Writes those real values into state; AWS is not changed.
  • terraform graph | dot -Tsvg > graph.svg — Turns the dependency graph into a picture with Graphviz.

When it is green.

Note: Objects have changed outside of Terraform
  # aws_instance.web has changed
  ~ tags = { + "Incident" = "INC-1042" }
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

When it is red.

dot: command not found

Fix. Install Graphviz with sudo apt install graphviz or sudo dnf install graphviz. Remember: after refresh-only, the next normal plan will propose removing the console tag unless you also add it to code.

What: every term in plain English

  • refresh — Terraform reads real AWS values into state.
  • -refresh-only — A plan or apply that only updates state from AWS. It never changes AWS.
  • drift — AWS changed outside Terraform, for example a console click.
  • terraform graph — Prints the dependency graph in DOT format.
  • dot — A Graphviz tool that turns DOT into a picture.

Example 1: See drift with plan -refresh-only

Someone added a tag in the console at night. Find out what changed.

  1. Add a tag Owner=ravi to the instance in the console.
  2. Run plan -refresh-only.
terraform plan -refresh-only

Output

Note: Objects have changed outside of Terraform

  # aws_instance.web has changed
  ~ resource "aws_instance" "web" {
      ~ tags = {
          + "Owner" = "ravi"
            # (1 unchanged element hidden)
        }
    }

This is a refresh-only plan, so Terraform will not take any actions to undo these.

What it shows: It only reports. Nothing is changed in AWS or state.

Example 2: Accept the drift into state, then decide

First record reality, then fix the code or revert.

terraform apply -refresh-only -auto-approve
terraform plan

Output

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

  # aws_instance.web will be updated in-place
  ~ tags = {
      - "Owner" = "ravi" -> null
    }
Plan: 0 to add, 1 to change, 0 to destroy.

What it shows: Now a normal plan wants to remove the tag. Either add Owner to the code, or apply to revert.

Example 3: Draw the dependency graph

A new teammate asks why the instance waits for the security group. Show a picture.

sudo apt-get install -y graphviz
terraform graph | dot -Tsvg > graph.svg
terraform graph | grep -- '->' | head -3

Output

"[root] aws_instance.web (expand)" -> "[root] aws_security_group.web (expand)"
"[root] aws_instance.web (expand)" -> "[root] data.aws_ami.al2023 (expand)"
"[root] aws_security_group.web (expand)" -> "[root] data.aws_vpc.default (expand)"

What it shows: Each arrow means depends on. Open graph.svg in a browser to see the boxes.

Example 4: Nightly drift job

Catch console changes the next morning, not during an outage.

terraform plan -refresh-only -detailed-exitcode -no-color > drift.txt
if [ $? -eq 2 ]; then echo "DRIFT in prod"; grep 'has changed' drift.txt; fi

Output

DRIFT in prod
  # aws_instance.web has changed

What it shows: Run it from Jenkins or GitHub Actions on a schedule and send the result to Slack.

Example 5: Graph only one change, from a saved plan

A full graph is crowded. A plan graph shows only what will change.

terraform plan -out=tfplan
terraform graph -type=plan tfplan | dot -Tpng > plan.png
terraform graph -type=plan tfplan | grep -c -- '->'

Output

Plan: 2 to add, 0 to change, 0 to destroy.
6

What it shows: Open plan.png. Fewer boxes, easier to explain to a reviewer.

Command cheat sheet

Command What it does When to use it
terraform plan -​refresh-​only Shows drift only Morning checks
terraform apply -​refresh-​only Saves real values into state Accept drift
terraform apply Reverts drift to code Undo console clicks
terraform plan -​refresh=​false Skips the AWS read Very large stacks, carefully
terraform graph Dependencies as DOT Explaining order
dot -Tsvg DOT to picture After graph
-​detailed-​exitcode Exit 2 on drift Scheduled jobs

Verify: did it work?

  1. Drift is gone

    terraform plan -refresh-only -detailed-exitcode; echo $?
    

    Output

    No changes. Your infrastructure still matches the configuration.
    0
    
  2. The picture was made

    ls -l graph.svg
    

    Output

    -rw-r--r-- 1 ravi ravi 18342 Oct 25 11:05 graph.svg
    

When it is red 1

Error: Unsupported argument: refresh-only cannot be combined with -replace

Cause. refresh-only never changes resources, so -replace makes no sense with it.

Fix, step by step

  1. Run them as two separate commands.

When it is red 2

bash: dot: command not found

Cause. Graphviz is not installed.

Fix, step by step

  1. Install graphviz with your package manager.
  2. Run the graph command again.

When it is red 3

Warning: The terraform refresh command is deprecated

Cause. Old command. It updates state with no review.

Fix, step by step

  1. Use terraform apply -refresh-only, which shows changes first.

When it is red 4

Note: Objects have changed outside of Terraform
  # aws_autoscaling_group.web has changed
      ~ desired_capacity = 2 -> 4

Cause. Not a real problem. Auto Scaling changes desired_capacity on its own, so it shows as drift every day.

Fix, step by step

  1. Add lifecycle { ignore_changes = [desired_capacity] } to the group.
  2. Run plan -refresh-only again and the noise is gone.

Cleanup

terraform destroy -auto-approve
rm -f graph.svg drift.txt

Practice tasks

Easy Make drift

Why: See it yourself.

What to do: Change a tag in the console and run plan -refresh-only.

How:
  1. Add a tag.
  2. Plan refresh-only.

Check: You see has changed.

Medium Revert drift

Why: Code is the source of truth.

What to do: Run a normal apply to remove the console tag.

How:
  1. Apply.
  2. Check the console.

Check: The tag is gone.

Medium Picture a VPC lab

Why: Graphs teach order.

What to do: Draw the graph for a VPC lab with subnets.

How:
  1. terraform graph | dot -Tpng > vpc.png

Check: You can name the first resource created.

Hard Schedule a drift check

Why: Automation beats memory.

What to do: Add the nightly job to a CI schedule.

How:
  1. Use cron in GitHub Actions or Jenkins.

Check: The job turns red on drift.

Easy Say it in two lines

Why: If you can say it simply, you understand it.

What to do: Write two short lines about this lesson for a fresher.

How:
  1. Write the problem it solves.
  2. Write the one command or file you use.
  3. Read it aloud.

Check: A fresher understands it without a question.

Easy Start a safe lab folder

Why: Practice needs a throwaway place.

What to do: Make a new folder with versions.tf and a random_pet resource, so no AWS cost.

How:
  1. mkdir tf-lab and cd into it.
  2. Add the hashicorp/random provider and one random_pet.
  3. Run terraform init and terraform apply.

Check: Apply complete! with 1 added.

Medium Break it on purpose

Why: You must know the red output by face.

What to do: Cause one error from the red part of this lesson and fix it.

How:
  1. Follow one red section.
  2. Copy the exact message to your notes.
  3. Write the fix in one line.

Check: You fixed it without searching the web.

Medium Run it twice

Why: A second run must be quiet.

What to do: Run the same plan two times with no edits.

How:
  1. Run terraform plan.
  2. Run it again.
  3. Explain any change it still shows.

Check: The second plan says No changes, or you can explain each line.

Medium Write a runbook page

Why: At 2 a.m. nobody remembers flags.

What to do: Write a one-page runbook for this lesson.

How:
  1. Title, when to use, exact commands, how to check, how to undo.

Check: A teammate can follow it alone.

Medium Run it from a pipeline

Why: Real teams run Terraform from CI, not from laptops.

What to do: Run the main command of this lesson inside a GitHub Actions or Jenkins job.

How:
  1. Add a job with hashicorp/setup-terraform or a Terraform Docker image.
  2. Give it AWS access through an IAM role, never a key in the file.
  3. Run init, then the command from this lesson.

Check: The job log shows the same output you saw on your laptop.

Medium Check the cost

Why: Labs left running cost real money.

What to do: Find what this lesson would cost per day if you forgot to destroy it.

How:
  1. Open the AWS Pricing Calculator.
  2. Add each resource from your plan.
  3. Write the daily cost in your notes.

Check: You know the daily cost and you ran terraform destroy.

Hard Draw the flow top to bottom

Why: A drawing shows the order of work.

What to do: Draw this lesson as boxes from top to bottom.

How:
  1. Start at your code, go through plan and state, end at AWS.
  2. Mark where each command reads or writes.

Check: Each box matches a real step you ran.

Hard Explain it like an interview

Why: Interviewers want real stories.

What to do: Record a 60 second answer about this lesson.

How:
  1. Say the problem, the command, and one error you hit.

Check: Your answer has a real command and a real error message.

Homework: try at home

Try at home

Create one EC2 lab, change its tags in the console, and practise both paths: accept the drift into code, and revert it with apply.

Recap

  • Every plan refreshes state first.
  • plan -refresh-only shows drift and changes nothing.
  • apply -refresh-only accepts AWS values into state.
  • A normal apply reverts drift to match code.
  • terraform graph plus dot draws dependencies.
  • Use ignore_changes for values AWS changes on purpose, such as desired_capacity.

FAQ

Does refresh-only change AWS?

Never. Only state.

Should I always accept drift?

No. Decide: add it to code, or revert it.

Can I skip refresh?

plan -refresh=false is faster but can be wrong. Use rarely.

Is graph useful for big stacks?

It gets crowded. Graph one module folder at a time.

What causes drift most?

Console clicks, scripts and auto-scaling.

Does plan -refresh-only need AWS access?

Yes. It reads AWS.

Why does Auto Scaling always show drift?

AWS changes desired_capacity when load changes. Use ignore_changes for that one argument.

How often should a drift job run?

Once a night for most teams. Every hour for strict prod accounts.

Interview questions

  1. How do you detect drift?

    plan -refresh-only with -detailed-exitcode on a schedule.

  2. Why was terraform refresh deprecated?

    It changed state without review. apply -refresh-only shows a plan first.

  3. How do you fix drift?

    Either update code to match, or apply to restore the code values.

  4. What does terraform graph show?

    Resource dependencies in DOT format.

  5. How do you stop drift?

    Limit console write access and change only through pipelines.

  6. Your drift job fires every night for the same resource. What do you do?

    Find who or what changes it. If it is expected, such as Auto Scaling, add ignore_changes for that argument. If it is a person, remove their console write access and route changes through the pipeline.

Quick quiz

Q1. Does -refresh-only change AWS?

No.

Q2. Which command accepts drift into state?

terraform apply -refresh-only.

Q3. What tool draws DOT files?

Graphviz dot.

Q4. What exit code means drift with -detailed-exitcode?

2.

Q5. Which old command is deprecated?

terraform refresh.

Lab

  1. Run terraform fmt -check -diff -recursive on your Chapter 33 code.
  2. Run terraform plan -out=tfplan and terraform show -json tfplan.
  3. Apply the plan, then run terraform state list and terraform output.
  4. Run terraform plan -replace on one instance and read the -/+ line.
  5. Change a tag in the console, then run terraform plan -refresh-only.
  6. Run terraform destroy to avoid cost.

Practice task

For each of state mv, state rm and taint, name the block or flag that replaces it in reviewed code.

Ravindra Bagale's Tip

Back up state with terraform state pull before any state mv or state rm.

In short

  • fmt -check and validate are the cheapest gate.
  • Save plans with -out and apply the file.
  • -target is for emergencies only.
  • state mv and rm change state at once; prefer moved and removed.
  • Use -replace, not taint; use refresh-only to record outside changes.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards