ื™ืฆื™ืจื” ื•ืžื™ืœื•ื™ ืื•ื˜ื•ืžื˜ื™ ืฉืœ ืจื›ื™ื‘ื™ ืชืฆื•ืจืช ืžื›ืฉื™ืจื™ ืจืฉืช ื‘ืืžืฆืขื•ืช Nornir

ื™ืฆื™ืจื” ื•ืžื™ืœื•ื™ ืื•ื˜ื•ืžื˜ื™ ืฉืœ ืจื›ื™ื‘ื™ ืชืฆื•ืจืช ืžื›ืฉื™ืจื™ ืจืฉืช ื‘ืืžืฆืขื•ืช Nornir

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

ืœืื—ืจื•ื ื” ืฆืฆื” ื›ืืŸ ืžืืžืจ ืžื™ืงืจื•ื˜ื™ืง ื•ืœื™ื ื•ืงืก. ืฉื’ืจื” ื•ืื•ื˜ื•ืžืฆื™ื” ืฉื‘ื• ื‘ืขื™ื” ื“ื•ืžื” ื ืคืชืจื” ื‘ืืžืฆืขื•ืช ืืžืฆืขื™ ืžืื•ื‘ื ื™ื. ื•ืœืžืจื•ืช ืฉื”ืžืฉื™ืžื” ืื•ืคื™ื™ื ื™ืช ืœื—ืœื•ื˜ื™ืŸ, ืื™ืŸ ื‘ื” ืฉื•ื ื“ื‘ืจ ื“ื•ืžื” ื‘ื”ืื‘ืจื”. ืื ื™ ืžืขื– ืœื”ืฆื™ืข ืืช ื”ืื•ืคื ื™ื™ื ืฉืœื™ ืœืงื”ื™ืœืช ื”-IT ื”ืžื›ื•ื‘ื“ืช.

ื–ื” ืœื ื”ืื•ืคื ื™ื™ื ื”ืจืืฉื•ื ื™ื ืœืžืฉื™ืžื” ื›ื–ื•. ื”ืืคืฉืจื•ืช ื”ืจืืฉื•ื ื” ื™ื•ืฉืžื” ืœืคื ื™ ืžืกืคืจ ืฉื ื™ื ื‘ื—ื–ืจื” ansible ื’ืจืกื” 1.x.x. ื”ืื•ืคื ื™ื™ื ื”ื™ื• ื‘ืฉื™ืžื•ืฉ ื ื“ื™ืจ ื•ืœื›ืŸ ื”ื—ืœื™ื“ื• ื›ืœ ื”ื–ืžืŸ. ื‘ืžื•ื‘ืŸ ื–ื” ืฉื”ืžืฉื™ืžื” ืขืฆืžื” ืื™ื ื” ืžืชืขื•ืจืจืช ื‘ืื•ืชื” ืชื“ื™ืจื•ืช ื›ืืฉืจ ื’ืจืกืื•ืช ืžืชืขื“ื›ื ื•ืช ansible. ื•ื‘ื›ืœ ืคืขื ืฉืืชื” ืฆืจื™ืš ืœื ืกื•ืข, ื”ืฉืจืฉืจืช ื ื•ืคืœืช ืื• ื”ื’ืœื’ืœ ื ื•ืคืœ. ืขื ื–ืืช, ื”ื—ืœืง ื”ืจืืฉื•ืŸ, ื™ืฆื™ืจืช ื”ื’ื“ืจื•ืช, ืชืžื™ื“ ืขื•ื‘ื“ ื‘ืฆื•ืจื” ื‘ืจื•ืจื” ืžืื•ื“, ืœืžืจื‘ื” ื”ืžื–ืœ jinja2 ื”ืžื ื•ืข ืžื‘ื•ืกืก ืžื–ืžืŸ. ืื‘ืœ ื”ื—ืœืง ื”ืฉื ื™, ืคืชื™ื—ืช ื”ื”ื’ื“ืจื•ืช, ื”ื‘ื™ื ื‘ื“ืจืš ื›ืœืœ ื”ืคืชืขื•ืช. ื•ืžื›ื™ื•ื•ืŸ ืฉืื ื™ ืฆืจื™ืš ืœื’ืœื’ืœ ืืช ื”ืชืฆื•ืจื” ืžืจื—ื•ืง ืœื—ืฆื™ ืžืื” ืžื›ืฉื™ืจื™ื, ืฉื—ืœืงื ืžืžื•ืงืžื™ื ื‘ืžืจื—ืง ืฉืœ ืืœืคื™ ืงื™ืœื•ืžื˜ืจื™ื, ื”ืฉื™ืžื•ืฉ ื‘ื›ืœื™ ื”ื–ื” ื”ื™ื” ืงืฆืช ืžืฉืขืžื.

ื›ืืŸ ืื ื™ ื—ื™ื™ื‘ ืœื”ื•ื“ื•ืช ืฉืกื‘ื™ืจ ืœื”ื ื™ื— ืฉืื™ ื”ื•ื•ื“ืื•ืช ืฉืœื™ ื ืขื•ืฆื” ื‘ื—ื•ืกืจ ื”ื”ื™ื›ืจื•ืช ืฉืœื™ ืขื ansibleืžืืฉืจ ื‘ื—ืกืจื•ื ื•ืชื™ื•. ื•ื–ื•, ืื’ื‘, ื ืงื•ื“ื” ื—ืฉื•ื‘ื”. ansible ื”ื•ื ืชื—ื•ื ื™ื“ืข ื ืคืจื“ ืœื—ืœื•ื˜ื™ืŸ ืขื DSL ืžืฉืœื• (ืฉืคืช ื“ื•ืžื™ื™ืŸ ืกืคืฆื™ืคื™ืช), ืฉื—ื™ื™ื‘ ืœื”ื™ืฉืžืจ ื‘ืจืžื” ื‘ื˜ื•ื—ื”. ื•ื‘ื›ืŸ, ื”ืจื’ืข ื”ื–ื” ansible ื–ื” ืžืชืคืชื— ื“ื™ ืžื”ืจ, ื•ืœืœื ื”ืชื™ื™ื—ืกื•ืช ืžื™ื•ื—ื“ืช ืœืชืื™ืžื•ืช ืœืื—ื•ืจ, ื–ื” ืœื ืžื•ืกื™ืฃ ื‘ื™ื˜ื—ื•ืŸ.

ืœื›ืŸ, ืœื ื›ืœ ื›ืš ืžื–ืžืŸ ื™ื•ืฉืžื” ื’ืจืกื” ืฉื ื™ื™ื” ืฉืœ ื”ืื•ืคื ื™ื™ื. ื”ืคืขื ืขืœ ืคึผึดื™ืชื•ึนืŸ, ืื• ื™ื•ืชืจ ื ื›ื•ืŸ ืขืœ ืžืกื’ืจืช ืฉื ื›ืชื‘ื” ื‘ ืคึผึดื™ืชื•ึนืŸ ืขื‘ื•ืจ ืคึผึดื™ืชื•ึนืŸ ื ืงืจื ื ื•ืจื ื™ืจ

ื›ืš - ื ื•ืจื ื™ืจ ื”ื•ื ืžื™ืงืจื•-ืžืกื’ืจืช ืฉื ื›ืชื‘ ื‘ ืคึผึดื™ืชื•ึนืŸ ืขื‘ื•ืจ ืคึผึดื™ืชื•ึนืŸ ื•ืžื™ื•ืขื“ ืœืื•ื˜ื•ืžืฆื™ื”. ืื•ืชื• ื“ื‘ืจ ื›ืžื• ื‘ืžืงืจื” ืขื ansible, ื›ื“ื™ ืœืคืชื•ืจ ื‘ืขื™ื•ืช ื›ืืŸ, ื ื“ืจืฉืช ื”ื›ื ืช ื ืชื•ื ื™ื ืžื•ื›ืฉืจื™ื, ื›ืœื•ืžืจ. ืžืœืื™ ืฉืœ ืžืืจื—ื™ื ื•ื”ืคืจืžื˜ืจื™ื ืฉืœื”ื, ืื‘ืœ ืกืงืจื™ืคื˜ื™ื ื ื›ืชื‘ื™ื ืœื ื‘-DSL ื ืคืจื“, ืืœื ื‘ืื•ืชื• p[i|i]ton ืœื ืžืื•ื“ ื™ืฉืŸ, ืื‘ืœ ื˜ื•ื‘ ืžืื•ื“.

ื‘ื•ืื• ื ืกืชื›ืœ ืขืœ ืžื” ื–ื” ื‘ืืžืฆืขื•ืช ื”ื“ื•ื’ืžื” ื”ื—ื™ื” ื”ื‘ืื”.

ื™ืฉ ืœื™ ืจืฉืช ืกื ื™ืคื™ื ืขื ื›ืžื” ืขืฉืจื•ืช ืžืฉืจื“ื™ื ื‘ืจื—ื‘ื™ ื”ืืจืฅ. ืœื›ืœ ืžืฉืจื“ ื™ืฉ ื ืชื‘ WAN ืฉืžืกื™ื™ื ืžืกืคืจ ืขืจื•ืฆื™ ืชืงืฉื•ืจืช ืžืžืคืขื™ืœื™ื ืฉื•ื ื™ื. ืคืจื•ื˜ื•ืงื•ืœ ื”ื ื™ืชื•ื‘ ื”ื•ื BGP. ื ืชื‘ื™ WAN ืžื’ื™ืขื™ื ื‘ืฉื ื™ ืกื•ื’ื™ื: Cisco ISG ืื• Juniper SRX.

ื›ืขืช ื”ืžืฉื™ืžื”: ืขืœื™ืš ืœื”ื’ื“ื™ืจ ืชืช-ืจืฉืช ื™ื™ืขื•ื“ื™ืช ืœืžืขืงื‘ ื•ื™ื“ืื• ื‘ื™ืฆื™ืื” ื ืคืจื“ืช ื‘ื›ืœ ื ืชื‘ื™ ื”-WAN ืฉืœ ืจืฉืช ื”ืกื ื™ืคื™ื - ืคืจืกื ืืช ื”ืจืฉืช ื”ืžืฉื ื” ื”ื–ื• ื‘-BGP - ื”ื’ื“ืจ ืืช ืžื’ื‘ืœืช ื”ืžื”ื™ืจื•ืช ืฉืœ ื”ื™ืฆื™ืื” ื”ื™ื™ืขื•ื“ื™ืช.

ืจืืฉื™ืช, ืขืœื™ื ื• ืœื”ื›ื™ืŸ ื›ืžื” ืชื‘ื ื™ื•ืช, ืฉืขืœ ื‘ืกื™ืกืŸ ื™ื•ืคืงื• ืชืฆื•ืจื•ืช ื‘ื ืคืจื“ ืขื‘ื•ืจ ืกื™ืกืงื• ื•ื’'ื•ื ื™ืคืจ. ื›ืžื• ื›ืŸ, ื™ืฉ ืฆื•ืจืš ืœื”ื›ื™ืŸ ื ืชื•ื ื™ื ืขื‘ื•ืจ ื›ืœ ื ืงื•ื“ื” ื•ืคืจืžื˜ืจื™ื ืฉืœ ื—ื™ื‘ื•ืจ, ื›ืœื•ืžืจ. ืœืืกื•ืฃ ืืช ืื•ืชื• ืžืœืื™

ืชื‘ื ื™ืช ืžื•ื›ื ื” ืขื‘ื•ืจ ืกื™ืกืงื•:

$ 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

ืชื‘ื ื™ื•ืช, ื›ืžื•ื‘ืŸ, ืœื ื™ื•ืฆืื•ืช ื™ืฉ ืžืื™ืŸ. ืืœื• ื”ื ื‘ืขืฆื ื”ื‘ื“ืœื™ื ื‘ื™ืŸ ืชืฆื•ืจื•ืช ื”ืขื‘ื•ื“ื” ืฉื”ื™ื• ื•ื”ื™ื• ืœืื—ืจ ืคืชืจื•ืŸ ื”ืžืฉื™ืžื” ื‘ืฉื ื™ ื ืชื‘ื™ื ืกืคืฆื™ืคื™ื™ื ืžื“ื’ืžื™ื ืฉื•ื ื™ื.

ืžื”ืชื‘ื ื™ื•ืช ืฉืœื ื• ืื ื—ื ื• ืจื•ืื™ื ืฉื›ื“ื™ ืœืคืชื•ืจ ืืช ื”ื‘ืขื™ื”, ืื ื—ื ื• ืฆืจื™ื›ื™ื ืจืง ืฉื ื™ ืคืจืžื˜ืจื™ื ืขื‘ื•ืจ Juniper ื•-3 ืคืจืžื˜ืจื™ื ืขื‘ื•ืจ Cisco. ื”ื ื” ื”ื:

  • ifname
  • ืกื™ื•ืžืช ips
  • 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, ืงื‘ื•ืฆื” (ื‘ืžืงืจื” ืฉืœื™ ืืœื• ื›ื ื™ืกื•ืช/ืกื™ืกืžืื•ืช) ื‘ groups.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

ื•ื”ื ื” groups.yaml:

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

juniper:
    platform: junos
    username: admin2
    password: juniper2

ื–ื” ืžื” ืฉืงืจื” ืžืœืื™ ืœืžืฉื™ืžื” ืฉืœื ื•. ื‘ืžื”ืœืš ื”ืืชื—ื•ืœ, ืคืจืžื˜ืจื™ื ืžืงื•ื‘ืฆื™ ื”ืžืœืื™ ืžืžื•ืคื™ื ืœืžื•ื“ืœ ื”ืื•ื‘ื™ื™ืงื˜ InventoryElement.

ืžืชื—ืช ืœืกืคื•ื™ืœืจ ื™ืฉ ื“ื™ืื’ืจืžื” ืฉืœ ืžื•ื“ืœ 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.
ื›ืืŸ ืื•ืชื• ื“ื‘ืจ ื›ืžื• ื‘ ansible ื”ื•ื˜ืžืขื” ืจื™ืฆืช ื‘ื“ื™ืงื” ืฉื‘ื” ื ื•ืฆืจ ื—ื™ื‘ื•ืจ ืœื ืชื‘, ืžื›ื™ื ื™ื ืชืฆื•ืจื” ืฉื•ื ื”, ืืฉืจ ืœืื—ืจ ืžื›ืŸ ืžืื•ืžืชืช ืขืœ ื™ื“ื™ ื”ืžื›ืฉื™ืจ (ืื‘ืœ ื–ื” ืœื ื‘ื˜ื•ื—; ื–ื” ืชืœื•ื™ ื‘ืชืžื™ื›ืช ื”ืžื›ืฉื™ืจ ื•ื‘ื™ื™ืฉื•ื ื”ื“ืจื™ื™ื‘ืจ ื‘-NAPALM) , ืืš ื”ืชืฆื•ืจื” ื”ื—ื“ืฉื” ืื™ื ื” ืžื™ื•ืฉืžืช ื™ืฉื™ืจื•ืช. ืœืฉื™ืžื•ืฉ ืงืจื‘ื™, ืขืœื™ืš ืœื”ืกื™ืจ ืืช ื”ืคืจืžื˜ืจ ืจื™ืฆื” ื™ื‘ืฉื” ืื• ืœืฉื ื•ืช ืืช ื”ืขืจืš ืฉืœื• ืœ ืœื ื ื›ื•ืŸ.

ื›ืืฉืจ ื”ืกืงืจื™ืคื˜ ืžื‘ื•ืฆืข, 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

ื‘ืชื—ื™ืœืช ื”ื›ืชื‘ื” ืงืฆืช ื”ื’ื–ืžืชื™ ansible, ืื‘ืœ ื–ื” ืœื ื›ืœ ื›ืš ื ื•ืจื. ืื ื™ ืžืื•ื“ ืื•ื”ื‘ ืื•ืชื ืงืžืจื•ืŸ ื›ืžื•, ืฉื ื•ืขื“ ืœื”ืกืชื™ืจ ืžื™ื“ืข ืจื’ื™ืฉ ืžื—ื•ืฅ ืœื˜ื•ื•ื— ื”ืจืื™ื™ื”. ื•ื›ื ืจืื” ืฉืจื‘ื™ื ืฉืžื• ืœื‘ ืฉื™ืฉ ืœื ื• ืืช ื›ืœ ื”ื”ืชื—ื‘ืจื•ืช/ืกื™ืกืžืื•ืช ืœื›ืœ ื ืชื‘ื™ ื”ืงืจื‘ ื ื•ืฆืฆื™ื ื‘ืฆื•ืจื” ืคืชื•ื—ื” ื‘ืงื•ื‘ืฅ gorups.yaml. ื–ื” ืœื ื™ืคื”, ื›ืžื•ื‘ืŸ. ื‘ื•ืื• ื ื’ืŸ ืขืœ ื”ื ืชื•ื ื™ื ื”ืืœื” ืขื ืงืžืจื•ืŸ.

ื‘ื•ืื• ื ืขื‘ื™ืจ ืืช ื”ืคืจืžื˜ืจื™ื ืž-grupper.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

ื–ื” ื›ื–ื” ืคืฉื•ื˜. ื ื•ืชืจ ืœืœืžื“ ืืช ืฉืœื ื• ื ื•ืจื ื™ืจ-script ื›ื“ื™ ืœืื—ื–ืจ ื•ืœื”ื—ื™ืœ ื ืชื•ื ื™ื ืืœื”.
ืœืฉื ื›ืš, ื‘ืกืงืจื™ืคื˜ ืฉืœื ื• ืœืื—ืจ ืฉื•ืจืช ื”ืืชื—ื•ืœ 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

ื”ื•ืกืคืช ืชื’ื•ื‘ื”