Laboratorijska vežba – Modul 24 – Automatizacija dva VyOS rutera Python-om, Netmiko-om, REST API-jem i Ansible-om
Cilj vežbe
Pripremiti laboratoriju sa dva VyOS rutera i Ubuntu Server kontrolnim računarom, pa sa kontrolnog računara:
- automatski proveriti dostupnost uređaja,
- prikupiti izlaze
showkomandi, - napraviti backup konfiguracija sa poređenjem verzija,
- primeniti standardnu konfiguraciju Netmiko-om,
- pročitati konfiguraciju preko REST API-ja,
- uraditi isto Ansible-om uz proveru idempotentnosti.
Kredencijali se nikada ne upisuju u kod.
Napomena o legalnosti i ovlašćenju: Vežba koristi isključivo besplatan softver otvorenog koda (VyOS, Ubuntu Server, Python, Netmiko, Ansible) i uređaje koje ste sami napravili. Iste skripte pokrećite nad drugim uređajima samo ako ih administrirate ili imate pisano ovlašćenje.
Potrebno predznanje
- Kompletna teorija ovog modula (Teme 1–15).
- Rad u Linux terminalu, SSH i UFW (Modul 18); VirtualBox i Host-only mreža (Modul 21); VyOS
configure/set/commit/save(Modul 22).
Potrebni programi
- VirtualBox (Modul 21).
- Ubuntu Server VM iz Modula 18 (24.04 LTS ili novija), sa pristupom internetu preko NAT adaptera radi instalacije paketa.
- VyOS ISO image — besplatni rolling (ili Stream) image sa zvaničnog sajta vyos.io, isti kao u Modulu 22.
Potrebni resursi
| VM | vCPU | RAM | Disk |
|---|---|---|---|
| Ubuntu Server (kontrolni računar) | 1–2 | 2 GB | postojeći |
| VYOS1 | 1 | 1 GB | 4 GB |
| VYOS2 | 1 | 1 GB | 4 GB |
Preporuka: najmanje 8 GB RAM-a na host računaru.
Topologija
VirtualBox Host-only mreža 192.168.56.0/24
------------------------------------------------------------
| | |
UBUNTU-SRV VYOS1 (eth0) VYOS2 (eth0)
192.168.56.20 192.168.56.11 192.168.56.12
(Python, Netmiko, SSH, HTTPS API SSH
Ansible)
|
NAT adapter → internet (apt, pip)
Plan adresiranja
| VM | Interfejs | Adresa | Namena |
|---|---|---|---|
| UBUNTU-SRV | Host-only | 192.168.56.20/24 | Kontrolni računar (Modul 18) |
| VYOS1 | eth0 (Host-only) | 192.168.56.11/24 | Upravljanje |
| VYOS1 | dum0 | 10.255.255.11/32 | Loopback (dodaje se skriptom) |
| VYOS2 | eth0 (Host-only) | 192.168.56.12/24 | Upravljanje |
| VYOS2 | dum0 | 10.255.255.12/32 | Loopback (dodaje se skriptom) |
Ako ste u Modulu 21 Ubuntu Server VM prebacili u Internal Network segmente, vratite snapshot iz Modula 18 ili ponovo uključite Host-only adapter sa adresom 192.168.56.20.
Struktura projekta na kontrolnom računaru
~/netauto-lab/
├── venv/ (virtuelno Python okruženje)
├── .gitignore
├── uredjaji.yaml (spisak uređaja — bez lozinki)
├── zajednicko.py (učitavanje uređaja i kredencijala)
├── provera_dostupnosti.py
├── prikupi_show.py
├── backup.py
├── konfigurisi.py
├── api_citanje.py
└── ansible/
├── ansible.cfg
├── inventory.ini
├── group_vars/vyos/vars.yml
├── group_vars/vyos/vault.yml (šifrovano)
├── prikupi.yml
└── standard.yml
Koraci vežbe
Korak 1 – Instalacija VyOS VM-ova
Za svaki ruter (VYOS1, pa VYOS2):
- U VirtualBox-u napravite novu VM: tip Linux, verzija Debian (64-bit), resursi iz tabele. Adapter 1: Host-only (ista mreža kao Ubuntu Server VM).
- Pokrenite VM sa VyOS ISO image-om i prijavite se kao
vyos/vyos(live režim). - Instalirajte sistem na disk komandom
install imagei prihvatite ponuđene odgovore; kada se traži, postavite svoju lozinku za korisnikavyos. - Posle završetka isključite VM, uklonite ISO iz virtuelnog optičkog uređaja i ponovo je pokrenite.
Korak 2 – Osnovna konfiguracija i nalog za automatizaciju
Na VYOS1 (konzola u VirtualBox-u):
configure
set system host-name VYOS1
set interfaces ethernet eth0 address 192.168.56.11/24
set service ssh
set system login user netauto authentication plaintext-password '<vaša lozinka za automatizaciju>'
commit
save
exit
Na VYOS2 isto, sa host-name VYOS2 i adresom 192.168.56.12/24, i istom lozinkom za nalog netauto.
Sa Ubuntu Server VM-a proverite i prihvatite SSH ključeve oba rutera (odgovorite yes na pitanje o ključu):
ssh netauto@192.168.56.11
exit
ssh netauto@192.168.56.12
exit
Napravite snapshot oba VyOS VM-a sa nazivom Pre-automatizacije (Modul 21).
VyOS nalozi imaju administratorska prava. U produkciji bi nalog za automatizaciju imao samo potrebna prava, preko centralne autentifikacije (TACACS+/RADIUS, Modul 16).
Korak 3 – Python okruženje
Na Ubuntu Server VM-u:
sudo apt update
sudo apt install -y python3-venv python3-pip git
mkdir -p ~/netauto-lab && cd ~/netauto-lab
python3 -m venv venv
source venv/bin/activate
pip install netmiko pyyaml requests ansible
Provera:
python -c "import netmiko, yaml, requests; print('Netmiko', netmiko.__version__)"
ansible --version
ansible-galaxy collection list | grep -E "vyos|netcommon"
Treba da se vide kolekcije vyos.vyos i ansible.netcommon. Prompt terminala počinje sa (venv) — kad god otvorite novi terminal, pre rada izvršite cd ~/netauto-lab && source venv/bin/activate.
Korak 4 – Kredencijali i .gitignore
Kredencijali se postavljaju kao promenljive okruženja samo u tekućoj sesiji terminala:
export NET_USER=netauto
read -s -p "Lozinka za netauto: " NET_PASS; echo; export NET_PASS
Napravite .gitignore i inicijalizujte Git repozitorijum:
cat > .gitignore << 'EOF'
venv/
backup/
izlazi/
*.json
.env
EOF
git init
Backup konfiguracija ne ide u javni repozitorijum (sadrži hash-eve lozinki), pa je isključen; u firmi bi se čuvao u posebnom, zaštićenom repozitorijumu.
Korak 5 – Spisak uređaja i zajednički modul
uredjaji.yaml:
---
uredjaji:
- ime: VYOS1
host: 192.168.56.11
device_type: vyos
loopback: 10.255.255.11/32
- ime: VYOS2
host: 192.168.56.12
device_type: vyos
loopback: 10.255.255.12/32
zajednicko.py:
import os
import yaml
def ucitaj_uredjaje(putanja="uredjaji.yaml"):
with open(putanja, encoding="utf-8") as f:
return yaml.safe_load(f)["uredjaji"]
def parametri_veze(uredjaj):
return {
"device_type": uredjaj["device_type"],
"host": uredjaj["host"],
"username": os.environ["NET_USER"],
"password": os.environ["NET_PASS"],
}
Korak 6 – Provera dostupnosti
provera_dostupnosti.py:
import json
import socket
import subprocess
from datetime import datetime
from zajednicko import ucitaj_uredjaje
def ping(ip):
rezultat = subprocess.run(["ping", "-c", "2", "-W", "1", ip], capture_output=True)
return rezultat.returncode == 0
def port_otvoren(ip, port=22, timeout=2):
try:
with socket.create_connection((ip, port), timeout=timeout):
return True
except OSError:
return False
izvestaj = {"vreme": datetime.now().isoformat(timespec="seconds"), "uredjaji": []}
for u in ucitaj_uredjaje():
stanje = {"ime": u["ime"], "host": u["host"], "ping": ping(u["host"]), "ssh": port_otvoren(u["host"])}
izvestaj["uredjaji"].append(stanje)
print(f"{u['ime']:6} ping={'OK' if stanje['ping'] else 'NE'} ssh={'OK' if stanje['ssh'] else 'NE'}")
with open("dostupnost.json", "w", encoding="utf-8") as f:
json.dump(izvestaj, f, indent=2, ensure_ascii=False)
Pokrenite python provera_dostupnosti.py i otvorite dostupnost.json.
Korak 7 – Prikupljanje show komandi
prikupi_show.py:
from datetime import datetime
from pathlib import Path
from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoAuthenticationException, NetmikoTimeoutException
from zajednicko import parametri_veze, ucitaj_uredjaje
KOMANDE = ["show version", "show interfaces", "show ip route"]
folder = Path("izlazi") / datetime.now().strftime("%Y-%m-%d_%H%M")
folder.mkdir(parents=True, exist_ok=True)
for u in ucitaj_uredjaje():
try:
with ConnectHandler(**parametri_veze(u)) as veza:
for komanda in KOMANDE:
izlaz = veza.send_command(komanda)
fajl = folder / f"{u['ime']}_{komanda.replace(' ', '_')}.txt"
fajl.write_text(izlaz, encoding="utf-8")
if komanda == "show version":
for red in izlaz.splitlines():
if red.startswith("Version:"):
print(f"{u['ime']}: {red.split(':', 1)[1].strip()}")
print(f"{u['ime']}: prikupljeno {len(KOMANDE)} komandi u {folder}")
except (NetmikoTimeoutException, NetmikoAuthenticationException) as greska:
print(f"{u['ime']}: GREŠKA — {type(greska).__name__}")
Pokrenite skriptu i pregledajte fajlove u folderu izlazi/.
Korak 8 – Backup konfiguracija sa poređenjem verzija
backup.py:
import difflib
from datetime import datetime
from pathlib import Path
from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoAuthenticationException, NetmikoTimeoutException
from zajednicko import parametri_veze, ucitaj_uredjaje
folder = Path("backup")
folder.mkdir(mode=0o700, exist_ok=True)
oznaka = datetime.now().strftime("%Y-%m-%d_%H%M%S")
neuspesni = []
for u in ucitaj_uredjaje():
prethodni = sorted(folder.glob(f"{u['ime']}_*.cfg"))
try:
with ConnectHandler(**parametri_veze(u)) as veza:
konfiguracija = veza.send_command("show configuration commands")
except (NetmikoTimeoutException, NetmikoAuthenticationException) as greska:
neuspesni.append(u["ime"])
print(f"{u['ime']}: BACKUP NIJE USPEO — {type(greska).__name__}")
continue
novi = folder / f"{u['ime']}_{oznaka}.cfg"
novi.write_text(konfiguracija + "\n", encoding="utf-8")
print(f"{u['ime']}: sačuvano u {novi}")
if prethodni:
stari_redovi = prethodni[-1].read_text(encoding="utf-8").splitlines()
razlike = list(difflib.unified_diff(stari_redovi, konfiguracija.splitlines(),
prethodni[-1].name, novi.name, lineterm=""))
print("\n".join(razlike) if razlike else " (nema izmena u odnosu na prethodni backup)")
if neuspesni:
raise SystemExit(f"Neuspešan backup: {', '.join(neuspesni)}")
- Pokrenite
python backup.py— nastaju prvi backup-i. - Ručno se prijavite na VYOS2 (
ssh netauto@192.168.56.12) i dodajte opis:configure,set interfaces ethernet eth0 description 'RUCNA-IZMENA',commit,save,exit,exit. - Ponovo pokrenite
python backup.py— za VYOS2 skripta prikazuje razliku (red sa+), a za VYOS1 „nema izmena".
Korak 9 – Primena standardne konfiguracije Netmiko-om
konfigurisi.py:
from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoAuthenticationException, NetmikoTimeoutException
from zajednicko import parametri_veze, ucitaj_uredjaje
for u in ucitaj_uredjaje():
komande = [
"set system login banner pre-login 'Samo za ovlascene korisnike'",
"set interfaces ethernet eth0 description 'MGMT-HOSTONLY'",
f"set interfaces dummy dum0 address {u['loopback']}",
"set interfaces dummy dum0 description 'LOOPBACK-UPRAVLJANJE'",
]
try:
with ConnectHandler(**parametri_veze(u)) as veza:
veza.send_config_set(komande)
veza.commit(comment="Standard iz skripte konfigurisi.py")
veza.save_config()
provera = veza.send_command("show interfaces")
print(f"=== {u['ime']} ===\n{provera}")
except (NetmikoTimeoutException, NetmikoAuthenticationException, ValueError) as greska:
print(f"{u['ime']}: IZMENA NIJE PRIMENJENA — {greska}")
Pokrenite skriptu. U izlazu show interfaces proverite adresu i opis dum0 i opis eth0 na oba rutera. Zatim pokrenite python backup.py i pogledajte razlike — opis RUCNA-IZMENA na VYOS2 zamenjen je standardnim.
Korak 10 – Čitanje konfiguracije preko REST API-ja
Na VYOS1 (SSH ili konzola) uključite HTTP API sa ključem koji sami izmislite:
configure
set service https api keys id automatizacija key '<vaš API ključ>'
commit
save
exit
Ako
commitprođe, ali API na zahteve ne odgovara ili vraća grešku 404, u novijim rolling verzijama VyOS-a REST pristup se uključuje i posebnom komandomset service https api rest(pa ponovocommitisave).
Na Ubuntu Server VM-u postavite ključ kao promenljivu okruženja (read -s -p "API ključ: " VYOS_API_KEY; echo; export VYOS_API_KEY) i napravite api_citanje.py:
import json
import os
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
odgovor = requests.post(
"https://192.168.56.11/retrieve",
data={
"data": json.dumps({"op": "showConfig", "path": ["interfaces"]}),
"key": os.environ["VYOS_API_KEY"],
},
verify=False, # samo u izolovanoj laboratoriji: samopotpisan sertifikat
timeout=10,
)
odgovor.raise_for_status()
rezultat = odgovor.json()
if not rezultat["success"]:
raise SystemExit(f"API greška: {rezultat['error']}")
for tip, interfejsi in rezultat["data"].items():
for ime, podesavanja in interfejsi.items():
adrese = podesavanja.get("address", [])
if isinstance(adrese, str):
adrese = [adrese]
print(f"{tip:9} {ime:5} {', '.join(adrese):20} {podesavanja.get('description', '')}")
Pokrenite skriptu. Uporedite ovaj rezultat (strukturisani podaci) sa tekstualnim izlazom show interfaces iz Koraka 9. Probajte i pogrešan ključ — rezultat je HTTP greška 401 ili 403.
Korak 11 – Ansible: inventory, Vault i prvi playbook
mkdir -p ~/netauto-lab/ansible/group_vars/vyos && cd ~/netauto-lab/ansible
ansible.cfg:
[defaults]
inventory = inventory.ini
[persistent_connection]
command_timeout = 30
inventory.ini:
[vyos]
vyos1 ansible_host=192.168.56.11
vyos2 ansible_host=192.168.56.12
[vyos:vars]
ansible_connection=ansible.netcommon.network_cli
ansible_network_os=vyos.vyos.vyos
ansible_user=netauto
group_vars/vyos/vars.yml:
---
ansible_password: "{{ vault_lozinka }}"
Šifrovani fajl sa lozinkom:
ansible-vault create group_vars/vyos/vault.yml
Postavite lozinku za Vault, a u editoru koji se otvori upišite jedan red vault_lozinka: <lozinka naloga netauto> i sačuvajte. Proverite da je fajl šifrovan: cat group_vars/vyos/vault.yml prikazuje samo $ANSIBLE_VAULT;1.1;AES256 i niz brojeva.
prikupi.yml:
---
- name: Prikupljanje podataka sa VyOS rutera
hosts: vyos
gather_facts: false
tasks:
- name: Verzija softvera
vyos.vyos.vyos_command:
commands:
- show version
register: verzija
- name: Prikaz prva tri reda
ansible.builtin.debug:
msg: "{{ verzija.stdout_lines[0][:3] }}"
ansible-inventory --graph
ansible-playbook prikupi.yml --ask-vault-pass
Korak 12 – Ansible: standardna konfiguracija i idempotentnost
standard.yml:
---
- name: Standardna konfiguracija VyOS rutera
hosts: vyos
gather_facts: false
tasks:
- name: Vremenska zona i poruka posle prijave
vyos.vyos.vyos_config:
lines:
- set system time-zone 'Europe/Belgrade'
- set system login banner post-login 'Pristup se evidentira'
save: true
- Suvi rad:
ansible-playbook standard.yml --ask-vault-pass --check --diff— prikazuje šta bi se promenilo, bez izmena. - Primena:
ansible-playbook standard.yml --ask-vault-pass— uPLAY RECAPjechanged=1za oba rutera. - Ponovo ista komanda — sada
changed=0: uređaji su već u željenom stanju. - Na VYOS1 ručno obrišite poruku (
configure,delete system login banner post-login,commit,save) i pokrenite playbook samo za taj ruter:ansible-playbook standard.yml --ask-vault-pass --limit vyos1— odstupanje je otkriveno i ispravljeno (changed=1samo za vyos1).
Korak 13 – Dijagnostička vežba: ruter odgovara na ping, a skripte ne rade
- Na konzoli VYOS2 (u VirtualBox-u, ne preko SSH-a) isključite SSH servis:
configure
delete service ssh
commit
save
exit
- Na kontrolnom računaru pokrenite
python backup.py. VYOS1 uspeva, a za VYOS2 skripta prijavljuje grešku i završava se porukom „Neuspešan backup: VYOS2". - Utvrdite uzrok sistematski, bez nagađanja: koju proveru prvo pokrećete, šta ona pokazuje, i šta iz toga zaključujete?
- Ispravite problem na konzoli VYOS2 i potvrdite da i
provera_dostupnosti.pyibackup.pyponovo uspevaju za oba rutera.
Komande za proveru
| Komanda | Šta proverava |
|---|---|
python provera_dostupnosti.py | Ping i SSH dostupnost svih uređaja iz uredjaji.yaml |
ls -l izlazi/*/ backup/ | Da li su izlazi i backup-i sačuvani |
show interfaces (VyOS) | Adrese i opisi interfejsa posle izmena |
show configuration commands | match banner (VyOS) | Da li je banner primenjen |
ansible-inventory --graph | Struktura inventory-ja |
ansible-playbook ... --check --diff | Šta bi playbook promenio |
grep -rn "<deo lozinke>" ~/netauto-lab --exclude-dir=venv | Da lozinka nije nigde upisana kao tekst |
Najčešće greške
KeyError: 'NET_PASS'— promenljive okruženja nisu postavljene u ovom terminalu (Korak 4).ModuleNotFoundError: No module named 'netmiko'— virtuelno okruženje nije aktivirano (source venv/bin/activate).NetmikoAuthenticationException— pogrešna lozinka ili nalognetautonije napravljen na tom ruteru.- Ansible greška o nepoznatom ključu hosta — ruter nije bar jednom otvoren ručnim
sshpristupom (Korak 2), ili je VM ponovo instaliran pa ima novi ključ (ssh-keygen -R 192.168.56.11). - Ansible svaki put prijavljuje
changed— linija ulinesse ne poklapa sa zapisom ushow configuration commands. - YAML greška — tab umesto razmaka ili pomereno uvlačenje.
Postupak rešavanja problema
- Mrežna dostupnost:
pingsa kontrolnog računara. - Servis: TCP port 22 (
provera_dostupnosti.pyilinc -zv 192.168.56.12 22). - Autentifikacija: ručni
ssh netauto@<adresa>sa istom lozinkom. - Okruženje skripte: aktivirano virtuelno okruženje, postavljene promenljive okruženja.
- Logika skripte: poruka o grešci i red u kodu na koji ukazuje.
Završna provera
- [ ] Oba VyOS rutera su instalirana, dostupna preko SSH-a i imaju nalog
netauto. - [ ]
dostupnost.jsonsadrži oba rutera sapingissh=true. - [ ] U folderu
izlazi/postoje izlazi tri komande za oba rutera. - [ ] Postoje najmanje dva backup-a po ruteru, a razlika posle ručne izmene je prikazana.
- [ ] Standardna konfiguracija (banner, opisi,
dum0) je primenjena i sačuvana na oba rutera. - [ ] Konfiguracija interfejsa je pročitana preko REST API-ja.
- [ ] Ansible playbook drugi put prijavljuje
changed=0. - [ ] Nijedan fajl u projektu ne sadrži lozinku ili API ključ kao običan tekst.
- [ ] Greška iz Koraka 13 je pronađena i ispravljena.
Dodatni izazov
- Automatsko noćno pokretanje: podesite
crondabackup.pypokreće svake noći u 2:00. Kredencijale čitajte iz fajla~/.netauto.envsa pravima600(samo vlasnik), koji skripta za pokretanje učita pre Python-a. Obrazložite zašto je ovo prihvatljivo u laboratoriji, a šta bi se koristilo u produkciji. - Bezbedan povratak: na VYOS1 (preko konzole) primenite izmenu komandom
commit-confirm 2(umestocommit), ne izvršavajtesavei nemojte je potvrditi komandomconfirm. Posmatrajte šta se dešava posle dva minuta i objasnite kako ovo štiti od izmene koja preseca upravljački pristup. - Paralelno izvršavanje: prepravite
prikupi_show.pytako da uređaje obrađuje paralelno pomoćuconcurrent.futures.ThreadPoolExecutor.
Rešenje
Kompletno rešenje dostupno je u /resenja/modul-24/04-laboratorijska-vezba-resenje.md.
📖 Prikaži rešenje
Rešenje laboratorijske vežbe – Modul 24
Tačne verzije softvera, MAC adrese i vremena u izlazima razlikuju se od instalacije do instalacije. Bitni su struktura izlaza i zaključci.
Korak 3 – Očekivana provera okruženja
(venv) admin@ubuntu-srv:~/netauto-lab$ python -c "import netmiko, yaml, requests; print('Netmiko', netmiko.__version__)"
Netmiko 4.x.x
(venv) admin@ubuntu-srv:~/netauto-lab$ ansible-galaxy collection list | grep -E "vyos|netcommon"
ansible.netcommon x.y.z
vyos.vyos x.y.z
Korak 6 – Provera dostupnosti
VYOS1 ping=OK ssh=OK
VYOS2 ping=OK ssh=OK
dostupnost.json:
{
"vreme": "2026-09-25T10:15:02",
"uredjaji": [
{"ime": "VYOS1", "host": "192.168.56.11", "ping": true, "ssh": true},
{"ime": "VYOS2", "host": "192.168.56.12", "ping": true, "ssh": true}
]
}
Korak 7 – Prikupljanje show komandi
VYOS1: VyOS 1.5-rolling-...
VYOS1: prikupljeno 3 komandi u izlazi/2026-09-25_1016
VYOS2: VyOS 1.5-rolling-...
VYOS2: prikupljeno 3 komandi u izlazi/2026-09-25_1016
U folderu je šest fajlova: VYOS1_show_version.txt, VYOS1_show_interfaces.txt, VYOS1_show_ip_route.txt i isti za VYOS2. Tabela ruta sadrži samo direktno povezanu mrežu C>* 192.168.56.0/24 is directly connected, eth0.
Korak 8 – Backup i razlike
Prvo pokretanje:
VYOS1: sačuvano u backup/VYOS1_2026-09-25_101700.cfg
VYOS2: sačuvano u backup/VYOS2_2026-09-25_101700.cfg
Drugo pokretanje, posle ručne izmene na VYOS2:
VYOS1: sačuvano u backup/VYOS1_2026-09-25_102030.cfg
(nema izmena u odnosu na prethodni backup)
VYOS2: sačuvano u backup/VYOS2_2026-09-25_102030.cfg
--- VYOS2_2026-09-25_101700.cfg
+++ VYOS2_2026-09-25_102030.cfg
@@ -1,4 +1,5 @@
set interfaces ethernet eth0 address '192.168.56.12/24'
+set interfaces ethernet eth0 description 'RUCNA-IZMENA'
set interfaces ethernet eth0 hw-id '08:00:27:xx:xx:xx'
...
Zašto je folder backup/ napravljen sa pravima 0o700: show configuration commands sadrži i encrypted-password hash-eve naloga; backup je poverljiv dokument (Modul 23).
Korak 9 – Standardna konfiguracija
Skraćen izlaz za VYOS1:
=== VYOS1 ===
Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down
Interface IP Address MAC VRF MTU S/L Description
----------- ----------------- ----------------- ------- --- ----- --------------------
dum0 10.255.255.11/32 xx:xx:xx:xx:xx:xx default 1500 u/u LOOPBACK-UPRAVLJANJE
eth0 192.168.56.11/24 08:00:27:xx:xx:xx default 1500 u/u MGMT-HOSTONLY
lo 127.0.0.1/8 00:00:00:00:00:00 default 65536 u/u
Naredni backup.py za VYOS2 prikazuje zamenu 'RUCNA-IZMENA' sa 'MGMT-HOSTONLY' i nove redove za dum0 i banner. Za VYOS1 prikazuje samo nove redove. Na VYOS-u je i commit komentar vidljiv u istoriji izmena: show system commit.
Korak 10 – REST API
dummy dum0 10.255.255.11/32 LOOPBACK-UPRAVLJANJE
ethernet eth0 192.168.56.11/24 MGMT-HOSTONLY
loopback lo
Sa pogrešnim ključem raise_for_status() prekida skriptu HTTP greškom (401 ili 403, zavisno od verzije VyOS-a). Upit se ne izvršava, a ključ nije otkriven. Razlika u odnosu na Korak 9: API vraća rečnike po tipu i nazivu interfejsa, pa skripta ne mora da parsira tekstualnu tabelu.
Korak 11 – Ansible prikupljanje
TASK [Prikaz prva tri reda] ****************************************
ok: [vyos1] => {
"msg": [
"Version: VyOS 1.5-rolling-...",
"Release train: current",
"Release flavor: generic"
]
}
ok: [vyos2] => { ... }
PLAY RECAP *********************************************************
vyos1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0
vyos2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0
(Tačan sadržaj prva tri reda zavisi od verzije VyOS-a.)
Korak 12 – Idempotentnost
| Pokretanje | Rezultat |
|---|---|
--check --diff | changed za oba rutera; prikazane linije koje bi bile poslate; na uređajima ništa nije promenjeno |
| Prvo stvarno pokretanje | changed=1 za vyos1 i vyos2 |
| Drugo pokretanje | changed=0 za oba — stanje je već ispravno |
Posle ručnog brisanja poruke, --limit vyos1 | changed=1 samo za vyos1; vyos2 nije ni kontaktiran |
Modul vyos_config poredi zahtevane linije sa show configuration commands (bez obzira na navodnike) i šalje samo linije koje nedostaju. Zato je drugo pokretanje bez izmena.
Korak 13 – Dijagnostička vežba
Simptom: backup.py uspeva za VYOS1, a za VYOS2 prijavljuje BACKUP NIJE USPEO — NetmikoTimeoutException i završava se sa „Neuspešan backup: VYOS2".
Dijagnostika: prvo python provera_dostupnosti.py:
VYOS1 ping=OK ssh=OK
VYOS2 ping=OK ssh=NE
Ping radi, pa su mrežna veza i adresa ispravne. TCP port 22 nije dostupan, pa problem nije u lozinki ni u skripti, već u SSH servisu na ruteru. Na konzoli VYOS2 show configuration commands | match ssh ne vraća ništa — SSH servis nije podešen.
Uzrok: isključen SSH servis (delete service ssh). Netmiko ne može da uspostavi TCP vezu i prijavljuje NetmikoTimeoutException.
Ispravka (konzola VYOS2):
configure
set service ssh
commit
save
exit
Posle ispravke obe skripte uspevaju za oba rutera. Pouka: provera ping + TCP port za nekoliko sekundi razdvaja mrežni problem, problem servisa i problem autentifikacije. Zato se pokreće pre svake automatizacije.
Rešenje dodatnog izazova
1. Noćni backup iz cron-a. Fajl ~/.netauto.env (prava 600, vlasnik je jedini koji ga čita):
NET_USER=netauto
NET_PASS=<lozinka>
chmod 600 ~/.netauto.env
Skripta ~/netauto-lab/pokreni_backup.sh (prava 700):
#!/bin/bash
set -a
source "$HOME/.netauto.env"
set +a
cd "$HOME/netauto-lab" || exit 1
"$HOME/netauto-lab/venv/bin/python" backup.py >> "$HOME/netauto-lab/backup.log" 2>&1
crontab -e:
0 2 * * * /home/<korisnik>/netauto-lab/pokreni_backup.sh
U laboratoriji je fajl sa pravima 600 prihvatljiv, jer je lozinka van koda i van Git-a, a čitljiva je samo vlasniku naloga. U produkciji bi se koristio poseban nalog samo za čitanje (dovoljan za backup) sa SSH ključem, ili kredencijali iz sistema za tajne (HashiCorp Vault) koje skripta preuzima pri pokretanju. Neuspeh backup-a (izlazni kod različit od 0) prijavljivao bi se monitoring sistemu.
2. commit-confirm. Posle commit-confirm 2 VyOS ispisuje da izmenu treba potvrditi komandom confirm. Kako potvrde nema, posle dva minuta ruter se sam vraća na prethodnu, sačuvanu konfiguraciju. Na starijim verzijama to radi restartom sistema, a na novijim može i ponovnim učitavanjem konfiguracije (podešavanje system config-management commit-confirm action). Zato se pre potvrde ne sme izvršiti save. Kada izmena greškom preseče upravljački pristup (npr. firewall pravilo ili pogrešna adresa na eth0), administrator ne može da pošalje confirm, pa se ruter sam vraća u stanje u kome je bio dostupan.
3. Paralelno prikupljanje:
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
from pathlib import Path
from netmiko import ConnectHandler
from netmiko.exceptions import NetmikoAuthenticationException, NetmikoTimeoutException
from zajednicko import parametri_veze, ucitaj_uredjaje
KOMANDE = ["show version", "show interfaces", "show ip route"]
folder = Path("izlazi") / datetime.now().strftime("%Y-%m-%d_%H%M")
folder.mkdir(parents=True, exist_ok=True)
def prikupi(u):
try:
with ConnectHandler(**parametri_veze(u)) as veza:
for komanda in KOMANDE:
izlaz = veza.send_command(komanda)
(folder / f"{u['ime']}_{komanda.replace(' ', '_')}.txt").write_text(izlaz, encoding="utf-8")
return f"{u['ime']}: prikupljeno {len(KOMANDE)} komandi"
except (NetmikoTimeoutException, NetmikoAuthenticationException) as greska:
return f"{u['ime']}: GREŠKA — {type(greska).__name__}"
with ThreadPoolExecutor(max_workers=10) as izvrsilac:
for poruka in izvrsilac.map(prikupi, ucitaj_uredjaje()):
print(poruka)
Svaki uređaj se obrađuje u posebnoj niti, pa ukupno trajanje približno odgovara trajanju najsporijeg uređaja, a ne zbiru svih. max_workers ograničava broj istovremenih SSH sesija, da se ne preopterete uređaji ni kontrolni računar.