Famoronana mandeha ho azy sy famenoana singa fanamafisana ny fitaovana amin'ny tambajotra mampiasa Nornir

Famoronana mandeha ho azy sy famenoana singa fanamafisana ny fitaovana amin'ny tambajotra mampiasa Nornir

Hey Habr!

Nisy lahatsoratra nipoitra tato ho ato Mikrotik sy Linux. Routine sy automation izay nisy olana mitovy amin'izany voavaha tamin'ny fampiasana fitaovana fôsily. Ary na dia mahazatra tanteraka aza ny asa dia tsy misy mitovy aminy amin'ny Habré. Sahy manolotra ny bisikiletako ho an'ny vondrom-piarahamonina IT hajaina aho.

Tsy ity no bisikileta voalohany amin'ny asa toy izany. Ny safidy voalohany dia nampiharina taona maromaro lasa izay azo atao dika 1.x.x. Mahalana no nampiasaina ilay bisikileta ka noho izany dia harafesina foana. Amin'ny heviny hoe ny asa mihitsy dia tsy mipoitra matetika araka ny fanavaozana ny dikan-teny azo atao. Ary isaky ny mila mitondra fiara ianao, dia mianjera ny rojo na ny kodiarana. Na izany aza, ny ampahany voalohany, mamorona configs, dia miasa tsara foana, soa ihany jinja2 Efa ela ny maotera. Saingy ny ampahany faharoa - ny famoahana configs - matetika dia nitondra tsy ampoizina. Ary satria tsy maintsy mandroaka ny config lavitra mankany amin'ny fitaovana an-jatony aho, ny sasany amin'izy ireo dia an'arivony kilometatra miala, ny fampiasana an'io fitaovana io dia mankaleo kely.

Eto aho dia tsy maintsy miaiky fa ny tsy fahatokisana ahy dia ny tsy fahampian'ny fahafantarako azy azo ataonoho ny lesoka ao aminy. Ary ity, raha ny marina, dia teboka manan-danja. azo atao dia misaraka tanteraka, faritra misy ny fahalalana miaraka amin'ny DSL (Domain Specific Language), izay tsy maintsy tazonina amin'ny ambaratonga matoky tena. Eny, tamin'io fotoana io azo atao Mivoatra haingana izy io, ary tsy misy fiheverana manokana ny fifanarahana mihemotra, tsy manampy fahatokisana izany.

Noho izany, tsy ela akory izay dia nisy ny dikan-teny faharoa amin'ny bisikileta. Amin'ity indray mitoraka ity Python, na ny marimarina kokoa amin'ny rafitra voasoratra ao Python ary ho Python eo ambanin'ny anarana Nornir

Noho izany- Nornir dia microframework voasoratra ao Python ary ho Python ary natao ho an'ny automation. Mitovy amin'ny tranga misy azo atao, mba hamahana olana eto dia ilaina ny fanomanana angon-drakitra mahay, i.e. fanisana ny mpampiantrano sy ny mason'izy ireo, fa ny script dia tsy voasoratra amin'ny DSL misaraka, fa amin'ny p[i|i]ton tsy dia antitra loatra, fa tena tsara.

Andeha hojerentsika hoe inona no fampiasana ity ohatra mivantana manaraka ity.

Manana tambajotran-tsampana misy birao am-polony maro manerana ny firenena aho. Ny birao tsirairay dia manana router WAN izay mamarana fantsona fifandraisana maromaro amin'ny mpandraharaha samihafa. Ny protocol routing dia BGP. Misy karazany roa ny router WAN: Cisco ISG na Juniper SRX.

Ny asa izao: mila manamboatra subnet natokana ho an'ny Video Surveillance ianao amin'ny seranana misaraka amin'ny router WAN rehetra ao amin'ny tambajotran'ny sampana - ambarao amin'ny BGP ity subnet ity - amboary ny fetran'ny hafainganam-pandehan'ny seranana voatokana.

Voalohany, mila manomana môdely roa isika, izay mifototra amin'ny fananganana manokana ho an'ny Cisco sy Juniper. Ilaina ihany koa ny manomana data ho an'ny teboka tsirairay sy ny mari-pamantarana fifandraisana, i.e. manangona tahiry mitovy

Modely vonona ho an'ny 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

Modely ho an'ny 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

Ny templates, mazava ho azy, dia tsy mivoaka avy amin'ny rivotra manify. Ireo dia tena tsy mitovy amin'ny fikajiana miasa izay nisy sy taorian'ny famahana ny asa amin'ny router roa manokana amin'ny modely samihafa.

Avy amin'ny maodely dia hitantsika fa hamahana ny olana dia mila paramètre roa ho an'ny Juniper sy paramètres 3 ho an'ny Cisco isika. ireto izy ireo:

  • ifname
  • ipssuffix
  • asn

Ankehitriny dia mila mametraka ireo mari-pamantarana ireo ho an'ny fitaovana tsirairay isika, i.e. manao toy izany koa lisitra.

ho an'ny lisitra Hanaraka tanteraka ny antontan-taratasy izahay Manomboka ny Nornir

izany hoe, andao hamorona skeleton rakitra mitovy:

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

Ny rakitra config.yaml dia ny rakitra fichier nornir mahazatra

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

Hasehontsika ny masontsivana lehibe ao amin'ny rakitra hosts.yaml, vondrona (raha ny ahy dia logins/passwords) in groups.yaml, ary ao defaults.yaml Tsy hanondro na inona na inona izahay, fa mila mampiditra minus telo ianao - manondro fa misy izany yaml foana anefa ny rakitra.

Toy izao ny endriky ny 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

Ary eto ny groupe.yaml:

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

juniper:
    platform: junos
    username: admin2
    password: juniper2

Izany no nitranga lisitra ho an’ny asantsika. Mandritra ny fanombohana, ny mari-pamantarana avy amin'ny rakitra fitahirizam-bokatra dia atao sari-tany amin'ny modely zavatra InventoryElement.

Eo ambanin'ny mpandroba dia misy sarin'ny modely 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"
                }
            }
        }
    }
}

Ity modely ity dia mety hikorontana kely, indrindra amin'ny voalohany. Mba hamantarana izany, ny fomba interactive in 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'

Ary farany, andao hiroso amin'ny script mihitsy. Tsy misy tokony hireharehako manokana eto. Vao avy naka ohatra efa vonona aho fampianarana ary saika tsy niova izy io. Toy izao ny endriky ny script miasa vita:

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)

Tandremo ny parameter dry_run=Marina amin'ny fanombohana zavatra andalana nr.
Eto dia mitovy amin'ny in azo atao Nisy fitsapana natao izay nanaovana ny fifandraisana amin'ny router, namboarina ny fanovana vaovao, izay nohamarinin'ny fitaovana avy eo (saingy tsy azo antoka izany; miankina amin'ny fanohanan'ny fitaovana sy ny fampiharana ny mpamily ao amin'ny NAPALM) , fa tsy mihatra mivantana ny config vaovao. Ho an'ny fampiasana ady dia tsy maintsy esorinao ny parameter dry_run na hanova ny sandany ho Diso.

Rehefa vita ny script dia mamoaka logs amin'ny antsipiriany amin'ny console i Nornir.

Eo ambanin'ny mpandroba dia ny fivoahan'ny fiadiana amin'ny router fitsapana roa:

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

Manafina ny tenimiafina ao amin'ny ansible_vault

Tany am-piandohan'ny lahatsoratra dia nisondrotra kely aho azo atao, saingy tsy dia ratsy loatra izany. Tena tiako izy ireo andohalambony eny tahaka, izay natao hanafenana vaovao saro-pady tsy hitan'ny maso. Ary azo inoana fa maro no nahatsikaritra fa manana ny fidirana / tenimiafina rehetra ho an'ny mpitaingina ady rehetra mipoitra amin'ny endrika misokatra ao anaty rakitra. gorups.yaml. Mazava ho azy fa tsy tsara tarehy. Andao hiaro ity angona ity amin'ny andohalambony eny.

Andao hamindra ny masontsivana avy amin'ny groups.yaml mankany amin'ny creds.yaml, ary apetaho amin'ny AES256 miaraka amin'ny tenimiafina 20 isa:

$ 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

Tsotra izany. Mbola mitoetra ny mampianatra antsika Nornir-script hamerenana sy hampiharana an'io data io.
Mba hanaovana izany, ao amin'ny scripty aorian'ny tsipika fanombohana nr = InitNornir(config_file=… ampio ity code manaraka ity:

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

Mazava ho azy, ny vault.passwd dia tsy tokony ho eo akaikin'ny creds.yaml toy ny tamin'ny ohatra nataoko. Fa tsy maninona raha milalao.

Izay ihany aloha izao. Misy lahatsoratra roa hafa momba ny Cisco + Zabbix ho avy, saingy tsy momba ny automation izany. Ary ato ho ato dia mikasa ny hanoratra momba ny RESTCONF ao amin'ny Cisco aho.

Source: www.habr.com

Add a comment