ืึธื˜ืึทืžืึทื˜ื™ืง ื“ื•ืจ ืื•ืŸ ืคื™ืœื•ื ื’ ืคื•ืŸ ื ืขืฅ ืžื™ื˜ืœ ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทืŸ ืขืœืขืžืขื ื˜ืŸ ื ื™ืฆืŸ Nornir

ืึธื˜ืึทืžืึทื˜ื™ืง ื“ื•ืจ ืื•ืŸ ืคื™ืœื•ื ื’ ืคื•ืŸ ื ืขืฅ ืžื™ื˜ืœ ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทืŸ ืขืœืขืžืขื ื˜ืŸ ื ื™ืฆืŸ Nornir

ื”ื™ื™ ื”ืื‘ืจ!

ืœืขืฆื˜ื ืก ืื™ื– ืืจื•ื™ืก ื ืืจื˜ื™ืงืœ ื“ื ืžื™ืงืจืึธื˜ื™ืง ืื•ืŸ ืœื™ื ื•ืงืก. ืจื•ื˜ื™ืŸ ืื•ืŸ ืึธื˜ืึทืžื™ื™ืฉืึทืŸ ื•ื•ื• ืึทืŸ ืขื ืœืขื›ืข ืคึผืจืึธื‘ืœืขื ืื™ื– ืกืึทืœื•ื•ื“ ื ื™ืฆืŸ ืคืึทืกืึทืœ ืžื™ื˜ืœ. ืื•ืŸ ื›ืึธื˜ืฉ ื“ื™ ืึทืจื‘ืขื˜ ืื™ื– ื’ืึธืจ ื˜ื™ืคึผื™ืฉ, ืขืก ืื™ื– ื’ืึธืจื ื™ืฉื˜ ืขื ืœืขืš ื•ื•ืขื’ืŸ ืื™ื ืื•ื™ืฃ Habrรฉ. ืื™ืš ืึทืจื•ื™ืกืคืึธื“ืขืจืŸ ืฆื• ืคืึธืจืฉืœืึธื’ืŸ ืžื™ื™ืŸ ื•ื•ืขืœืึธืกื™ืคึผืขื“ ืฆื• ื“ื™ ืจืขืกืคึผืขืงื˜ืขื“ IT ืงื”ืœ.

ื“ืึธืก ืื™ื– ื ื™ืฉื˜ ื“ืขืจ ืขืจืฉื˜ืขืจ ื‘ื™ื™ืง ืคึฟืึทืจ ืึทื–ืึท ืึท ืึทืจื‘ืขื˜. ื“ืขืจ ืขืจืฉื˜ืขืจ ืึธืคึผืฆื™ืข ืื™ื– ื™ืžืคึผืœืึทืžืขื ืึทื“ ืขื˜ืœืขื›ืข ื™ืึธืจ ืฆื•ืจื™ืง ืฆื•ืจื™ืง ืื™ืŸ ืึทื ืกืึทื‘ืœืข ื•ื•ืขืจืกื™ืข 1.ืงืก.ืงืก. ื“ื™ ื•ื•ืขืœืึธืกื™ืคึผืขื“ ืื™ื– ืจืึทืจืขืœื™ ื’ืขื ื™ืฆื˜ ืื•ืŸ ื“ืขืจื™ื‘ืขืจ ืงืขืกื™ื™ื“ืขืจ ืจืึทืกื˜ื™ื“. ืื™ืŸ ื“ืขื ื–ื™ื ืขืŸ ืึทื– ื“ื™ ืึทืจื‘ืขื˜ ื–ื™ืš ื˜ื•ื˜ ื ื™ืฉื˜ ืื•ื™ืคืฉื˜ื™ื™ืŸ ื•ื•ื™ ืึธืคื˜ ื•ื•ื™ ื•ื•ืขืจืกื™ืขืก ื–ืขื ืขืŸ ื“ืขืจื”ื™ื™ึทื ื˜ื™ืงื˜ ืึทื ืกืึทื‘ืœืข. ืื•ืŸ ื™ืขื“ืขืก ืžืึธืœ ื•ื•ืขืŸ ืžืขืŸ ื“ืึทืจืฃ ืคืึธืจ, ืคึฟืึทืœื˜ ื“ื™ ืงื™ื™ื˜ ืึธื“ืขืจ ื“ืึธืก ืจืึธื“. ืึธื‘ืขืจ, ื“ืขืจ ืขืจืฉื˜ืขืจ ื˜ื™ื™ืœ, ื“ื–ืฉืขื ืขืจื™ื™ื˜ื™ื ื’ ืงืึธื ืคื™ื’ืก, ืฉื˜ืขื ื“ื™ืง ืึทืจื‘ืขื˜ ื–ื™ื™ืขืจ ืงืœืืจ, ื’ืœื™ืง jinja2 ื“ืขืจ ืžืึธื˜ืึธืจ ืื™ื– ืœืึทื ื’ ื’ืขื’ืจื™ื ื“ืขื˜. ืื‘ืขืจ ื“ืขืจ ืฆื•ื•ื™ื™ื˜ืขืจ ื˜ื™ื™ืœ - ืจืึธื•ืœื™ื ื’ ืื•ื™ืก ืงืึธื ืคื™ื’ืก - ื™ื•ื–ืฉืึทื•ื•ืึทืœื™ ื’ืขื‘ืจืื›ื˜ ืกืึทืคึผืจื™ื™ื–ื™ื–. ืื•ืŸ ื–ื™ื ื˜ ืื™ืš ื”ืึธื‘ืŸ ืฆื• ืจืึธื•ืœื™ื ื’ ื“ื™ ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทืŸ ืจื™ืžืึธื•ื˜ืœื™ ืฆื• ื”ืขืœืคื˜ ืึท ื”ื•ื ื“ืขืจื˜ ื“ืขื•ื•ื™ืกืขืก, ืขื˜ืœืขื›ืข ืคื•ืŸ โ€‹โ€‹ื•ื•ืึธืก ื–ืขื ืขืŸ ืœื™ื’ืŸ ื˜ื•ื™ื–ื ื˜ืขืจ ืคื•ืŸ ืงื™ืœืึธืžืขื˜ืขืจืก ืึทื•ื•ืขืง, ื ื™ืฆืŸ ื“ืขื ื’ืขืฆื™ื™ึทื’ ืื™ื– ื’ืขื•ื•ืขืŸ ืึท ื‘ื™ืกืœ ื ื•ื“ื ืข.

ื“ืึธ ืื™ืš ืžื•ื–ืŸ ืึทืจื™ื™ึทื ืœืึธื–ืŸ ืึทื– ืžื™ื™ืŸ ืึทื ืกืขืจื˜ืึทื ื˜ื™ ืœื™ื’ื˜ ืจื•ื‘ึฟ ืžืกืชึผืžื ืื™ืŸ ืžื™ื™ืŸ ืžืึทื ื’ืœ ืคื•ืŸ ืคืึทืžื™ืœื™ืขืจืึทื˜ื™ ืžื™ื˜ ืึทื ืกืึทื‘ืœืขื•ื•ื™ ืื™ืŸ ืื™ืจืข ื—ืกืจื•ื ื•ืช. ืื•ืŸ ื“ืึธืก, ืื’ื‘, ืื™ื– ืึท ื•ื•ื™ื›ื˜ื™ืง ืคื•ื ื˜. ืึทื ืกืึทื‘ืœืข ืื™ื– ืึท ื’ืึธืจ ื‘ืึทื–ื•ื ื“ืขืจ, ื–ื™ื™ืŸ ืื™ื™ื’ืขื ืข ืฉื˜ื— ืคื•ืŸ ื•ื•ื™ืกืŸ ืžื™ื˜ ื–ื™ื™ืŸ ืื™ื™ื’ืขื ืข DSL (Domain Specific Language), ื•ื•ืึธืก ืžื•ื–ืŸ ื–ื™ื™ืŸ ืžื™ื™ื ื˜ื™ื™ื ื“ ืื•ื™ืฃ ืึท ื–ื™ื›ืขืจ ืžื“ืจื’ื”. ื ื•, ืึทื– ืžืึธืžืขื ื˜ ืึทื– ืึทื ืกืึทื‘ืœืข ืขืก ืื™ื– ื“ืขื•ื•ืขืœืึธืคึผื™ื ื’ ื’ืึทื ืฅ ื’ืขืฉื•ื•ื™ื ื“, ืื•ืŸ ืึธืŸ ืกืคึผืขืฆื™ืขืœ ืื›ื˜ื•ื ื’ ืคึฟืึทืจ ืฆื•ืจื™ืง ืงืึทืžืคึผืึทื˜ืึทื‘ื™ืœืึทื˜ื™, ืขืก ื˜ื•ื˜ ื ื™ืฉื˜ ืœื™ื™ื’ืŸ ื‘ื˜ื—ื•ืŸ.

ื“ืขืจื™ื‘ืขืจ, ื ื™ื˜ ืึทื–ื•ื™ ืœืึทื ื’ ืฆื•ืจื™ืง ืึท ืฆื•ื•ื™ื™ื˜ ื•ื•ืขืจืกื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ื•ื•ืขืœืึธืกื™ืคึผืขื“ ืื™ื– ื™ืžืคึผืœืึทืžืขื ืึทื“. ื“ืึธืก ืžืึธืœ ืื•ื™ืฃ ืคึผื™ื˜ื”ืึธืŸ, ืึธื“ืขืจ ื’ืึทื ืฅ ืื•ื™ืฃ ืึท ืคืจื™ื™ืžื•ื•ืขืจืง ื’ืขืฉืจื™ื‘ืŸ ืื™ืŸ ืคึผื™ื˜ื”ืึธืŸ ืื•ืŸ ืคึฟืึทืจ ืคึผื™ื˜ื”ืึธืŸ ื’ืขืจื•ืคืŸ ื ืึธืจื ื™ืจ

ืื–ื•ื™ โ€” ื ืึธืจื ื™ืจ ืื™ื– ืึท ืžื™ืงืจืึธืคืจืึทืžืขื•ื•ืึธืจืง ื’ืขืฉืจื™ื‘ืŸ ืื™ืŸ ืคึผื™ื˜ื”ืึธืŸ ืื•ืŸ ืคึฟืึทืจ ืคึผื™ื˜ื”ืึธืŸ ืื•ืŸ ื“ื™ื–ื™ื™ื ื“ ืคึฟืึทืจ ืึธื˜ืึทืžื™ื™ืฉืึทืŸ. ื“ื™ ื–ืขืœื‘ืข ื•ื•ื™ ืื™ืŸ ื“ืขื ืคืึทืœ ืžื™ื˜ ืึทื ืกืึทื‘ืœืข, ืฆื• ืกืึธืœื•ื•ืข ืคึผืจืึธื‘ืœืขืžืก ื“ืึธ, ืงืึธืžืคึผืขื˜ืขื ื˜ ื“ืึทื˜ืŸ ืฆื•ื’ืจื™ื™ื˜ื•ื ื’ ืื™ื– ืคืืจืœืื ื’ื˜, ื™.ืข. ื™ื ื•ื•ืึทื ื˜ืึธืจื™ ืคื•ืŸ ืžื—ื ื•ืช ืื•ืŸ ื–ื™ื™ืขืจ ืคึผืึทืจืึทืžืขื˜ืขืจืก, ืึธื‘ืขืจ ืกืงืจื™ืคึผืก ื–ืขื ืขืŸ ื’ืขืฉืจื™ื‘ืŸ ื ื™ืฉื˜ ืื™ืŸ ืึท ื‘ืึทื–ื•ื ื“ืขืจ ื“ืกืœ, ืึธื‘ืขืจ ืื™ืŸ ื“ืขืจ ื–ืขืœื‘ื™ืงืขืจ ื ื™ืฉื˜ ื–ื™ื™ืขืจ ืึทืœื˜, ืึธื‘ืขืจ ื–ื™ื™ืขืจ ื’ื•ื˜ ืคึผ[ื™|ื™]ื˜ืึธืŸ.

ื–ืืœ ืก ืงื•ืง ืื™ืŸ ื•ื•ืึธืก ืขืก ืื™ื– ื ื™ืฆืŸ ื“ื™ ืคืืœื’ืขื ื“ืข ืœืขื‘ืŸ ื‘ื™ื™ึทืฉืคึผื™ืœ.

ืื™ืš ื”ืึธื‘ืŸ ืึท ืฆื•ื•ื™ื™ึทื’ ื ืขืฅ ืžื™ื˜ ืขื˜ืœืขื›ืข ื˜ื•ืฅ ืึธืคืึทืกื™ื– ืื™ื‘ืขืจ ื“ื™ ืžื“ื™ื ื”. ื™ืขื“ืขืจ ืึธืคื™ืก ื”ืื˜ ืึท ื•ื•ืึทืŸ ืจืึทื•ื˜ืขืจ ื•ื•ืึธืก ื˜ืขืจืžืึทื ื™ื™ืฅ ืขื˜ืœืขื›ืข ืงืึธืžื•ื ื™ืงืึทืฆื™ืข ื˜ืฉืึทื ืึทืœื– ืคื•ืŸ ืคืึทืจืฉื™ื“ืขื ืข ืึธืคึผืขืจื™ื™ื˜ืขืจื–. ื“ื™ ืจื•ื˜ื™ื ื’ ืคึผืจืึธื˜ืึธืงืึธืœ ืื™ื– BGP. ื•ื•ืึทืŸ ืจืึธื•ื˜ืขืจืก ืงื•ืžืขืŸ ืื™ืŸ ืฆื•ื•ื™ื™ ื˜ื™ื™ืคึผืก: Cisco ISG ืึธื“ืขืจ Juniper SRX.

ืื™ืฆื˜ ื“ื™ ืึทืจื‘ืขื˜: ืื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ืงืึทื ืคื™ื’ื™ืขืจ ืึท ื“ืขื“ืึทืงื™ื™ื˜ืึทื“ ืกื•ื‘ื ืขื˜ ืคึฟืึทืจ ื•ื•ื™ื“ืขื ืกืขืจื•ื•ื™ื™ืœืึทื ืก ืื•ื™ืฃ ืึท ื‘ืึทื–ื•ื ื“ืขืจ ืคึผืึธืจื˜ ืื•ื™ืฃ ืึทืœืข WAN ืจืึธื•ื˜ืขืจืก ืคื•ืŸ ื“ื™ ืฆื•ื•ื™ื™ึทื’ ื ืขืฅ - ืžืขืœื“ืŸ ื“ืขื ืกื•ื‘ื ืขื˜ ืื™ืŸ BGP - ืงืึทื ืคื™ื’ื™ืขืจ ื“ื™ ื’ื™ื›ืงื™ื™ึทื˜ ืฉื™ืขื•ืจ ืคื•ืŸ ื“ื™ ื“ืขื“ืึทืงื™ื™ื˜ืึทื“ ืคึผืึธืจื˜.

ืขืจืฉื˜ืขืจ, ืžื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ืฆื•ื’ืจื™ื™ื˜ืŸ ืึท ืคึผืึธืจ ืคื•ืŸ ื˜ืขืžืคึผืœืึทื˜ืขืก, ืื•ื™ืฃ ื“ืขืจ ื‘ืื–ืข ืคื•ืŸ โ€‹โ€‹ื•ื•ืึธืก ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทื ื– ื•ื•ืขื˜ ื–ื™ื™ืŸ ื“ื–ืฉืขื ืขืจื™ื™ื˜ืึทื“ ืกืขืคึผืขืจืึทื˜ืœื™ ืคึฟืึทืจ ืกื™ืกืงืึธ ืื•ืŸ ื“ื–ืฉื•ื ื™ืคึผืขืจ. ืขืก ืื™ื– ืื•ื™ืš ื ื™ื™ื˜ื™ืง ืฆื• ืฆื•ื’ืจื™ื™ื˜ืŸ ื“ืึทื˜ืŸ ืคึฟืึทืจ ื™ืขื“ืขืจ ืคื•ื ื˜ ืื•ืŸ ืงืฉืจ ืคึผืึทืจืึทืžืขื˜ืขืจืก, ื™.ืข. ืงืœื™ื™ึทื‘ืŸ ื“ื™ ื–ืขืœื‘ืข ื™ื ื•ื•ืึทื ื˜ืึธืจื™

ื’ืจื™ื™ื˜ ืžื•ืกื˜ืขืจ ืคึฟืึทืจ Cisco:

$ cat templates/ios/base.j2 
class-map match-all VIDEO_SURV
 match access-group 111

policy-map VIDEO_SURV
 class VIDEO_SURV
    police 1500000 conform-action transmit  exceed-action drop

interface {{ host.task_data.ifname }}
  description VIDEOSURV
  ip address 10.10.{{ host.task_data.ipsuffix }}.254 255.255.255.0
  service-policy input VIDEO_SURV

router bgp {{ host.task_data.asn }}
  network 10.40.{{ host.task_data.ipsuffix }}.0 mask 255.255.255.0

access-list 11 permit 10.10.{{ host.task_data.ipsuffix }}.0 0.0.0.255
access-list 111 permit ip 10.10.{{ host.task_data.ipsuffix }}.0 0.0.0.255 any

ืžื•ืกื˜ืขืจ ืคึฟืึทืจ ื“ื–ืฉื•ื ื™ืคึผืขืจ:

$ cat templates/junos/base.j2 
set interfaces {{ host.task_data.ifname }} unit 0 description "Video surveillance"
set interfaces {{ host.task_data.ifname }} unit 0 family inet filter input limit-in
set interfaces {{ host.task_data.ifname }} unit 0 family inet address 10.10.{{ host.task_data.ipsuffix }}.254/24
set policy-options policy-statement export2bgp term 1 from route-filter 10.10.{{ host.task_data.ipsuffix }}.0/24 exact
set security zones security-zone WAN interfaces {{ host.task_data.ifname }}
set firewall policer policer-1m if-exceeding bandwidth-limit 1m
set firewall policer policer-1m if-exceeding burst-size-limit 187k
set firewall policer policer-1m then discard
set firewall policer policer-1.5m if-exceeding bandwidth-limit 1500000
set firewall policer policer-1.5m if-exceeding burst-size-limit 280k
set firewall policer policer-1.5m then discard
set firewall filter limit-in term 1 then policer policer-1.5m
set firewall filter limit-in term 1 then count limiter

ื˜ืขืžืคึผืœืึทื˜ืขืก, ืคื•ืŸ ืงื•ืจืก, ื˜ืึธืŸ ื ื™ื˜ ืงื•ืžืขืŸ ืื•ื™ืก ืคื•ืŸ ื“ื™ืŸ ืœื•ืคื˜. ื“ืึธืก ื–ืขื ืขืŸ ื‘ื™ื™ืกื™ืงืœื™ ื“ื™ืคืขืจืึทื ืกื™ื– ืฆื•ื•ื™ืฉืŸ ื“ื™ ืืจื‘ืขื˜ืŸ ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทื ื– ื•ื•ืึธืก ื–ืขื ืขืŸ ื’ืขื•ื•ืขืŸ ืื•ืŸ ื–ืขื ืขืŸ ื’ืขื•ื•ืขืŸ ื ืึธืš ืกืึทืœื•ื•ื™ื ื’ ื“ื™ ืึทืจื‘ืขื˜ ืื•ื™ืฃ ืฆื•ื•ื™ื™ ืกืคึผืขืฆื™ืคื™ืฉ ืจืึธื•ื˜ืขืจืก ืคื•ืŸ ืคืึทืจืฉื™ื“ืขื ืข ืžืึธื“ืขืœืก.

ืคึฟื•ืŸ ืื•ื ื“ื–ืขืจ ื˜ืขืžืคึผืœืึทื˜ืขืก ืžื™ืจ ื–ืขืŸ ืึทื– ืฆื• ืกืึธืœื•ื•ืข ื“ื™ ืคึผืจืึธื‘ืœืขื, ืžื™ืจ ื ืึธืจ ื“ืึทืจืคึฟืŸ ืฆื•ื•ื™ื™ ืคึผืึทืจืึทืžืขื˜ืขืจืก ืคึฟืึทืจ ื“ื–ืฉื•ื ื™ืคึผืขืจ ืื•ืŸ 3 ืคึผืึทืจืึทืžืขื˜ืขืจืก ืคึฟืึทืจ ืกื™ืกืงืึธ. ื“ืึธ ื–ื™ื™ ื–ืขื ืขืŸ:

  • ifname
  • ipsuffix
  • asn

ืื™ืฆื˜ ืžื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ืฉื˜ืขืœืŸ ื“ื™ ืคึผืึทืจืึทืžืขื˜ืขืจืก ืคึฟืึทืจ ื™ืขื“ืขืจ ืžื™ื˜ืœ, ื™.ืข. ื˜ืึธืŸ ื“ื™ ื–ืขืœื‘ืข ื–ืึทืš ื™ื ื•ื•ืึทื ื˜ืึธืจื™.

ืคืึทืจ ื™ื ื•ื•ืึทื ื˜ืึธืจื™ ืžื™ืจ ื•ื•ืขืœืŸ ืฉื˜ืจืขื ื’ ื ืึธื›ืคืึธืœื’ืŸ ื“ื™ ื“ืึทืงื™ื•ืžืขื ื˜ื™ื™ืฉืึทืŸ ื™ื ื™ื˜ื™ืึทืœื™ื–ื™ื ื’ ื ืึธืจื ื™ืจ

ื“ืึธืก ืื™ื–, ืœืึธื–ืŸ ืื•ื ื“ื– ืžืึทื›ืŸ ื“ื™ ื–ืขืœื‘ืข ื˜ืขืงืข ืกืงืขืœืขื˜:

.
โ”œโ”€โ”€ config.yaml
โ”œโ”€โ”€ inventory
โ”‚   โ”œโ”€โ”€ defaults.yaml
โ”‚   โ”œโ”€โ”€ groups.yaml
โ”‚   โ””โ”€โ”€ hosts.yaml

ื“ื™ config.yaml ื˜ืขืงืข ืื™ื– ื“ืขืจ ื ืึธืจืžืึทืœ nornir ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทืŸ ื˜ืขืงืข

$ cat config.yaml 
---
core:
    num_workers: 10

inventory:
    plugin: nornir.plugins.inventory.simple.SimpleInventory
    options:
        host_file: "inventory/hosts.yaml"
        group_file: "inventory/groups.yaml"
        defaults_file: "inventory/defaults.yaml"

ืžื™ืจ ื•ื•ืขืœืŸ ืึธื ื•ื•ื™ื™ึทื–ืŸ ื“ื™ ื”ื•ื™ืคึผื˜ ืคึผืึทืจืึทืžืขื˜ืขืจืก ืื™ืŸ ื“ืขืจ ื˜ืขืงืข hosts.yaml, ื’ืจื•ืคึผืข (ืื™ืŸ ืžื™ื™ืŸ ืคืึทืœ, ื“ืึธืก ื–ืขื ืขืŸ ืœืึธื’ื™ื ืก / ืคึผืึทืกื•ื•ืขืจื“ื–) ืื™ืŸ ื’ืจื•ืคึผืขืก.ื™ืึทืžืœืื•ืŸ ืื™ืŸ defaults.yaml ืžื™ืจ ื•ื•ืขืœืŸ ื ื™ืฉื˜ ืึธื ื•ื•ื™ื™ึทื–ืŸ ืขืคึผืขืก, ืึธื‘ืขืจ ืื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ืึทืจื™ื™ึทืŸ ื“ืจื™ื™ ืžื™ื ื•ืกืขืก ื“ืึธืจื˜ - ื•ื•ืึธืก ื™ื ื“ื™ืงื™ื™ืฅ ืึทื– ื“ืึธืก ืื™ื– yaml ื“ื™ ื˜ืขืงืข ืื™ื– ืœื™ื™ื“ื™ืง ื›ืึธื˜ืฉ.

ื“ืึธืก ืื™ื– ื•ื•ื™ hosts.yaml ืงื•ืงื˜ ื•ื•ื™:

---
srx-test:
    hostname: srx-test
    groups: 
        - juniper
    data:
        task_data:
            ifname: fe-0/0/2
            ipsuffix: 111

cisco-test:
    hostname: cisco-test
    groups: 
        - cisco
    data:
        task_data:
            ifname: GigabitEthernet0/1/1
            ipsuffix: 222
            asn: 65111

ืื•ืŸ ื“ืึธ ืื™ื– ื’ืจื•ืคึผืขืก.ื™ืึทืžืœ:

---
cisco:
    platform: ios
    username: admin1
    password: cisco1

juniper:
    platform: junos
    username: admin2
    password: juniper2

ื“ืืก ืื™ื– ื•ื•ืึธืก ื’ืขื˜ืจืืคืŸ ื™ื ื•ื•ืึทื ื˜ืึธืจื™ ืคึฟืึทืจ ืื•ื ื“ื–ืขืจ ืึทืจื‘ืขื˜. ื‘ืขืฉืึทืก ื™ื ื™ื˜ื™ืึทืœื™ื–ืึทื˜ื™ืึธืŸ, ืคึผืึทืจืึทืžืขื˜ืขืจืก ืคื•ืŸ ื™ื ื•ื•ืึทื ื˜ืึธืจื™ ื˜ืขืงืขืก ื–ืขื ืขืŸ ืžืึทืคึผื˜ ืฆื• ื“ื™ ื›ื™ื™ืคืขืฅ ืžืึธื“ืขืœ ื™ื ื•ื•ืขื ื˜ืึธืจื™ ืขืœืขืžืขื ื˜.

ื•ื ื˜ืขืจ ื“ืขืจ ืกืคึผื•ื™ืœืขืจ ืื™ื– ืึท ื“ื™ืึทื’ืจืึทืžืข ืคื•ืŸ โ€‹โ€‹ื“ื™ InventoryElement ืžืึธื“ืขืœ

print(json.dumps(InventoryElement.schema(), indent=4))
{
    "title": "InventoryElement",
    "type": "object",
    "properties": {
        "hostname": {
            "title": "Hostname",
            "type": "string"
        },
        "port": {
            "title": "Port",
            "type": "integer"
        },
        "username": {
            "title": "Username",
            "type": "string"
        },
        "password": {
            "title": "Password",
            "type": "string"
        },
        "platform": {
            "title": "Platform",
            "type": "string"
        },
        "groups": {
            "title": "Groups",
            "default": [],
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "data": {
            "title": "Data",
            "default": {},
            "type": "object"
        },
        "connection_options": {
            "title": "Connection_Options",
            "default": {},
            "type": "object",
            "additionalProperties": {
                "$ref": "#/definitions/ConnectionOptions"
            }
        }
    },
    "definitions": {
        "ConnectionOptions": {
            "title": "ConnectionOptions",
            "type": "object",
            "properties": {
                "hostname": {
                    "title": "Hostname",
                    "type": "string"
                },
                "port": {
                    "title": "Port",
                    "type": "integer"
                },
                "username": {
                    "title": "Username",
                    "type": "string"
                },
                "password": {
                    "title": "Password",
                    "type": "string"
                },
                "platform": {
                    "title": "Platform",
                    "type": "string"
                },
                "extras": {
                    "title": "Extras",
                    "type": "object"
                }
            }
        }
    }
}

ื“ืขืจ ืžืึธื“ืขืœ ืงืขืŸ ืงื•ืงืŸ ืึท ื‘ื™ืกืœ ืงืึทื ืคื™ื•ื–ื™ื ื’, ืกืคึผืขืฆื™ืขืœ ืื™ืŸ ืขืจืฉื˜ืขืจ. ืื™ืŸ ืกื“ืจ ืฆื• ืจืขื›ืขื ืขืŸ ืขืก ืื•ื™ืก, ื“ื™ ื™ื ื˜ืขืจืึทืงื˜ื™ื•ื• ืžืึธื“ืข ืื™ืŸ ืคึผื™ื˜ื”ืึธืŸ.

 $ ipython3
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.1.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from nornir import InitNornir                                                                           

In [2]: nr = InitNornir(config_file="config.yaml", dry_run=True)                                                

In [3]: nr.inventory.hosts                                                                                      
Out[3]: 
{'srx-test': Host: srx-test, 'cisco-test': Host: cisco-test}

In [4]: nr.inventory.hosts['srx-test'].data                                                                                    
Out[4]: {'task_data': {'ifname': 'fe-0/0/2', 'ipsuffix': 111}}

In [5]: nr.inventory.hosts['srx-test']['task_data']                                                     
Out[5]: {'ifname': 'fe-0/0/2', 'ipsuffix': 111}

In [6]: nr.inventory.hosts['srx-test'].platform                                                                                
Out[6]: 'junos'

ืื•ืŸ ืœืขืกืึธืฃ, ืœืึธื–ืŸ ืื•ื ื“ื– ื’ื™ื™ืŸ ืฆื• ื“ื™ ืฉืจื™ืคื˜ ื–ื™ืš. ืื™ืš ื”ืึธื‘ ื“ืึธ ื’ืึธืจื ื™ืฉื˜ ืฆื• ื–ื™ื™ืŸ ืกืคึผืขืฆื™ืขืœ ืฉื˜ืึธืœืฅ. ืื™ืš ื”ืึธื‘ ื ืึธืจ ื’ืขื ื•ืžืขืŸ ืึท ืคืึทืจื˜ื™ืง ื‘ื™ื™ึทืฉืคึผื™ืœ ืคื•ืŸ ื˜ื•ื˜ืึธืจื™ืึทืœ ืื•ืŸ ื’ืขื•ื•ื™ื™ื ื˜ ืขืก ื›ึผืžืขื˜ ืึทื ื˜ืฉื™ื™ื ื“ื–ืฉื“. ื“ืึธืก ืื™ื– ื•ื•ื™ ื“ื™ ืคืึทืจื˜ื™ืง ืึทืจื‘ืขื˜ ืฉืจื™ืคื˜ ืงื•ืงื˜ ื•ื•ื™:

from nornir import InitNornir
from nornir.plugins.tasks import networking, text
from nornir.plugins.functions.text import print_title, print_result

def config_and_deploy(task):
    # Transform inventory data to configuration via a template file
    r = task.run(task=text.template_file,
                 name="Base Configuration",
                 template="base.j2",
                 path=f"templates/{task.host.platform}")

    # Save the compiled configuration into a host variable
    task.host["config"] = r.result

    # Save the compiled configuration into a file
    with open(f"configs/{task.host.hostname}", "w") as f:
        f.write(r.result)

    # Deploy that configuration to the device using NAPALM
    task.run(task=networking.napalm_configure,
             name="Loading Configuration on the device",
             replace=False,
             configuration=task.host["config"])

nr = InitNornir(config_file="config.yaml", dry_run=True) # set dry_run=False, cross your fingers and run again

# run tasks
result = nr.run(task=config_and_deploy)
print_result(result)

ื‘ืึทืฆืึธืœืŸ ื•ืคืžืขืจืงื–ืึทืžืงื™ื™ึทื˜ ืฆื• ื“ื™ ืคึผืึทืจืึทืžืขื˜ืขืจ dry_run=ืืžืช ื™ื ื™ื˜ื™ืึทืœื™ื–ืึทื˜ื™ืึธืŸ ืื™ืŸ ืฉื•ืจื” ื›ื™ื™ืคืขืฅ nr.
ื“ืึธ ื“ื™ ื–ืขืœื‘ืข ื•ื•ื™ ืื™ืŸ ืึทื ืกืึทื‘ืœืข ืึท ืคึผืจืึธื‘ืข ืœื•ื™ืคืŸ ืื™ื– ื™ืžืคึผืœืึทืžืขื ืึทื“ ืื™ืŸ ื•ื•ืึธืก ืึท ืงืฉืจ ืฆื• ื“ื™ ืจืึทื•ื˜ืขืจ ืื™ื– ื’ืขืžืื›ื˜, ืึท ื ื™ื™ึทืข ืžืึทื“ืึทืคื™ื™ื“ ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทืŸ ืื™ื– ืฆื•ื’ืขื’ืจื™ื™ื˜, ื•ื•ืึธืก ืื™ื– ื“ืึทืŸ ื•ื•ืึทืœืึทื“ื™ื™ื˜ืึทื“ ื“ื•ืจืš ื“ื™ ืžื™ื˜ืœ (ืึธื‘ืขืจ ื“ืึธืก ืื™ื– ื ื™ืฉื˜ ื–ื™ื›ืขืจ; ืขืก ื“ืขืคึผืขื ื“ืก ืื•ื™ืฃ ื“ื™ ืฉื˜ื™ืฆืŸ ืคื•ืŸ ื“ื™ ืžื™ื˜ืœ ืื•ืŸ ื“ื™ ื™ืžืคึผืœืึทืžืขื ื˜ื™ื™ืฉืึทืŸ ืคื•ืŸ ื“ื™ ื“ืจื™ื™ื•ื•ืขืจ ืื™ืŸ NAPALM) , ืึธื‘ืขืจ ื“ื™ ื ื™ื™ึทืข ืงืึทื ืคื™ื’ื™ืขืจื™ื™ืฉืึทืŸ ืื™ื– ื ื™ืฉื˜ ื’ืœื™ื™ึทืš ื’ืขื•ื•ืขื ื“ื˜. ืคึฟืึทืจ ืงืึทืžื‘ืึทื˜ ื ื•ืฆืŸ, ืื™ืจ ืžื•ื–ืŸ ืึทืจืึธืคึผื ืขืžืขืŸ ื“ืขื ืคึผืึทืจืึทืžืขื˜ืขืจ dry_run ืึธื“ืขืจ ื˜ื•ื™ืฉืŸ ื–ื™ื™ึทืŸ ื•ื•ืขืจื˜ ืฆื• ืคืึทืœืฉ.

ื•ื•ืขืŸ ื“ืขืจ ืฉืจื™ืคื˜ ืื™ื– ืขืงืกืึทืงื™ื•ื˜ืึทื“, Nornir ืึทื•ื˜ืคึผื•ืฅ ื“ื™ื˜ื™ื™ืœื“ ืœืึธื’ืก ืฆื• ื“ื™ ืงืึทื ืกืึธื•ืœ.

ื•ื ื˜ืขืจ ื“ืขืจ ืกืคึผื•ื™ืœืขืจ ืื™ื– ื“ืขืจ ืจืขื–ื•ืœื˜ืึทื˜ ืคื•ืŸ ืึท ืงืึทืžื‘ืึทื˜ ืœื•ื™ืคืŸ ืื•ื™ืฃ ืฆื•ื•ื™ื™ ืคึผืจื•ื‘ื™ืจืŸ ืจืึธื•ื˜ืขืจืก:

config_and_deploy***************************************************************
* cisco-test ** changed : True *******************************************
vvvv config_and_deploy ** changed : True vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
---- Base Configuration ** changed : True ------------------------------------- INFO
class-map match-all VIDEO_SURV
 match access-group 111

policy-map VIDEO_SURV
 class VIDEO_SURV
    police 1500000 conform-action transmit  exceed-action drop

interface GigabitEthernet0/1/1
  description VIDEOSURV
  ip address 10.10.222.254 255.255.255.0
  service-policy input VIDEO_SURV

router bgp 65001
  network 10.10.222.0 mask 255.255.255.0

access-list 11 permit 10.10.222.0 0.0.0.255
access-list 111 permit ip 10.10.222.0 0.0.0.255 any
---- Loading Configuration on the device ** changed : True --------------------- INFO
+class-map match-all VIDEO_SURV
+ match access-group 111
+policy-map VIDEO_SURV
+ class VIDEO_SURV
+interface GigabitEthernet0/1/1
+  description VIDEOSURV
+  ip address 10.10.222.254 255.255.255.0
+  service-policy input VIDEO_SURV
+router bgp 65001
+  network 10.10.222.0 mask 255.255.255.0
+access-list 11 permit 10.10.222.0 0.0.0.255
+access-list 111 permit ip 10.10.222.0 0.0.0.255 any
^^^^ END config_and_deploy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* srx-test ** changed : True *******************************************
vvvv config_and_deploy ** changed : True vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
---- Base Configuration ** changed : True ------------------------------------- INFO
set interfaces fe-0/0/2 unit 0 description "Video surveillance"
set interfaces fe-0/0/2 unit 0 family inet filter input limit-in
set interfaces fe-0/0/2 unit 0 family inet address 10.10.111.254/24
set policy-options policy-statement export2bgp term 1 from route-filter 10.10.111.0/24 exact
set security zones security-zone WAN interfaces fe-0/0/2
set firewall policer policer-1m if-exceeding bandwidth-limit 1m
set firewall policer policer-1m if-exceeding burst-size-limit 187k
set firewall policer policer-1m then discard
set firewall policer policer-1.5m if-exceeding bandwidth-limit 1500000
set firewall policer policer-1.5m if-exceeding burst-size-limit 280k
set firewall policer policer-1.5m then discard
set firewall filter limit-in term 1 then policer policer-1.5m
set firewall filter limit-in term 1 then count limiter
---- Loading Configuration on the device ** changed : True --------------------- INFO
[edit interfaces]
+   fe-0/0/2 {
+       unit 0 {
+           description "Video surveillance";
+           family inet {
+               filter {
+                   input limit-in;
+               }
+               address 10.10.111.254/24;
+           }
+       }
+   }
[edit]
+  policy-options {
+      policy-statement export2bgp {
+          term 1 {
+              from {
+                  route-filter 10.10.111.0/24 exact;
+              }
+          }
+      }
+  }
[edit security zones]
     security-zone test-vpn { ... }
+    security-zone WAN {
+        interfaces {
+            fe-0/0/2.0;
+        }
+    }
[edit]
+  firewall {
+      policer policer-1m {
+          if-exceeding {
+              bandwidth-limit 1m;
+              burst-size-limit 187k;
+          }
+          then discard;
+      }
+      policer policer-1.5m {
+          if-exceeding {
+              bandwidth-limit 1500000;
+              burst-size-limit 280k;
+          }
+          then discard;
+      }
+      filter limit-in {
+          term 1 {
+              then {
+                  policer policer-1.5m;
+                  count limiter;
+              }
+          }
+      }
+  }
^^^^ END config_and_deploy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ื‘ืึทื”ืึทืœื˜ืŸ ืคึผืึทืกื•ื•ืขืจื“ื– ืื™ืŸ ansible_vault

ืื™ืŸ ื“ื™ ืึธื ื”ื™ื™ื‘ ืคื•ืŸ ื“ืขื ืึทืจื˜ื™ืงืœ ืื™ืš ื’ืขื’ืื ื’ืขืŸ ืึท ื‘ื™ืกืœ ืึธื•ื•ื•ืขืจื‘ืึธืจื“ ืึทื ืกืึทื‘ืœืข, ืึธื‘ืขืจ ืขืก ืื™ื– ื ื™ืฉื˜ ืึทืœืข ืึทื– ืฉืœืขื›ื˜. ืื™ืš ื˜ืึทืงืข ื•ื•ื™ ื–ื™ื™ ื•ื•ืึธืœื˜ ื•ื•ื™, ื•ื•ืึธืก ืื™ื– ื“ื™ื–ื™ื™ื ื“ ืฆื• ื‘ืึทื”ืึทืœื˜ืŸ ืฉืคึผื™ืจืขื•ื•ื“ื™ืง ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ืื•ื™ืก ืคื•ืŸ ื“ืขืจื–ืขืŸ. ืื•ืŸ ืžื™ืกื˜ืึธืžืข ืคื™ืœืข ื”ืึธื‘ืŸ ื‘ืืžืขืจืงื˜ ืึทื– ืžื™ืจ ื”ืึธื‘ืŸ ืึทืœืข ื“ื™ ืœืึธื’ื™ื ืก / ืคึผืึทืกื•ื•ืขืจื“ื– ืคึฟืึทืจ ืึทืœืข ืงืึทืžื‘ืึทื˜ ืจืึธื•ื˜ืขืจืก ืกืคึผืึทืจืงืœื™ื ื’ ืื™ืŸ ืึธืคึฟืŸ ืคืึธืจืขื ืื™ืŸ ืึท ื˜ืขืงืข gorups.yaml. ืขืก ืื™ื– ื ื™ืฉื˜ ืฉื™ื™ืŸ, ืคื•ืŸ ืงื•ืจืก. ื–ืืœ ืก ื‘ืึทืฉื™ืฆืŸ ื“ืขื ื“ืึทื˜ืŸ ืžื™ื˜ ื•ื•ืึธืœื˜.

ืœืึธืžื™ืจ ืึทืจื™ื‘ืขืจืคื™ืจืŸ ื“ื™ ืคึผืึทืจืึทืžืขื˜ืขืจืก ืคื•ืŸ groups.yaml ืฆื• creds.yaml ืื•ืŸ ื™ื ืงืจื™ืคึผื˜ ืขืก ืžื™ื˜ AES256 ืžื™ื˜ ืึท 20-ืฆื™ืคึฟืขืจ ืคึผืึทืจืึธืœ:

$ cd inventory
$ cat creds.yaml
---
cisco:
    username: admin1
    password: cisco1

juniper:
    username: admin2
    password: juniper2

$ pwgen 20 -N 1 > vault.passwd
ansible-vault encrypt creds.yaml --vault-password-file vault.passwd  
Encryption successful
$ cat creds.yaml 
$ANSIBLE_VAULT;1.1;AES256
39656463353437333337356361633737383464383231366233386636333965306662323534626131
3964396534396333363939373539393662623164373539620a346565373439646436356438653965
39643266333639356564663961303535353364383163633232366138643132313530346661316533
6236306435613132610a656163653065633866626639613537326233653765353661613337393839
62376662303061353963383330323164633162386336643832376263343634356230613562643533
30363436343465306638653932366166306562393061323636636163373164613630643965636361
34343936323066393763323633336366366566393236613737326530346234393735306261363239
35663430623934323632616161636330353134393435396632663530373932383532316161353963
31393434653165613432326636616636383665316465623036376631313162646435

ืขืก ืก ืึทื– ืคึผืฉื•ื˜. ืขืก ื‘ืœื™ื™ื‘ื˜ ืฆื• ืœืขืจื ืขืŸ ืื•ื ื“ื–ืขืจ ื ืึธืจื ื™ืจ-ืฉืจื™ืคื˜ ืฆื• ืฆื•ืจื™ืงืงืจื™ื’ืŸ ืื•ืŸ ืฆื•ืœื™ื™ื’ืŸ ื“ืขื ื“ืึทื˜ืŸ.
ืฆื• ื˜ืึธืŸ ื“ืึธืก, ืื™ืŸ ืื•ื ื“ื–ืขืจ ืฉืจื™ืคื˜ ื ืึธืš ื“ื™ ื™ื ื™ื˜ื™ืึทืœื™ื–ืึทื˜ื™ืึธืŸ ืฉื•ืจื” nr = InitNornir(config_file =... ืœื™ื™ื’ ื“ื™ ืคืืœื’ืขื ื“ืข ืงืึธื“:

...
nr = InitNornir(config_file="config.yaml", dry_run=True) # set dry_run=False, cross your fingers and run again

# enrich Inventory with the encrypted vault data
from ansible_vault import Vault
vault_password_file="inventory/vault.passwd"
vault_file="inventory/creds.yaml"
with open(vault_password_file, "r") as fp:
    password = fp.readline().strip()   
    vault = Vault(password)
    vaultdata = vault.load(open(vault_file).read())

for a in nr.inventory.hosts.keys():
    item = nr.inventory.hosts[a]
    item.username = vaultdata[item.groups[0]]['username']
    item.password = vaultdata[item.groups[0]]['password']
    #print("hostname={}, username={}, password={}n".format(item.hostname, item.username, item.password))

# run tasks
...

ืคื•ืŸ ืงื•ืจืก, vault.passwd ื–ืึธืœ ื ื™ื˜ ื–ื™ื™ืŸ ืœื™ื’ืŸ ื•ื•ื™ื™ึทื˜ืขืจ ืฆื• creds.yaml ื•ื•ื™ ืื™ืŸ ืžื™ื™ืŸ ื‘ื™ื™ึทืฉืคึผื™ืœ. ืื‘ืขืจ ืขืก ืื™ื– ื’ื•ื˜ ืคึฟืึทืจ ืคึผืœื™ื™ื™ื ื’.

ืึทื– ืก ืึทืœืข ืคึฟืึทืจ ืื™ืฆื˜. ืขืก ื–ืขื ืขืŸ ืึท ืคึผืึธืจ ืžืขืจ ืึทืจื˜ื™ืงืœืขืŸ ื•ื•ืขื’ืŸ Cisco + Zabbix ืงื•ืžืขืŸ, ืึธื‘ืขืจ ื“ืึธืก ืื™ื– ื ื™ืฉื˜ ืึท ื‘ื™ืกืœ ื•ื•ืขื’ืŸ ืึธื˜ืึทืžื™ื™ืฉืึทืŸ. ืื•ืŸ ืื™ืŸ ื“ืขื ืœืขื‘ืŸ ืฆื•ืงื•ื ืคึฟื˜ ืื™ืš ืคึผืœืึทืŸ ืฆื• ืฉืจื™ื™ึทื‘ืŸ ื•ื•ืขื’ืŸ RESTCONF ืื™ืŸ ืกื™ืกืงืึธ.

ืžืงื•ืจ: www.habr.com

ืœื™ื™ื’ืŸ ืึท ื‘ืึทืžืขืจืงื•ื ื’