ЁЯХ╕я╕П рдзрдбрд╛ 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 рдмрд╛рдВрдзрдХрд╛рдо рдХрд░рдгрд╛рд░реЗ рдЖрд╣реЗрдд. ЁЯС╖ЁЯС╖ЁЯС╖
- рдкрд╛рдпрд░реА 1: lab рдЖрдгрд┐ library тАФ рдЖрдзреА рдХрд╛рд╣реАрдЪ рдпрд╛рдпрд▓рд╛ рдирдХреЛ. рджреЛрдиреНрд╣реА рдПрдХрджрдо.
- рдкрд╛рдпрд░реА 2: рдореБрдЦреНрдп gate рдЖрдгрд┐ рдЪрд╛рд░рд╣реА lockers тАФ lab рддрдпрд╛рд░ рдЖрд╣реЗ. 5 рдПрдХрджрдо.
- рдкрд╛рдпрд░реА 3: рдорд╛рдЧрдЪреЗ gate тАФ рддреЗ рдореБрдЦреНрдп gate рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рдд рд╣реЛрддреЗ.
рдЖрда рдирд╛рд╣реА, рддреАрди рдкрд╛рдпрд▒реНрдпрд╛. 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
тЭУ рдХрд╛рдп
- Dependency graph тАФ рдПрдХ directed graph: nodes рдореНрд╣рдгрдЬреЗ resources, A тЖТ B edge рдЪрд╛ рдЕрд░реНрде "B рдЖрдзреА A рдкреВрд░реНрдг рд╡реНрд╣рд╛рдпрд▓рд╛ рд╣рд╡рд╛". Terraform рддреЛ config рдЖрдгрд┐ state рд╡рд░реВрди рдмрд╛рдВрдзрддреЗ.
- Implicit dependency тАФ reference рдореБрд│реЗ рддрдпрд╛рд░ рд╣реЛрддреЗ.
room_id = school_room.lab.idрдореБрд│реЗ gate lab рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рд░рд╛рд╣рддреЗ. рдмрд╣реБрддреЗрдХ рдХреНрд░рдо рдЕрд╕рд╛рдЪ рдард░рддреЛ, рдЖрдгрд┐ рд╣рд╛рдЪ рдкрд╕рдВрддреАрдЪрд╛ рдорд╛рд░реНрдЧ рдЖрд╣реЗ. - Explicit dependency тАФ
depends_on = [school_gate.main], references рдордзреВрди рди рджрд┐рд╕рдгрд╛рд▒реНрдпрд╛ рдХреНрд░рдорд╛рд╕рд╛рдареА (service рд╡рд╛рдкрд░рд╛рдпрд▓рд╛ рд╕реБрд░реБрд╡рд╛рдд рдХрд░рдгреНрдпрд╛рдЖрдзреА рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рд╣рд╡реА рдЕрд╕рд▓реЗрд▓реА permission). рдХреНрд╡рдЪрд┐рддрдЪ рд╡рд╛рдкрд░рд╛: рддреНрдпрд╛рдореБрд│реЗ plans рдЕрдзрд┐рдХ рд╕рд╛рд╡рдз (conservative) рд╣реЛрддрд╛рдд. - Directed acyclic graph (DAG) тАФ graph рдордзреНрдпреЗ cycles рдирд╕рд╛рдпрд▓рд╛рдЪ рд╣рд╡реЗрдд. Terraform
Error: Cycle: тАжрджрд╛рдЦрд╡рддреЗ рдЖрдгрд┐ loop рдордзреАрд▓ nodes рдЪреА рдирд╛рд╡реЗ рд╕рд╛рдВрдЧрддреЗ. - Parallel walk тАФ рдЬреНрдпрд╛рдВрдЪреНрдпрд╛ dependencies рдкреВрд░реНрдг рдЭрд╛рд▓реНрдпрд╛ рдЖрд╣реЗрдд рдЕрд╢рд╛ рдкреНрд░рддреНрдпреЗрдХ node рд╡рд░ Terraform рдХрд╛рдо рдХрд░рддреЗ, рдПрдХрд╛ рд╡реЗрд│реА
-parallelism=Nрдкрд░реНрдпрдВрдд (default 10). - Destroy рдЪрд╛ рдХреНрд░рдо тАФ рдЙрд▓рдЯрд╛: рдПрдЦрд╛рджреНрдпрд╛ node рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдЕрд╕рд▓реЗрд▓реЗ рд╕рдЧрд│реЗ рдЧреЗрд▓реНрдпрд╛рдирдВрддрд░рдЪ рддреЛ destroy рд╣реЛрддреЛ.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рдХреНрд░рдорд╛рдореБрд│реЗрдЪ рд╕рдВрдкреВрд░реНрдг 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 рдирд╛рдХрд╛рд░рд▓рд╛ рдЧреЗрд▓рд╛.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- "рд╕реБрд░рдХреНрд╖рд┐рдд рд░рд╛рд╣рд╛рд╡реЗ рдореНрд╣рдгреВрди" рд╕рдЧрд│реАрдХрдбреЗ
depends_onрдЬреЛрдбрдгреЗ тАФ plans рд╣рд│реВ рд╣реЛрддрд╛рдд, рдЖрдгрд┐ рдореВрд▓реНрдпреЗ рдЬрд╛рд╕реНрдд рдХрд╛рд│ unknown рд░рд╛рд╣рддрд╛рдд - reference рдРрд╡рдЬреА id рдХрд┐рдВрд╡рд╛ рдирд╛рд╡ hard-code рдХрд░реВрди рдЦрд░реА dependency рд▓рдкрд╡рдгреЗ
- рдПрдХрдореЗрдХрд╛рдВрдЪрд╛ id рд▓рд╛рдЧрдгрд╛рд▒реНрдпрд╛ рджреЛрди resources рдордзреАрд▓ cycle тАФ рдПрдХрд╛рдЪреЗ рджреЛрди resources рдордзреНрдпреЗ рд╡рд┐рднрд╛рдЬрди рдХрд░рд╛ (рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде security group рдЖрдгрд┐ рд╡реЗрдЧрд│рд╛ rule)
-parallelismрдЦреВрдк рдЬрд╛рд╕реНрдд рдареЗрд╡рдгреЗ рдЖрдгрд┐ cloud API рдЪреНрдпрд╛ rate limits рд▓рд╛ рдзрдбрдХрдгреЗ- рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ state files рдордзреАрд▓ resources рдЪрд╛ рдХреНрд░рдо рд▓рд╛рдЧреЗрд▓ рдЕрд╢реА рдЕрдкреЗрдХреНрд╖рд╛ рдареЗрд╡рдгреЗ тАФ graph state рдЪреНрдпрд╛ рд╕реАрдореЗрд╡рд░ рдерд╛рдВрдмрддреЛ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ 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