Iran laifọwọyi ati kikun awọn eroja iṣeto ẹrọ nẹtiwọọki nipa lilo Nornir

Iran laifọwọyi ati kikun awọn eroja iṣeto ẹrọ nẹtiwọọki nipa lilo Nornir

Hey Habr!

Laipe ohun article popped soke nibi Mikrotik ati Lainos. Baraku ati adaṣiṣẹ nibiti a ti yanju iṣoro ti o jọra nipa lilo awọn ọna fosaili. Ati pe botilẹjẹpe iṣẹ naa jẹ aṣoju patapata, ko si nkankan iru nipa rẹ lori Habré. Mo gboya lati fi keke mi fun agbegbe IT ti o bọwọ fun.

Eyi kii ṣe keke akọkọ fun iru iṣẹ bẹẹ. Aṣayan akọkọ ti ni imuse ni ọpọlọpọ ọdun sẹyin pada sinu dahun version 1.x.x. Kẹkẹ naa ko ṣọwọn lo ati nitori naa ipata nigbagbogbo. Ni ori pe iṣẹ-ṣiṣe funrararẹ ko dide ni igbagbogbo bi awọn ẹya ṣe imudojuiwọn dahun. Ati ni gbogbo igba ti o nilo lati wakọ, pq naa ṣubu tabi kẹkẹ naa ṣubu. Sibẹsibẹ, apakan akọkọ, ti o npese awọn atunto, nigbagbogbo ṣiṣẹ ni kedere, da jinja2 Awọn engine ti wa ni gun mulẹ. Ṣugbọn apakan keji - yiyi awọn atunto - nigbagbogbo mu awọn iyalẹnu wá. Ati pe niwọn igba ti Mo ni lati yi atunto latọna jijin si idaji ọgọrun awọn ẹrọ, diẹ ninu eyiti o wa ni ẹgbẹẹgbẹrun awọn ibuso kilomita, lilo ọpa yii jẹ alaidun diẹ.

Nibi ti mo gbọdọ gba pe mi aidaniloju julọ seese da ni mi aini ti faramọ pẹlu mi dahunju ninu awọn oniwe- shortcomings. Ati eyi, nipasẹ ọna, jẹ aaye pataki kan. dahun jẹ iyatọ patapata, agbegbe ti imọ ti ara rẹ pẹlu DSL tirẹ (Ede Specific Domain), eyiti o gbọdọ ṣetọju ni ipele igboya. O dara, akoko yẹn dahun O n dagbasoke ni iyara pupọ, ati laisi iyi pataki fun ibamu sẹhin, ko ṣafikun igbẹkẹle.

Nitorinaa, ko pẹ diẹ sẹyin ẹya keji ti kẹkẹ naa ti ṣe imuse. Akoko yi lori Python, tabi dipo lori ilana ti a kọ sinu Python ati fun Python ẹtọ ni Nornir

Nitorina - Nornir jẹ microframework ti a kọ sinu Python ati fun Python ati apẹrẹ fun adaṣiṣẹ. Kanna bi ninu ọran pẹlu dahun, lati yanju awọn iṣoro nibi, a nilo igbaradi data ti o peye, i.e. akojo oja ti ogun ati awọn won sile, ṣugbọn awọn iwe afọwọkọ ti wa ni kọ ko ni lọtọ DSL, sugbon ni kanna ko gan atijọ, sugbon gidigidi dara p[i|i] toonu.

Jẹ ká wo ni ohun ti o ti wa ni lilo awọn wọnyi ifiwe apẹẹrẹ.

Mo ní ẹ̀ka ọ́fíìsì kan tó ní ọ́fíìsì méjìlá jákèjádò orílẹ̀-èdè náà. Ọfiisi kọọkan ni olulana WAN ti o fopin si ọpọlọpọ awọn ikanni ibaraẹnisọrọ lati awọn oniṣẹ oriṣiriṣi. Ilana afisona jẹ BGP. WAN onimọ wá ni meji orisi: Cisco ISG tabi Juniper SRX.

Bayi iṣẹ-ṣiṣe naa: o nilo lati tunto subnet igbẹhin fun Kakiri Fidio lori ibudo lọtọ lori gbogbo awọn onimọ-ọna WAN ti nẹtiwọọki ẹka - polowo subnet yii ni BGP - tunto opin iyara ti ibudo igbẹhin.

Ni akọkọ, a nilo lati mura awọn awoṣe meji, lori ipilẹ eyiti awọn atunto yoo ṣe ipilẹṣẹ lọtọ fun Sisiko ati Juniper. O tun jẹ dandan lati ṣeto data fun aaye kọọkan ati awọn paramita asopọ, ie. gba kanna oja

Awoṣe ti o ṣetan fun Sisiko:

$ 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

Àdàkọ fún Juniper:

$ 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

Awọn awoṣe, dajudaju, ko jade kuro ninu afẹfẹ tinrin. Iwọnyi jẹ iyatọ pataki laarin awọn atunto iṣẹ ti o wa ati lẹhin ipinnu iṣẹ-ṣiṣe lori awọn onimọ-ọna meji kan pato ti awọn awoṣe oriṣiriṣi.

Lati awọn awoṣe wa a rii pe lati yanju iṣoro naa, a nilo awọn aye meji nikan fun Juniper ati awọn aye 3 fun Sisiko. nibi ti won wa:

  • iforukọ
  • ipsuffix
  • asn

Bayi a nilo lati ṣeto awọn paramita wọnyi fun ẹrọ kọọkan, i.e. ṣe ohun kanna oja.

fun oja A yoo muna tẹle awọn iwe aṣẹ Bibẹrẹ Nornir

iyẹn ni, jẹ ki a ṣẹda egungun faili kanna:

.
├── config.yaml
├── inventory
│   ├── defaults.yaml
│   ├── groups.yaml
│   └── hosts.yaml

Faili config.yaml jẹ faili iṣeto nornir boṣewa

$ 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"

A yoo tọkasi awọn paramita akọkọ ninu faili naa ogun.yaml, ẹgbẹ (ninu ọran mi awọn wọnyi ni awọn iwọle/awọn ọrọ igbaniwọle) ni awọn ẹgbẹ.yamlati ninu aseku.yaml A kii yoo tọka ohunkohun, ṣugbọn o nilo lati tẹ awọn iyokuro mẹta sibẹ - nfihan pe o jẹ iṣu awọn faili ti ṣofo tilẹ.

Eyi ni ohun ti hosts.yaml dabi:

---
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

Ati eyi ni awọn ẹgbẹ.yaml:

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

juniper:
    platform: junos
    username: admin2
    password: juniper2

Ohun tó ṣẹlẹ̀ nìyí oja fun ise wa. Lakoko ipilẹṣẹ, awọn aye lati awọn faili akojo oja ti wa ni ya aworan si awoṣe ohun OjaElement.

Ni isalẹ apanirun jẹ aworan atọka ti awoṣe 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"
                }
            }
        }
    }
}

Awoṣe yi le wo kekere kan airoju, paapa ni akọkọ. Ni ibere lati ro ero rẹ, awọn ohun ibanisọrọ mode ni Python.

 $ 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'

Ati nikẹhin, jẹ ki a lọ si iwe afọwọkọ funrararẹ. Mo ni nkankan lati wa ni paapa lọpọlọpọ ti nibi. Mo ti o kan mu a setan-ṣe apẹẹrẹ lati ikẹkọ o si lo fere ko yipada. Eyi ni ohun ti iwe afọwọkọ iṣẹ ti pari dabi:

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)

San ifojusi si paramita dry_run=Ododo ni ibẹrẹ nkan nkan nr.
Nibi kanna bi ninu dahun A ti ṣe imuse idanwo kan ninu eyiti o ti ṣe asopọ si olulana, a ti pese atunto tuntun kan, eyiti o jẹ ifọwọsi nipasẹ ẹrọ (ṣugbọn eyi ko daju; o da lori atilẹyin ẹrọ ati imuse awakọ ni NAPALM) , ṣugbọn awọn titun iṣeto ni ko taara loo. Fun lilo ija, o gbọdọ yọ paramita kuro gbẹ_run tabi yi iye rẹ pada si eke.

Nigba ti iwe afọwọkọ ti wa ni executed, Nornir jade alaye àkọọlẹ si awọn console.

Ni isalẹ apanirun ni abajade ti ija ija kan lori awọn olulana idanwo meji:

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 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Tọju awọn ọrọ igbaniwọle ni ansible_vault

Ni ibere ti awọn article Mo ti lọ kekere kan sínú òkun dahun, ṣugbọn kii ṣe gbogbo rẹ buru. Mo feran wọn gaan Ile ifinkan pamo bi, eyi ti o ti ṣe lati tọju kókó alaye jade ti oju. Ati boya ọpọlọpọ ti ṣe akiyesi pe a ni gbogbo awọn iwọle / awọn ọrọ igbaniwọle fun gbogbo awọn olulana ija ti n dan ni fọọmu ṣiṣi ni faili kan gorup.yaml. Ko lẹwa, dajudaju. Jẹ ki a daabobo data yii pẹlu Ile ifinkan pamo.

Jẹ ki a gbe awọn paramita lati groups.yaml lọ si creds.yaml, ki o si parọ rẹ pẹlu AES256 pẹlu ọrọ igbaniwọle oni-nọmba 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

O rọrun yẹn. O wa lati kọ ẹkọ wa Nornir-akosile lati gba ati ki o waye yi data.
Lati ṣe eyi, ninu iwe afọwọkọ wa lẹhin laini ibẹrẹ nr = InitNornir(config_file=… fi koodu wọnyi kun:

...
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
...

Nitoribẹẹ, vault.passwd ko yẹ ki o wa lẹgbẹẹ creds.yaml bi ninu apẹẹrẹ mi. Ṣugbọn o dara fun ṣiṣere.

Iyẹn ni gbogbo fun bayi. Nibẹ ni o wa kan tọkọtaya siwaju sii ìwé nipa Sisiko + Zabbix bọ, ṣugbọn yi ni ko kan bit nipa adaṣiṣẹ. Ati ni ọjọ iwaju nitosi Mo gbero lati kọ nipa RESTCONF ni Sisiko.

orisun: www.habr.com

Fi ọrọìwòye kun