Ọgbọ akpaaka na njuputa ihe nhazi ngwaọrụ netwọkụ na-eji Nornir

Ọgbọ akpaaka na njuputa ihe nhazi ngwaọrụ netwọkụ na-eji Nornir

Ndewo, Habr!

Na nso nso a otu akụkọ bilitere ebe a Mikrotik na Linux. Oge na akpaaka ebe a na-edozi nsogbu yiri nke ahụ site na iji ụzọ fossil. Ma n'agbanyeghị na ọrụ ahụ bụ nke a na-ahụkarị, ọ nweghị ihe yiri ya na Habré. Ana m anwa anwa ịnye ndị obodo IT a na-akwanyere ùgwù igwe igwe kwụ otu ebe.

Nke a abụghị nke mbụ igwe kwụ otu ebe maka ọrụ dị otú ahụ. Emebere nhọrọ nke mbụ ọtụtụ afọ gara aga laa azụ azịza ụdị 1.x.x. A naghị eji igwe kwụ otu ebe eme ihe, yabụ na-agba nchara mgbe niile. N'uche na ọrụ ahụ n'onwe ya adịghị ebili mgbe ọ bụla a na-emelite nsụgharị azịza. Na oge ọ bụla ịchọrọ ịkwọ ụgbọala, yinye ahụ na-adapụ ma ọ bụ wiil ahụ daa. Otú ọ dị, akụkụ nke mbụ, na-emepụta nhazi, na-arụ ọrụ mgbe niile nke ọma, ọ dabara nke ọma jinja2 A na-emezi engine ahụ ogologo oge. Mana akụkụ nke abụọ - ịtụgharị configs - na-ebutekarị ihe ịtụnanya. Ma ebe ọ bụ na m ga-ebupụ nhazi ahụ n'ebe dị anya na ọkara narị ngwaọrụ, ụfọdụ n'ime ha dị ọtụtụ puku kilomita site na iji ngwá ọrụ a bụ ntakịrị ihe na-agwụ ike.

N'ebe a, m ga-ekweta na ejighị m n'aka na ọ ga-abụ na amaghị m nke ọma azịzakarịa na adịghị ike ya. Na nke a, n'ụzọ, bụ isi ihe dị mkpa. azịza bụ ihe dị iche iche, mpaghara ihe ọmụma ya na DSL nke ya (Asụsụ Specific Language), nke a ga-edobe na ọkwa ntụkwasị obi. Ọfọn, mgbe ahụ azịza Ọ na-etolite ngwa ngwa, na-enweghị nkwanye ùgwù pụrụ iche maka ndakọrịta azụ, ọ naghị atụkwasị obi ike.

Ya mere, n'oge na-adịghị anya gara aga ka e mejuputa ụdị igwe nke abụọ. Oge a gawa eke, ma ọ bụ karịa n'usoro edere na eke na maka eke n'okpuru aha Nornir

Ya mere - Nornir bụ microframework edere na eke na maka eke na emebere maka akpaaka. Otu dị ka ikpe na azịza, iji dozie nsogbu ebe a, a chọrọ nkwadebe data ruru eru, ya bụ. Ndepụta nke ndị ụsụụ ndị agha na parampat ha, mana edeghị scripts ọ bụghị na DSL dị iche, mana n'otu ụzọ ahụ abụghị nke ochie, mana ezigbo p[i|i] ton.

Ka anyị leba anya n'ihe ọ na-eji ihe atụ ndụ na-esonụ.

Enwere m alaka ụlọ ọrụ nwere ọtụtụ ụlọ ọrụ iri na abụọ na mba ahụ. Ụlọ ọrụ ọ bụla nwere rawụta WAN nke na-akwụsị ọtụtụ ọwa nkwukọrịta sitere na ndị ọrụ dị iche iche. Usoro ntụgharị bụ BGP. Ndị na-anya ụgbọ ala WAN na-abịa n'ụdị abụọ: Cisco ISG ma ọ bụ Juniper SRX.

Ugbu a ọrụ a: ịkwesịrị ịhazi subnet raara onwe ya nye maka onyunyo vidiyo na ọdụ ụgbọ mmiri dị iche na ndị na-anya ụgbọ ala WAN niile nke netwọkụ alaka - kpọsaa subnet a na BGP - hazie oke ọsọ nke ọdụ ụgbọ mmiri raara onwe ya nye.

Nke mbụ, anyị kwesịrị ịkwadebe ụdị ndebiri abụọ, dabere na nhazi nke a ga-emepụta iche maka Cisco na Juniper. Ọ dịkwa mkpa iji dozie data maka isi ihe ọ bụla na paramita njikọ, ya bụ. na-anakọta otu ngwa ahịa

template dị njikere maka 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

Ụdị maka 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

Ụdị, n'ezie, anaghị apụta na mkpa ikuku. Ndị a bụ n'ezie ọdịiche dị n'etiti nhazi ọrụ nke bụ na mgbe edozichara ọrụ ahụ na ndị na-anya ụgbọ elu abụọ nke ụdị dị iche iche.

Site na ndebiri anyị, anyị na-ahụ na iji dozie nsogbu ahụ, anyị chọrọ naanị paramita abụọ maka Juniper na 3 paramita maka Cisco. ebe a ka ha bụ:

  • ọ bụrụ aha
  • ipsuffix
  • asn

Ugbu a, anyị kwesịrị ịtọ ntọala ndị a maka ngwaọrụ ọ bụla, i.e. mee otu ihe ahụ Ndepụta Ngwaahịa.

Iji Ndepụta Ngwaahịa Anyị ga-agbaso akwụkwọ ahụ nke ọma Na-amalite Nornir

ya bụ, ka anyị mepụta otu skeleton faịlụ:

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

Faịlụ config.yaml bụ faịlụ nhazi nornir ọkọlọtọ

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

Anyị ga-egosi isi ihe dị na faịlụ ahụ ndị ọbịa.yaml, otu (n'ọnọdụ m ndị a bụ logins/passwords) na otu.yaml, na n’ime ndabara.yaml Anyị agaghị egosi ihe ọ bụla, mana ịkwesịrị ịbanye minuses atọ ebe ahụ - na-egosi na ọ bụ yaml faịlụ ahụ tọgbọrọ chakoo.

Nke a bụ ihe hosts.yaml dị ka:

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

Na ebe a bụ otu.yaml:

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

juniper:
    platform: junos
    username: admin2
    password: juniper2

Nke a bụ ihe mere Ndepụta Ngwaahịa maka ọrụ anyị. N'oge mmalite, a na-edepụta paramita sitere na faịlụ ngwa ahịa na ụdị ihe ahụ Ndepụta Ngwaahịa.

N'okpuru onye na-emebi ihe bụ eserese nke ụdị 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"
                }
            }
        }
    }
}

Ihe nlereanya a nwere ike ile anya ntakịrị mgbagwoju anya, karịsịa na mbụ. Iji chọpụta ya, ọnọdụ mmekọrịta na-abanye 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'

Na n'ikpeazụ, ka anyị gaa n'ihu na edemede ahụ n'onwe ya. Enweghị m ihe m ga-eji na-anya isi ebe a. M nnọọ were a njikere mere ihe atụ si nkuzi ma jiri ya mee ihe fọrọ nke nta ka ọ bụrụ agbanweghị. Nke a bụ ihe edemede arụ ọrụ emechara dị ka:

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)

Lezienụ anya na oke dry_run=Eziokwu n'ahịrị ihe mmalite nr.
Ebe a dị ka in azịza emejuputa ule ule nke ejiri njikọ na rawụta mee ihe, a na-edozi nhazi ọhụrụ, nke a kwadoro site na ngwaọrụ ahụ (ma nke a ejighị n'aka; ọ dabere na nkwado ngwaọrụ na mmejuputa ọkwọ ụgbọala na NAPALM) , ma a naghị etinye nhazi ọhụrụ ahụ ozugbo. Maka iji ọgụ ọ dị mkpa iwepu oke dry_run ma ọ bụ gbanwee uru ya ka ọ bụrụ ụgha.

Mgbe emechara edemede ahụ, Nornir na-ewepụta ndekọ zuru ezu na njikwa.

N'okpuru onye na-emebi ihe bụ mmepụta nke ọgụ na-agba ọsọ na ndị na-anya ụgbọ mmiri abụọ:

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

Na-ezo okwuntughe na ansible_vault

Ná mmalite nke isiokwu ahụ, agara m ntakịrị ntakịrị azịza, ma ọ bụghị ihe niile dị njọ. Enwere m mmasị na ha uzo dị ka, nke e mere iji zoo ozi dị nro n'anya ya. Ma eleghị anya, ọtụtụ achọpụtala na anyị nwere logins / okwuntughe niile maka ndị na-anya ụgbọ agha na-egbuke egbuke n'ụdị na-emeghe na faịlụ. gorups.yaml. Ọ dịghị mma, n'ezie. Ka anyị jiri chebe data a uzo.

Ka anyị bufee paramita ahụ site na groups.yaml gaa creds.yaml, wee zoo ya na AES256 jiri paswọọdụ ọnụọgụ iri abụọ:

$ 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

Ọ dị mfe otú ahụ. Ọ na-anọgide na-akụziri anyị Nornir-script iji weghachite na itinye data a.
Iji mee nke a, na edemede anyị mgbe akara mmalite nr = InitNornir (config_file =… tinye koodu a:

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

N'ezie, vault.passwd ekwesịghị ịdị n'akụkụ creds.yaml dị ka n'ihe atụ m. Mana ọ dị mma igwu egwu.

Nke ahụ bụ naanị ugbu a. Enwere akụkọ di na nwunye ọzọ gbasara Cisco + Zabbix na-abịa, mana nke a abụghị ntakịrị gbasara akpaaka. Na n'ọdịnihu dị nso m na-eme atụmatụ ide banyere RESTCONF na Cisco.

isi: www.habr.com

Tinye a comment