Эй Ҳабр!
Ба наздикӣ дар ин ҷо як мақола пайдо шуд
Ин аввалин велосипед барои чунин вазифа нест. Варианти аввал чанд сол пеш дар бозгашт амалӣ карда шуд иҷрошаванда версияи 1.x.x. Велосипед кам истифода мешуд ва аз ин рӯ пайваста занг мезад. Ба он маъно, ки худи вазифа на он қадар зуд-зуд нав карда мешавад иҷрошаванда. Ва хар дафъае, ки ба шумо мошин рондан лозим меояд, занчир меафтад ё чарх меафтад. Аммо, қисми аввал, тавлиди конфигуратсияҳо, хушбахтона, ҳамеша хеле равшан кор мекунад ҷинҷа 2 Мотор кайҳо боз таъсис ёфтааст. Аммо қисми дуюм, ки конфигуратсияҳоро паҳн мекунад, одатан ногаҳонӣ овард. Ва азбаски ман бояд конфигуратсияро ба таври фосилавӣ ба нимсад дастгоҳ, ки баъзе аз онҳо ҳазорҳо километр дур ҷойгиранд, паҳн кунам, истифодаи ин асбоб каме дилгиркунанда буд.
Дар ин ҷо ман бояд иқрор шавам, ки номуайянии ман эҳтимолан дар набудани ошноии ман аст иҷрошаванданазар ба камбудихои худ. Ва ин, дар омади гап, як нуктаи муҳим аст. иҷрошаванда як минтақаи комилан алоҳида, соҳаи дониши худ бо DSL (Забони мушаххаси домен), ки бояд дар сатҳи боварӣ нигоҳ дошта шавад. Бале, ҳамон лаҳза иҷрошаванда Он хеле зуд инкишоф меёбад ва бидуни таваҷҷӯҳи махсус ба мутобиқати ақиб, он эътимодро илова намекунад.
Аз ин рӯ, чанде пеш версияи дуюми велосипед амалӣ карда шуд. Ин дафъа дар python, ё дурусттар дар чаҳорчӯбае, ки дар он навишта шудааст python ва барои python дар зери ном
Пас - Норнир микрочаҳорчӯба аст, ки дар он навишта шудааст python ва барои python ва барои автоматикунонӣ пешбинӣ шудааст. Ҳамон тавре ки дар мавриди бо иҷрошаванда, барои ҳалли мушкилот дар ин ҷо, омодасозии маълумоти салоҳиятдор талаб карда мешавад, яъне. инвентаризатсияи ҳостҳо ва параметрҳои онҳо, аммо скриптҳо на дар DSL-и алоҳида, балки дар ҳамон p[i|i]ton на он қадар кӯҳна, балки хеле хуб навишта шудаанд.
Биёед бубинем, ки он мисоли зиндаи зеринро истифода мебарад.
Ман як шабакаи филиал дорам, ки дар саросари кишвар даҳҳо офисҳо доранд. Ҳар як идора дорои роутери WAN мебошад, ки якчанд каналҳои алоқаро аз операторҳои гуногун қатъ мекунад. Протоколи масир BGP аст. Роутерҳои WAN дар ду намуд меоянд: Cisco ISG ё Juniper SRX.
Акнун вазифа: ба шумо лозим аст, ки зершабакаи махсусро барои назорати видеоӣ дар бандари алоҳида дар ҳама роутерҳои WAN-и шабакаи филиал танзим кунед - ин зершабакаро дар BGP таблиғ кунед - маҳдудияти суръати порти махсусро танзим кунед.
Аввалан, мо бояд якчанд шаблон омода кунем, ки дар асоси онҳо конфигуратсияҳо барои Cisco ва Juniper алоҳида тавлид карда мешаванд. Инчунин барои ҳар як нуқта ва параметрҳои пайвастшавӣ маълумот омода кардан лозим аст, яъне. ҳамон инвентаризатсияро ҷамъ кунед
Шаблони омода барои 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
Шаблонҳо, албатта, аз ҳаво берун намеоянд. Инҳо аслан фарқияти байни конфигуратсияҳои корӣ мебошанд, ки пас аз ҳалли вазифа дар ду роутери мушаххаси моделҳои гуногун буданд ва буданд.
Аз қолабҳои мо мебинем, ки барои ҳалли мушкилот ба мо танҳо ду параметр барои Juniper ва 3 параметр барои Cisco лозим аст. инҳоянд:
- ifname
- ipsuffix
- асн
Акнун мо бояд ин параметрҳоро барои ҳар як дастгоҳ муқаррар кунем, яъне. ҳамон корро кунед инвентаризатсияи.
барои инвентаризатсияи Мо ҳуҷҷатҳоро қатъиян риоя хоҳем кард
яъне биёед ҳамон скелети файлро созем:
.
├── 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 Мо чизеро нишон намедиҳем, аммо шумо бояд дар он ҷо се минус ворид кунед - нишон медиҳад, ки ин аст ямл ҳарчанд файл холӣ аст.
Ин аст он чизе ки 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
Ва ин аст group.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"
}
}
}
}
}
Ин модел метавонад каме печида бошад, махсусан дар аввал. Барои фаҳмидани он, режими интерактивӣ дар ipython.
$ 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 вобаста аст) , аммо конфигуратсияи нав мустақиман татбиқ карда намешавад. Барои истифодаи ҷангӣ, шумо бояд параметрро хориҷ кунед хушк_дав ё арзиши онро ба тағйир диҳед дуруц.
Вақте ки скрипт иҷро мешавад, 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. Зебо нест, албатта. Биёед ин маълумотро бо толор.
Биёед параметрҳоро аз group.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 дар Cisco нависам.
Манбаъ: will.com