ЁЯПл The SchoolтА║ЁЯУЬ TerraformтА║ЁЯХ╕я╕П рдзрдбрд╛ 06 тАФ Dependency graph: gates рдЖрдзреА рдЦреЛрд▓реНрдпрд╛
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯХ╕я╕П рдзрдбрд╛ 06 тАФ Dependency graph: gates рдЖрдзреА рдЦреЛрд▓реНрдпрд╛

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: рдзрдбрд╛ 06 / 12 ┬╖ рдорд╛рдЧреЗ: lesson-05-state ┬╖ рдкреБрдвреЗ: lesson-07-modules


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ05, рдЖрдгрд┐ рдХрдВрддреНрд░рд╛рдЯрджрд╛рд░ рдХреНрд░рдо рдХрд╕рд╛ рдард░рд╡рддреЛ рддреЗ. рдкреНрд░рддреНрдпреЗрдХ reference (gate рдЪреНрдпрд╛ рдЖрддреАрд▓ school_room.lab.id) рдПрдХ edge рдЖрд╣реЗ: gate рдЖрдзреА lab рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рд╣рд╡реА. depends_on рдЖрд░рд╛рдЦрдбреНрдпрд╛рд▓рд╛ рди рджрд┐рд╕рдгрд╛рд░реА edge рдЬреЛрдбрддреЛ. рдЬреНрдпрд╛рдВрдЪреНрдпрд╛рдордзреНрдпреЗ рдХреЛрдгрддрд╛рд╣реА рдорд╛рд░реНрдЧ рдирд╛рд╣реА рдЕрд╢рд╛ рдЧреЛрд╖реНрдЯреА рдПрдХрд╛ рдорд░реНрдпрд╛рджреЗрдкрд░реНрдпрдВрдд рдПрдХрд╛рдЪ рд╡реЗрд│реА рдмрд╛рдВрдзрд▓реНрдпрд╛ рдЬрд╛рддрд╛рдд (-parallelism, default рдиреЗ 10). Destroy graph рдЙрд▓рдЯрд╛ рдЪрд╛рд▓рд╡рддреЛ. рдЖрдгрд┐ loop тАФ A рд▓рд╛ B рд╣рд╡рд╛, B рд▓рд╛ A рд╣рд╡рд╛ тАФ рдирд╛рдХрд╛рд░рд▓рд╛ рдЬрд╛рддреЛ. iac/demo.py рдордзреАрд▓ graph(); iac/engine.py рдордзреАрд▓ _inst_deps(), graph() рдЖрдгрд┐ apply().

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдЖрд░рд╛рдЦрдбрд╛ рд╕рд╛рдВрдЧрддреЛ: рдПрдХ lab, рдПрдХ library, lab рдордзреНрдпреЗ рдЬрд╛рдгрд╛рд░реЗ рдПрдХ рдореБрдЦреНрдп gate, library рдордзреНрдпреЗ рдЬрд╛рдгрд╛рд░реЗ рдПрдХ рдорд╛рдЧрдЪреЗ gate, рдЖрдгрд┐ lab рдордзреНрдпреЗ 4 lockers.

рдЕрдЬреВрди рди рдмрд╛рдВрдзрд▓реЗрд▓реНрдпрд╛ рдЦреЛрд▓реАрд▓рд╛ gate рд▓рд╛рд╡рддрд╛ рдпреЗрдд рдирд╛рд╣реА. ЁЯЪк рдореНрд╣рдгреВрди рдХрдВрддреНрд░рд╛рдЯрджрд╛рд░ рдмрд╛рдг рдХрд╛рдврддреЛ: lab тЖТ рдореБрдЦреНрдп gate, lab тЖТ рдкреНрд░рддреНрдпреЗрдХ locker, library тЖТ рдорд╛рдЧрдЪреЗ gate. рдЖрдгрд┐ рдЖрдгрдЦреА рдПрдХ рдмрд╛рдг рдЬреЛ рдЖрд░рд╛рдЦрдбреНрдпрд╛рд▓рд╛ рд╕реНрд╡рддрдГрд╣реВрди рджрд┐рд╕рдд рдирд╛рд╣реА: рд╢рд╛рд│рд╛ рдореНрд╣рдгрддреЗ "рдореБрдЦреНрдп gate рддрдпрд╛рд░ рдЭрд╛рд▓реНрдпрд╛рдирдВрддрд░рдЪ рдорд╛рдЧрдЪреЗ gate рдЙрдШрдбрд╛" тАФ рдореНрд╣рдгреВрди рдРрд╢реНрд╡рд░реНрдпрд╛ рддреЗ depends_on рдиреЗ рд▓рд┐рд╣реВрди рдареЗрд╡рддреЗ.

рдХрдВрддреНрд░рд╛рдЯрджрд╛рд░рд╛рдХрдбреЗ 10 рдмрд╛рдВрдзрдХрд╛рдо рдХрд░рдгрд╛рд░реЗ рдЖрд╣реЗрдд. ЁЯС╖ЁЯС╖ЁЯС╖

рдЖрда рдирд╛рд╣реА, рддреАрди рдкрд╛рдпрд▒реНрдпрд╛. Campus рдкрд╛рдбрд╛рдпрдЪрд╛ рдЕрд╕реЗрд▓ рддрд░ рдЙрд▓рдЯреЗ рдЬрд╛: рдЖрдзреА gates рдЖрдгрд┐ lockers, рд╢реЗрд╡рдЯреА рдЦреЛрд▓реНрдпрд╛.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    lab["school_room.lab"] --> gm["school_gate.main"]
    lab --> l["school_locker.row[0..3]"]
    lib["school_room.library"] --> gb["school_gate.back"]
    gm -.->|"depends_on"| gb
    s1["step 1: 2 rooms"] --- s2["step 2: 1 gate + 4 lockers"] --- s3["step 3: back gate"]

ЁЯЧ║я╕П рд░реЗрдЦрд╛рдЯрд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/terraform/lesson-diagrams.html#l06

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рдХреНрд░рдорд╛рдореБрд│реЗрдЪ рд╕рдВрдкреВрд░реНрдг system рд╕рд╛рдареА рдПрдХ apply рд╕реБрд░рдХреНрд╖рд┐рдд рдард░рддреЛ: servers рдЖрдзреА network, service рдЖрдзреА рддреА рд╡рд╛рдкрд░рдд рдЕрд╕рд▓реЗрд▓рд╛ role. Parallelism рдореБрд│реЗ рддреЗ рдЬрд▓рдж рд╣реЛрддреЗ. рдЖрдгрд┐ cycle check рдХрдзреАрдЪ рдмрд╛рдВрдзрддрд╛ рди рдпреЗрдгрд╛рд░реЗ design рдерд╛рдВрдмрд╡рддреЛ тАФ Terraform рдЕрд░реНрдзрд╡рдЯ fail рд╣реЛрдгреНрдпрд╛рдРрд╡рдЬреА plan рдЪреНрдпрд╛ рд╡реЗрд│реАрдЪ рддреБрдореНрд╣рд╛рд▓рд╛ рд╕рд╛рдВрдЧрддреЗ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

iac/engine.py рдордзреАрд▓ expand() рдкреНрд░рддреНрдпреЗрдХ block рдЪреЗ references рдЖрдгрд┐ depends_on рдЧреЛрд│рд╛ рдХрд░рддреЗ. _inst_deps() рддреНрдпрд╛рдВрдЪреЗ instance-level edges рдордзреНрдпреЗ рд░реВрдкрд╛рдВрддрд░ рдХрд░рддреЗ (school_room.lab рдЪрд╛ reference рддреНрдпрд╛рдЪреНрдпрд╛ рд╕рд░реНрд╡ instances рдирд╛ рд▓рд╛рдЧреВ рд╣реЛрддреЛ). graph() рдореНрд╣рдгрдЬреЗ Kahn's algorithm: рддреЗ рд╡рд╛рд░рдВрд╡рд╛рд░ рдЬреНрдпрд╛рдВрдЪреНрдпрд╛ dependencies рдкреВрд░реНрдг рдЭрд╛рд▓реНрдпрд╛ рдЖрд╣реЗрдд рдЕрд╕реЗ рд╕рд░реНрд╡ nodes рдШреЗрддреЗ; рдПрдХрд╣реА рддрдпрд╛рд░ рдирд╕реЗрд▓ рдкрдг nodes рдЙрд░рд▓реЗ рдЕрд╕рддреАрд▓ рддрд░ рддреЗ loop рд╢реЛрдзрддреЗ рдЖрдгрд┐ CycleError raise рдХрд░рддреЗ. apply(..., parallelism=N) рдкреНрд░рддреНрдпреЗрдХ step рд▓рд╛ N рдкрд░реНрдпрдВрдд рддрдпрд╛рд░ operations рдЪрд╛рд▓рд╡рддреЗ тАФ рдкреНрд░рддреНрдпреЗрдХ operation рдПрдХ step рдШреЗрддреЗ рдЕрд╕реЗ рд╢рд┐рдХрд╡рдгреНрдпрд╛рд╕рд╛рдареАрдЪреЗ model. Deletes рддреНрдпрд╛рдВрдЪреНрдпрд╛рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдЕрд╕рд▓реЗрд▓реНрдпрд╛ resources рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рддрд╛рдд.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 iac/demo.py graph
python3 - <<'EOF'
import sys; sys.path.insert(0, "iac")
from cloud import FakeCloud
from engine import plan, apply
from demo import GRAPH
for par in (1, 2, 3, 4, 5, 10):
    _, steps, _ = apply(plan(GRAPH, None, FakeCloud()), FakeCloud(), parallelism=par)
    print(f"parallelism {par:>2} тЖТ {len(steps)} steps {[len(s) for s in steps]}")
flat = {"resource": {"school_room": {"lab": {"name": "lab"}},
        "school_locker": {"row": {"count": 6, "room_id": "${school_room.lab.id}", "label": "${count.index}"}}}}
_, steps, _ = apply(plan(flat, None, FakeCloud()), FakeCloud())
print("1 room + 6 lockers тЖТ", [len(s) for s in steps])
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

graph рдЕрд╕реЗ print рдХрд░рддреЗ:

тФАтФА parallelism 10: 3 steps for 8 resources тЖТ [2, 5, 1] per step
   step 1: school_room.lab, school_room.library
   step 2: school_gate.main, school_locker.row[0], school_locker.row[1], school_locker.row[2], school_locker.row[3]
   step 3: school_gate.back
тФАтФА destroy runs the graph backwards:
   step 1: school_locker.row[0], school_locker.row[1], school_locker.row[2], school_locker.row[3], school_gate.back
   step 2: school_room.library, school_gate.main
   step 3: school_room.lab
тФАтФА a gate that needs a locker that needs the gate тЖТ Error: Cycle: school_gate.g, school_locker.l

рддреБрдордЪрд╛ snippet рдЕрд╕реЗ print рдХрд░рддреЛ:

parallelism  1 тЖТ 8 steps [1, 1, 1, 1, 1, 1, 1, 1]
parallelism  2 тЖТ 4 steps [2, 2, 2, 2]
parallelism  3 тЖТ 3 steps [2, 3, 3]
parallelism  4 тЖТ 3 steps [2, 4, 2]
parallelism  5 тЖТ 3 steps [2, 5, 1]
parallelism 10 тЖТ 3 steps [2, 5, 1]
1 room + 6 lockers тЖТ [1, 6]

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рддреБрдореНрд╣реА blocks рдХреЛрдгрддреНрдпрд╛ рдХреНрд░рдорд╛рдиреЗ рд▓рд┐рд╣рд┐рд▓реЗ рддреНрдпрд╛рд╡рд░реВрди рдирд╛рд╣реА, graph рдХреНрд░рдо рдард░рд╡рддреЛ. рдкреБрд░реЗрд╕реЗ рдмрд╛рдВрдзрдХрд╛рдо рдХрд░рдгрд╛рд░реЗ рдЕрд╕рддрд╛рдирд╛ campus рд▓рд╛ 3 steps рд▓рд╛рдЧрд▓реНрдпрд╛ тАФ рд╕рд░реНрд╡рд╛рдд рд▓рд╛рдВрдм рд╕рд╛рдЦрд│реАрдЪреА рд▓рд╛рдВрдмреА (lab тЖТ рдореБрдЦреНрдп gate тЖТ рдорд╛рдЧрдЪреЗ gate) тАФ рдЖрдгрд┐ 5 рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдмрд╛рдВрдзрдХрд╛рдо рдХрд░рдгрд╛рд▒реНрдпрд╛рдВрдЪрд╛ рдЙрдкрдпреЛрдЧ рдЭрд╛рд▓рд╛ рдирд╛рд╣реА, рдХрд╛рд░рдг step 2 рдордзреНрдпреЗ рдХрдзреАрдЪ 5 рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдЧреЛрд╖реНрдЯреА рддрдпрд╛рд░ рдирд╕рддрд╛рдд. 1 рдмрд╛рдВрдзрдХрд╛рдо рдХрд░рдгрд╛рд▒реНрдпрд╛рд╕рд╣ 8 steps рд▓рд╛рдЧрд▓реНрдпрд╛. Destroy рдиреЗ рддреЛрдЪ graph рдЙрд▓рдЯрд╛ рдЪрд╛рд▓рд╡рд▓рд╛, рдЖрдгрд┐ рдХрд╛рд╣реАрд╣реА рдмрд╛рдВрдзрдгреНрдпрд╛рдЖрдзреАрдЪ loop рдирд╛рдХрд╛рд░рд▓рд╛ рдЧреЗрд▓рд╛.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ рдЦрд░рд╛ graph рдХрд╛рдврд╛ рдЖрдгрд┐ walk рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рд╛:

terraform graph | dot -Tsvg > graph.svg     # needs Graphviz; open graph.svg in a browser
terraform apply -parallelism=5              # fewer concurrent API calls

References рдордзреВрди рди рджрд┐рд╕рдгрд╛рд░реА explicit dependency:

resource "aws_iam_role_policy" "read_timetables" {
  role   = aws_iam_role.app.id
  policy = data.aws_iam_policy_document.read.json
}

resource "aws_instance" "app" {
  ami                  = var.ami
  instance_type        = "t3.small"
  iam_instance_profile = aws_iam_instance_profile.app.name
  depends_on           = [aws_iam_role_policy.read_timetables]   # the app reads S3 at boot
}

рдХреНрд▓рд╛рд╕рд┐рдХ cycle тАФ рдПрдХрдореЗрдХрд╛рдВрдирд╛ рдкрд░рд╡рд╛рдирдЧреА рджреЗрдгрд╛рд░реЗ рджреЛрди security groups тАФ rules рд╡реЗрдЧрд│реНрдпрд╛ aws_vpc_security_group_ingress_rule resources рдордзреНрдпреЗ рд╣рд▓рд╡реВрди рддреЛрдбрд▓рд╛ рдЬрд╛рддреЛ, рдореНрд╣рдгрдЬреЗ рдкреНрд░рддреНрдпреЗрдХ group рдЖрдзреА рддрдпрд╛рд░ рд╣реЛрдК рд╢рдХрддреЛ рдЖрдгрд┐ rules рдирдВрддрд░.

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: apply рдЕрд░реНрдзреНрдпрд╛рд╡рд░ fail рдЭрд╛рд▓рд╛ рдХреА рдХрд╛рдп рдмрд╛рдВрдзрд▓реЗ рдЧреЗрд▓реЗ рдЖрдгрд┐ рдХрд╛рдп рдирд╛рд╣реА рддреЗ graph рд╕рд╛рдВрдЧрддреЛ. Error рд╡рд╛рдЪрд╛, рджреБрд░реБрд╕реНрдд рдХрд░рд╛, рдЖрдгрд┐ рдкреБрдиреНрд╣рд╛ plan рдХрд░рд╛ тАФ Terraform рд╕реБрд░реБрд╡рд╛рддреАрдкрд╛рд╕реВрди рдирд╛рд╣реА, state рдкрд╛рд╕реВрди рдкреБрдвреЗ рдЪрд╛рд▓реВ рдареЗрд╡рддреЗ.

тПня╕П рдкреБрдвреЗ

рддреАрдЪ рдЦреЛрд▓реА + gate + lockers рдкреБрдиреНрд╣рд╛ рдкреБрдиреНрд╣рд╛ рдпреЗрдд рд░рд╛рд╣рддрд╛рдд. рдкреБрдвреЗ: рддреЗ рдПрдХрджрд╛рдЪ module рдореНрд╣рдгреВрди рд▓рд┐рд╣рд╛ рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ wing рд╕рд╛рдареА рдмрд╛рдВрдзрд╛.

git checkout lesson-07-modules

ЁЯХ╕я╕П Lesson 06 тАФ The dependency graph: rooms before gates

ЁЯУН You are here: Lesson 06 of 12 ┬╖ Previous: lesson-05-state ┬╖ Next: lesson-07-modules


ЁЯУж What's in this branch

Lessons 01тАУ05, plus the way the contractor decides the order. Every reference (school_room.lab.id inside the gate) is an edge: the lab must exist before the gate. depends_on adds an edge the plans cannot see. Things with no path between them are built at the same time, up to a limit (-parallelism, 10 by default). Destroy runs the graph backwards. And a loop тАФ A needs B, B needs A тАФ is refused. graph() in iac/demo.py; _inst_deps(), graph() and apply() in iac/engine.py.

ЁЯзТ Explain like I'm 5

The plans say: a lab, a library, a main gate into the lab, a back gate into the library, and 4 lockers in the lab.

You can't hang a gate on a room that isn't built yet. ЁЯЪк So the contractor draws arrows: lab тЖТ main gate, lab тЖТ each locker, library тЖТ back gate. And one more arrow that the plans can't see by themselves: the school says "open the back gate only after the main gate exists" тАФ so Aishwarya writes it down with depends_on.

The contractor has 10 builders. ЁЯС╖ЁЯС╖ЁЯС╖

Three steps, not eight. To take the campus down, go backwards: gates and lockers first, rooms last.

ЁЯЧ║я╕П Diagram

flowchart LR
    lab["school_room.lab"] --> gm["school_gate.main"]
    lab --> l["school_locker.row[0..3]"]
    lib["school_room.library"] --> gb["school_gate.back"]
    gm -.->|"depends_on"| gb
    s1["step 1: 2 rooms"] --- s2["step 2: 1 gate + 4 lockers"] --- s3["step 3: back gate"]

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/terraform/lesson-diagrams.html#l06

тЭУ What

ЁЯдФ Why

Because the order is what makes one apply safe for a whole system: the network before the servers, the role before the service that uses it. Parallelism is what makes it fast. And the cycle check is what stops a design that can never be built тАФ Terraform tells you at plan time instead of failing halfway.

ЁЯФз How (in this repo)

expand() in iac/engine.py collects each block's references and depends_on. _inst_deps() turns them into instance-level edges (a reference to school_room.lab covers all its instances). graph() is Kahn's algorithm: it repeatedly takes every node whose dependencies are done; if none is ready but nodes are left, it finds the loop and raises CycleError. apply(..., parallelism=N) runs up to N ready operations per step тАФ a teaching model where every operation takes one step. Deletes wait for the resources that depended on them.

ЁЯзк Try it

python3 iac/demo.py graph
python3 - <<'EOF'
import sys; sys.path.insert(0, "iac")
from cloud import FakeCloud
from engine import plan, apply
from demo import GRAPH
for par in (1, 2, 3, 4, 5, 10):
    _, steps, _ = apply(plan(GRAPH, None, FakeCloud()), FakeCloud(), parallelism=par)
    print(f"parallelism {par:>2} тЖТ {len(steps)} steps {[len(s) for s in steps]}")
flat = {"resource": {"school_room": {"lab": {"name": "lab"}},
        "school_locker": {"row": {"count": 6, "room_id": "${school_room.lab.id}", "label": "${count.index}"}}}}
_, steps, _ = apply(plan(flat, None, FakeCloud()), FakeCloud())
print("1 room + 6 lockers тЖТ", [len(s) for s in steps])
EOF

тЬЕ Verify тАФ what you should see

graph prints:

тФАтФА parallelism 10: 3 steps for 8 resources тЖТ [2, 5, 1] per step
   step 1: school_room.lab, school_room.library
   step 2: school_gate.main, school_locker.row[0], school_locker.row[1], school_locker.row[2], school_locker.row[3]
   step 3: school_gate.back
тФАтФА destroy runs the graph backwards:
   step 1: school_locker.row[0], school_locker.row[1], school_locker.row[2], school_locker.row[3], school_gate.back
   step 2: school_room.library, school_gate.main
   step 3: school_room.lab
тФАтФА a gate that needs a locker that needs the gate тЖТ Error: Cycle: school_gate.g, school_locker.l

Your snippet prints:

parallelism  1 тЖТ 8 steps [1, 1, 1, 1, 1, 1, 1, 1]
parallelism  2 тЖТ 4 steps [2, 2, 2, 2]
parallelism  3 тЖТ 3 steps [2, 3, 3]
parallelism  4 тЖТ 3 steps [2, 4, 2]
parallelism  5 тЖТ 3 steps [2, 5, 1]
parallelism 10 тЖТ 3 steps [2, 5, 1]
1 room + 6 lockers тЖТ [1, 6]

ЁЯПБ What you just proved

The graph, not the order you wrote the blocks in, decides the order. With enough builders the campus took 3 steps тАФ the length of the longest chain (lab тЖТ main gate тЖТ back gate) тАФ and more than 5 builders did not help, because step 2 never has more than 5 things ready. With 1 builder it took 8 steps. Destroy ran the same graph backwards, and the loop was refused before anything was built.

тЪая╕П Common mistakes

ЁЯПн In production

On a real account тАФ draw the real graph and control the walk:

terraform graph | dot -Tsvg > graph.svg     # needs Graphviz; open graph.svg in a browser
terraform apply -parallelism=5              # fewer concurrent API calls

An explicit dependency that references cannot show:

resource "aws_iam_role_policy" "read_timetables" {
  role   = aws_iam_role.app.id
  policy = data.aws_iam_policy_document.read.json
}

resource "aws_instance" "app" {
  ami                  = var.ami
  instance_type        = "t3.small"
  iam_instance_profile = aws_iam_instance_profile.app.name
  depends_on           = [aws_iam_role_policy.read_timetables]   # the app reads S3 at boot
}

The classic cycle тАФ two security groups that allow each other тАФ is broken by moving the rules into separate aws_vpc_security_group_ingress_rule resources, so each group can be created first and the rules afterwards.

ЁЯПн Why this matters in production: when an apply fails halfway, the graph tells you what was built and what was not. Read the error, fix it, and plan again тАФ Terraform continues from the state, not from the start.

тПня╕П Next

The same room + gate + lockers keeps coming back. Next: write it once as a module and build it for every wing.

git checkout lesson-07-modules
тЖР PreviousstateNext тЖТmodules

This page is the lesson's README from the lesson-06-dependency-graph branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.