Skriptování uvnitř HP Comware OS Tomáš Kubica
HP Comware verze 7 Dokument verze 1.00 Skripty v zip souboru Duben 2014
Úvod Následující lab guide není oficiálním dokumentem, ani jej nelze považovat za best practice. Tento lab se zaměřuje na moderní možnosti skriptování zejména uvnitř operačního systému Comware 7, který je k nalezení na přepínačích a směrovačích HP. Zejména se bude soustředit na integrovaný interpretátor jazyka Python a některé další možnosti. Materiál je vhodné kombinovat s manuály k prvkům s podporou Python, například HP 5900. Dále pak s nějakou obecně dostupnou učebnicí Python. Zkoušet můžete přímo na prvku s touto podporou nebo v nejnovějším simulátoru Comware sítí (Simware 2.0) – více informací na www.netsvet.cz. Skripty nemusíte přepisovat – na stránkách je ke stažení zip soubor. Přeji vám hodně zdaru a hlavně inovativní inspirace! Tomáš Kubica
2|HP skriptování v Comware
Obsah Úvod ........................................................................................................................................................ 2 Moderní skriptování................................................................................................................................ 4 Zabudovaný Python v Comware ............................................................................................................. 4 Základy Python v Comware................................................................................................................. 4 Kopírka portů .................................................................................................................................... 10 Automatické pojmenování portů na základě LLDP ........................................................................... 14 Generování náhodných routes ......................................................................................................... 18 Zálohování konfigurace na FTP server .............................................................................................. 22 Embedded Automation Architecture (EAA) .......................................................................................... 25 Na co lze reagovat ............................................................................................................................. 25 CLI monitor.................................................................................................................................... 25 Syslog ............................................................................................................................................ 25 SNMP notifikace ............................................................................................................................ 25 SNMP hodnota .............................................................................................................................. 25 Process .......................................................................................................................................... 25 Hotplug.......................................................................................................................................... 25 Interface ........................................................................................................................................ 25 Jak reakce vypadá ............................................................................................................................. 26 Další konfigurovatelné vlastnosti ...................................................................................................... 26 Zápis na FTP server při uložení konfigurace...................................................................................... 26 Update port description na základě nového LLDP souseda ............................................................. 27 Přetížený port ................................................................................................................................... 29 Plánování úloh....................................................................................................................................... 30 Závěr ..................................................................................................................................................... 32
3|HP skriptování v Comware
Moderní skriptování Zabudovaný Python v Comware V operačním systému Comware 7 se u některých zařízení už nachází interpret jazyka Python. Ten je velmi oblíbený pro svou jednoduchost a přívětivost ke všem – a to i k těm, kteří s programováním začínají, nebo není jejich primární znalostí. Nejprve si vyzkoušíme pár základů a pak se vrhneme na konkrétní příklady skriptů.
Základy Python v Comware Jak začít? Vstupte do příkazové řádky (třeba na HP 5900) a napište „python“ … jak jinak. <Switch1>python Python 2.7.3 (default, May 24 2013, 14:37:26) [GCC 4.4.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>
Nacházíme s v interaktivním Python režimu, který je ideální na zkoušení a hledání té správné syntaxe. Pokud ještě Python neznáte, doporučuji si projít nějaký úvodní kurz. Tento jazyk vás nenutí dopředu deklarovat proměnné, definovat jejich typ – je zkrátka velmi přívětivý. Co si můžete vyzkoušet? >>> 1 + 5 6 >>> 'Tomas' + ' ' + 'Kubica' 'Tomas Kubica' >>> vysledek = 5 + 9 >>> print vysledek 14 >>> print 'Vysledek je: ' + str(vysledek) Vysledek je: 14
A co požádat uživatele o vstup? >>> odpoved = raw_input('Co pijes? ') Co pijes? pivo >>> print 'Jojo, ' + odpoved + ' je fajn.' Jojo, pivo je fajn. >>>
Složitější bude, pokud chceme jeho odpověď omezit – například ano/ne. K tomu už je nejlépe vytvořit si funkci. To je v Python velmi jednoduché a používá se slovíčko “def”. V tomto jazyce se funkce (nebo obecně jakékoli bloky) nezačínají a neukončují nějakým speciálním znakem (jako {} v Java), ale jednoduše se kód odšoupne mezerami (typicky 4, ale lze i jinak). Také si ukážeme cyklus While – dokud totiž nedostaneme požadovanou odpověď (ano nebo ne), tak program nepustíme dál. Pojďme na to. >>> def zeptat(otazka): ... valid = {"ano":True, "a":True, "ne":False, "n":False} ... while True:
4|HP skriptování v Comware
... choice = raw_input(otazka).lower() ... if choice in valid: ... return valid[choice] ... else: ... print 'Potrebuji odpoved ano nebo ne' ... >>> >>> zeptat('Mas rad pivo? [a/n]') Mas rad pivo? [a/n]nevim Potrebuji odpoved ano nebo ne Mas rad pivo? [a/n]a True >>>
A takhle bychom toho mohli využít >>> if zeptat('Mas rad pivo? [a/n]'): ... print 'Ma rad pivo' ... else: ... print 'Nema rad pivo' ... Mas rad pivo? [a/n]n Nema rad pivo >>>
Potřebujete krátký komentář k tomu, co se tam děje? V zásadě jsme si vyzkoušeli hned najednou spoustu věcí. Příkazem def jsme definovali funkci a v závorce jsme uvedli vstupní parametr (v našem případě formulaci otázky), který očekáváme. Proměnnou valid jsme si naplnili datovou strukturou key/value (přiřazení klíče a hodnoty je dvojtečka). Smyslem je, abychom nemuseli složitě dělat mraky „if“ příkazů pro každou možnost, kterou „bereme“ – místo toho se později v programu stačí zeptat, jestli odpověď uživatele je v tomto seznamu klíčů (příkaz if choice in valid). No a protože každá odpověď znamená něco jiného (některé říkají ano, jiné ne), tak bychom i tak museli mít složitou „if“ sekvenci a vracet podle toho hodnotu. Místo toho my jednoduše ukážeme na datovou strukturu key/value a řekneme: vrať hodnotu klíče, který se jmenuje choice. Vyhodnocování jsme uzavřeli do bloku While, z kterého je jediný únik a to je příkaz return, kterým říkáme, že celá naše funkce končí a vrací hodnotu. Poslední co ještě zmíním je to, že u raw_input() jsme ještě přidali lower() – je nám jedno jak velká písmena uživatel použije a nechce se nám vytvářet všechny možnosti, proto konvertujeme na malá. Úplně poslední výbava, kterou budeme potřebovat pro práci s Python v Comware budou slovníky a jejich procházení. Slovník může být poměrně složitá struktura, ale v našem případě nám bude stačit jednoduchý seznam/pole (říkejte tomu, jak chcete). Dejme si příklad. >>> zvirata = ['pes', 'kocka', 'slon', 'mravenec'] >>> print zvirata[0] pes >>> print zvirata[1] kocka >>> for zvire in zvirata: ... print zvire + ' je zvire' ...
5|HP skriptování v Comware
pes je zvire kocka je zvire slon je zvire mravenec je zvire >>>
Tak to bychom měli – a jak to teď souvisí s Comware? V aktuální verzi je možné do Python prostředí importovat knihovnu Comware, která potenciálně může mít různé funkce. V tuto chvíli jsou to knihovny pro zálohování konfigurací a transfer souborů a pak také jedna, kterou budeme používat – CLI, tedy vyvolání příkazu a stažení jeho výsledků. Do budoucna lze předpokládat, že se okruh „zabudovaných“ funkcí v knihovně bude rozšiřovat, ale my si ukážeme, že i s jednoduchým pohráváním s CLI lze udělat zajímavé skripty. >>> import comware >>> comware.CLI('display interface brief') <Switch1>display interface brief Brief information on interface(s) under route mode: Link: ADM - administratively down; Stby - standby Protocol: (s) - spoofing Interface Link Protocol Main IP Description InLoop0 UP UP(s) -M-E1/0/1 UP UP 172.16.1.2 NULL0 UP UP(s) -REG0 DOWN --Brief information on interface(s) under bridge mode: Link: ADM - administratively down; Stby - standby Speed or Duplex: (a)/A - auto; H - half; F - full Type: A - access; T - trunk; H - hybrid Interface Link Speed Duplex Type PVID Description GE1/0/2 UP 1G(a) F(a) A 1 GE1/0/3 ADM auto A A 1 GE1/0/4 ADM auto A A 1 GE1/0/5 UP 1G(a) F(a) A 1 GE1/0/6 ADM auto A A 1 GE1/0/7 ADM auto A A 1 GE1/0/8 ADM auto A A 1
>>>
Tak zatím nic složitého – importovali jsme knihovnu Comware a využili ji k vyvolání příkazu, konkrétně k výpisu portů. Pokud na konec příkazu napíšeme False, tak se výpis nebude objevovat na obrazovce. Také to můžeme zachytit do proměnné. >>> result = comware.CLI('display interface brief', False).get_output() >>> print result ['<Switch1>display interface brief', 'Brief information on interface(s) under route mode:', 'Link: ADM - administratively down; Stby - standby', 'Protocol: (s) - spoofing', 'Interface Link Protocol Main IP Description ', 'InLoop0 UP UP(s) -', 'M-E1/0/1 UP UP 172.16.1.2 ', 'NULL0
6|HP skriptování v Comware
UP UP(s) -', 'REG0 DOWN --', '', 'Brief information on interface(s) under bridge mode:', 'Link: ADM administratively down; Stby - standby', 'Speed or Duplex: (a)/A - auto; H half; F - full', 'Type: A - access; T - trunk; H - hybrid', 'Interface Link Speed Duplex Type PVID Description ', 'GE1/0/2 UP 1G(a) F(a) A 1 ', 'GE1/0/3 ADM auto A A 1 ', 'GE1/0/4 ADM auto A A 1 ', 'GE1/0/5 UP 1G(a) F(a) A 1 ', 'GE1/0/6 ADM auto A A 1 ', 'GE1/0/7 ADM auto A A 1 ', 'GE1/0/8 ADM auto A A 1 ', ''] >>>
Zdá se vám výpis result teď nějaký podivný? To je tím, že je to objekt, ale o to lépe se nám s ním bude pracovat. Zkuste třeba toto: >>> print result[2] Link: ADM - administratively down; Stby - standby >>> print result[3] Protocol: (s) - spoofing >>> for line in result: ... print line ... <Switch1>display interface brief Brief information on interface(s) under route mode: Link: ADM - administratively down; Stby - standby Protocol: (s) - spoofing Interface Link Protocol Main IP Description InLoop0 UP UP(s) -M-E1/0/1 UP UP 172.16.1.2 NULL0 UP UP(s) -REG0 DOWN --Brief information on interface(s) under bridge mode: Link: ADM - administratively down; Stby - standby Speed or Duplex: (a)/A - auto; H - half; F - full Type: A - access; T - trunk; H - hybrid Interface Link Speed Duplex Type PVID Description GE1/0/2 UP 1G(a) F(a) A 1 GE1/0/3 ADM auto A A 1 GE1/0/4 ADM auto A A 1 GE1/0/5 UP 1G(a) F(a) A 1 GE1/0/6 ADM auto A A 1 GE1/0/7 ADM auto A A 1 GE1/0/8 ADM auto A A 1 >>>
Můžeme si vypsat jen rozhraní, která jsou nahoře. >>> for line in result: ... if 'UP' in line: print line ... InLoop0 UP UP(s) --
7|HP skriptování v Comware
M-E1/0/1 NULL0 GE1/0/2 GE1/0/5 >>>
UP UP UP UP
UP UP(s) 1G(a) 1G(a)
172.16.1.2 -F(a) A 1 F(a) A 1
A nebo to parsovat a mít text jinak. Pro práci s řetězci použijeme funkci rsplit, která nám řádek rozdělí do seznamu/pole jednotlivých elementů tak jak je parsuje z řádky na základě mezerníku jako oddělovače (což lze změnit na jiný znak, pokud je potřeba). No a první element bude právě název interface, takže se na něj odkážeme (hranatá závorka 0 = první element). >>> for line in result: ... if 'UP' in line: print line.rsplit()[0] + ' je nahore!' ... InLoop0 je nahore! M-E1/0/1 je nahore! NULL0 je nahore! GE1/0/2 je nahore! GE1/0/5 je nahore! >>>
… a to už nám v tom lavíruje jen formátování. Použijeme funkci print s formátováním. Říkáme, že první proměnou vložíme a bude mít maximálně i minimálně 15 znaků, pak bude mezera, a pak druhá proměnná. To nám umožňuje formátovat tabulku. >>> for line in result: ... if 'UP' in line: print('{0:15.15} {1:15.15}'.format(line.rsplit()[0], 'nahore')) ... InLoop0 nahore M-E1/0/1 nahore NULL0 nahore GE1/0/2 nahore GE1/0/5 nahore >>>
Je dobré si také uvědomit, že „comware.CLI“ začíná vždy svou cestu v user kontextu. Pokud potřebujeme doskákat jinam, tak to musí být součást jednoho volání, kde jednotlivé příkazy oddělíme středníkem – pozor, za příkazem nesmí následovat středník bezprostředně, musí tam být alespoň jedna mezera! Udělejme si funkci na vypínání portu. >>> def vypnout(port): ... comware.CLI('system-view ; interface ' + port + ' ; shut') ... >>>
Vypišme si porty – zdá se, že GE1/0/5 je UP. >>> comware.CLI('display interface brief') <Switch1>display interface brief Brief information on interface(s) under route mode: Link: ADM - administratively down; Stby - standby
8|HP skriptování v Comware
Protocol: (s) - spoofing Interface Link InLoop0 UP M-E1/0/1 UP NULL0 UP REG0 DOWN
Protocol UP(s) UP UP(s) --
Main IP -172.16.1.2 ---
Description
Brief information on interface(s) under bridge mode: Link: ADM - administratively down; Stby - standby Speed or Duplex: (a)/A - auto; H - half; F - full Type: A - access; T - trunk; H - hybrid Interface Link Speed Duplex Type PVID Description GE1/0/2 UP 1G(a) F(a) A 1 GE1/0/3 ADM auto A A 1 GE1/0/4 ADM auto A A 1 GE1/0/5 UP 1G(a) F(a) A 1 GE1/0/6 ADM auto A A 1 GE1/0/7 ADM auto A A 1 GE1/0/8 ADM auto A A 1 >>>
Zkusme naší novou funkci. >>> vypnout('g1/0/5') <Switch1>system-view System View: return to User View with Ctrl+Z. [Switch1]interface g1/0/5 [Switch1-GigabitEthernet1/0/5]shut >>>
Tak to by bylo … ověřme to >>> comware.CLI('display interface brief') <Switch1>display interface brief Brief information on interface(s) under route mode: Link: ADM - administratively down; Stby - standby Protocol: (s) - spoofing Interface Link Protocol Main IP Description InLoop0 UP UP(s) -M-E1/0/1 UP UP 172.16.1.2 NULL0 UP UP(s) -REG0 DOWN --Brief information on interface(s) under bridge mode: Link: ADM - administratively down; Stby - standby Speed or Duplex: (a)/A - auto; H - half; F - full Type: A - access; T - trunk; H - hybrid Interface Link Speed Duplex Type PVID Description GE1/0/2 UP 1G(a) F(a) A 1 GE1/0/3 ADM auto A A 1
9|HP skriptování v Comware
GE1/0/4 GE1/0/5 GE1/0/6 GE1/0/7 GE1/0/8
ADM ADM ADM ADM ADM
auto auto auto auto auto
A A A A A
A A A A A
1 1 1 1 1
>>>
V tuto chvíli jsme dobře vybaveni k tomu, abychom začali v Python uvnitř Comware dělat něco užitečného.
Kopírka portů Možná to znáte – pokud konfigurujete nastavení vícero portů současně, použijete range a pracuje nad celou skupinou portů. To ovšem už musíte vědět, čeho vlastně chcete dosáhnout. Je běžné, že si nastavení postupně odladíte jen na jednom portu. No a když jste spokojeni, máte nastaveno všechno, co chcete a funguje to (ověřování, sFlow, CDP podpora a tak podobně) tak je potřeba to nastavit i na dalších portech. Co kdybychom si napsali skript, který toto kopírování provede za nás? Mějme tedy tuto konfiguraci na portu: <Switch1>display current-configuration interface g1/0/2 # interface GigabitEthernet1/0/2 port link-mode bridge combo enable fiber lldp compliance admin-status cdp txrx sflow flow collector 1 sflow flow max-header 256 sflow sampling-rate 1000 sflow counter collector 1 port-security port-mode userlogin-secure # return <Switch1>
Nejprve si v živém Python vyzkoušíme pár věcí a syntaxí a následně z toho uděláme skript. Budeme potřebovat vzít konfiguraci portu a udělat z ní sekvenci příkazů, kterou použijeme na jiném portu. Spusťte si živý Python a budeme zkoušet. >>> import comware >>> result = comware.CLI('display current-configuration interface g1/0/2',False).get_output() >>> for line in result: ... print line ... <Switch1>display current-configuration interface g1/0/2 # interface GigabitEthernet1/0/2 port link-mode bridge combo enable fiber lldp compliance admin-status cdp txrx
10 | H P s k r i p t o v á n í v C o m w a r e
sflow flow collector 1 sflow flow max-header 256 sflow sampling-rate 1000 sflow counter collector 1 port-security port-mode userlogin-secure # return >>>
Pojďme si tento výpis očistit tak, abychom měli skutečně jen příkazy týkající se portu, které pak spustíme nad nějakým jiným. >>> for line in result: ... if '#' not in line: ... if 'interface' not in line: print line ... port link-mode bridge combo enable fiber lldp compliance admin-status cdp txrx sflow flow collector 1 sflow flow max-header 256 sflow sampling-rate 1000 sflow counter collector 1 port-security port-mode userlogin-secure return >>>
Takhle je to správně – místo výpisu si to uložíme do nového slovníku. >>> script = [] >>> for line in result: ... if '#' not in line: ... if 'interface' not in line: script.append(line) ... >>> >>> print script [' port link-mode bridge', ' combo enable fiber', ' lldp compliance adminstatus cdp txrx', ' sflow flow collector 1', ' sflow flow max-header 256', ' sflow sampling-rate 1000', ' sflow counter collector 1', ' port-security port-mode userlogin-secure', 'return'] >>>
Pojďme teď tuto sekvenci vyvolat nad jiným portem. Jak už jsme se naučili dříve, začíná každé CLI volání v kontextu user a přes středníky vytváříme celou sekvenci. Abychom měli jistotu, že nastavení cílového portu není v nějakém konfliktu, vrátíme ho do výchozího stavu příkazem default a pak na něj nasypeme naší sekvenci. >>> command = 'system-view ; interface g1/0/5 ; default ;' >>> for line in script: ... command = command + line + ' ;' ... >>> comware.CLI(command)
11 | H P s k r i p t o v á n í v C o m w a r e
<Switch1>system-view System View: return to User View with Ctrl+Z. [Switch1]interface g1/0/5 [Switch1-GigabitEthernet1/0/5]default This command will restore the default settings. Continue? [Y/N]: [Switch1-GigabitEthernet1/0/5]port link-mode bridge [Switch1-GigabitEthernet1/0/5]combo enable fiber [Switch1-GigabitEthernet1/0/5]lldp compliance admin-status cdp txrx [Switch1-GigabitEthernet1/0/5]sflow flow collector 1 [Switch1-GigabitEthernet1/0/5]sflow flow max-header 256 [Switch1-GigabitEthernet1/0/5]sflow sampling-rate 1000 [Switch1-GigabitEthernet1/0/5]sflow counter collector 1 [Switch1-GigabitEthernet1/0/5]port-security port-mode userlogin-secure [Switch1-GigabitEthernet1/0/5]return >>>
Teď můžeme z Python vyskočit příkazem quit() a ověřit, že se vše povedlo. <Switch1>dis curr interface g1/0/2 # interface GigabitEthernet1/0/2 port link-mode bridge combo enable fiber lldp compliance admin-status cdp txrx sflow flow collector 1 sflow flow max-header 256 sflow sampling-rate 1000 sflow counter collector 1 port-security port-mode userlogin-secure # return <Switch1>dis curr interface g1/0/5 # interface GigabitEthernet1/0/5 port link-mode bridge combo enable fiber shutdown lldp compliance admin-status cdp txrx sflow flow collector 1 sflow flow max-header 256 sflow sampling-rate 1000 sflow counter collector 1 port-security port-mode userlogin-secure # return <Switch1>
Zdá se tedy, že jsme připraveni. Na počítači otevřete textový editor a z toho všeho uděláme spustitelný Python skript. K tomu budeme definovat funkci main (tělo aplikace) a na konci souboru řekneme, že je to hlavní tělo pro spouštění jako skript. Ještě budeme chtít brát vstupní argumenty – tedy z kterého na který port chceme kopírování provádět. Naimportujeme si knihovnu sys a getopt. 12 | H P s k r i p t o v á n í v C o m w a r e
Pokud skript dostane žádný nebo jen jeden argument tak se ukončí a napíše, jak si představuje, že bude používán. Pokud je argumentů dost, budeme je parsovat a zkoumat, jestli obsahuje přípínač -s nebo --source jako zdrojový port a -d nebo --destination jako cílový port. Pokud ano, tak si obsah uložíme do proměnné. No a pak už ve skriptu není nic zásadně nového, všechno už jsme si vyzkoušeli na živém Python. Takhle vypadá výsledek: import comware, sys, getopt def main(argv): sourceport = '' destinationport = '' if len(sys.argv) < 2: print 'portcopy.py -s <sourceport> -d <destinationport>' sys.exit() try: opts, args = getopt.getopt(argv,"hs:d:",["source=","destination="]) except getopt.GetoptError: print 'portcopy.py -s <sourceport> -d <destinationport>' sys.exit(2) for opt, arg in opts: if opt == '-h': print 'portcopy.py -s <sourceport> -d <destinationport>' sys.exit() elif opt in ("-s", "--source"): sourceport = arg elif opt in ("-d", "--destination"): destinationport = arg print 'Copying ' + sourceport + ' config to ' + destinationport result = comware.CLI('display current-configuration interface ' + sourceport, False) script = [] for line in result.get_output(): if '#' not in line: if 'interface' not in line: script.append(line) command = 'system-view ; interface ' + destinationport + ' ; default ;' for line in script: command = command + line + ' ;' comware.CLI(command) if __name__ == "__main__": main(sys.argv[1:])
Dejte souboru příponu py (já použil soubor portcopy.py) a nakopírujte do switche (TFTP, FTP, SCP, SFTP – dle vaší volby). To je všechno, můžeme vyzkoušet. <Switch1>python portcopy.py -s g1/0/2 -d g1/0/5 Copying g1/0/2 config to g1/0/5 <Switch1>system-view System View: return to User View with Ctrl+Z. [Switch1]interface g1/0/5 [Switch1-GigabitEthernet1/0/5]default This command will restore the default settings. Continue? [Y/N]:
13 | H P s k r i p t o v á n í v C o m w a r e
[Switch1-GigabitEthernet1/0/5]port link-mode bridge [Switch1-GigabitEthernet1/0/5]combo enable fiber [Switch1-GigabitEthernet1/0/5]lldp compliance admin-status cdp txrx [Switch1-GigabitEthernet1/0/5]sflow flow collector 1 [Switch1-GigabitEthernet1/0/5]sflow flow max-header 256 [Switch1-GigabitEthernet1/0/5]sflow sampling-rate 1000 [Switch1-GigabitEthernet1/0/5]sflow counter collector 1 [Switch1-GigabitEthernet1/0/5]port-security port-mode userlogin-secure [Switch1-GigabitEthernet1/0/5]return <Switch1>
A je to – máme vytvořen první Python skript spustitelný přímo uvnitř Comware. Pokud chcete rozvíjet dál, tady je pár nápadů, kam můžete svoje snahy směřovat: Kopírování na více cílových portů Řešení situace, kdy je v argumentu mezera (např. g 1/0/5), což parser nepozná, pokud tam nejsou uvozovky (zkuste vymyslet jak na to, třeba chytrou nápovědou uživateli) Potvrzení nakopírování, například zobrazte konfiguraci nového portu a zeptejte se, zda si uživatel opravdu přeje ji přepsat konfigurací ze zdrojového
Automatické pojmenování portů na základě LLDP Pro rychlou orientaci v síti je obvyklé dobré pojmenovat si (description) důležité fyzické porty sítě. To je výhodné jak pro samotnou práci v CLI, tak pro pohled z iMC, které description reflektuje. Pokud máte v zařízeních nastavena systémová jména a je zapnutý LLDP protocol, tak bychom mohli pojmenování uplinků udělat Python skriptem ve formátu “to_sysname”. Zkusíme to? Nejprve se podívejme, jak takový výpis vypadá a co z něj budeme potřebovat: [Switch1]dis lldp nei v LLDP neighbor-information of port 3[GigabitEthernet1/0/2]: LLDP agent nearest-bridge: LLDP neighbor index : 1 Update time : 0 days, 0 hours, 5 minutes, 26 seconds Chassis type : MAC address Chassis ID : 00e0-0200-0000 Port ID type : Interface name Port ID : GigabitEthernet1/0/2 Time to live : 121 Port description : GigabitEthernet1/0/2 Interface System name : Switch2 System description : HP Comware Software, Software Version 7.1.050, Alpha 7150 HP Simware7 Copyright (c) 2010-2014 Hewlett-Packard Development Compa ny, L.P. System capabilities supported : Bridge, Router, Customer Bridge, Service Bridge System capabilities enabled : Bridge, Router, Customer Bridge Management address type : All802 Management address : 00e0-0200-0000 Management address interface type : IfIndex Management address interface ID : Unknown
14 | H P s k r i p t o v á n í v C o m w a r e
Management address OID Port VLAN ID(PVID) : 1 Link aggregation supported Link aggregation enabled Aggregation port ID Auto-negotiation supported Auto-negotiation enabled OperMau Power port class PSE power supported PSE power enabled PSE pairs control ability Power pairs Port power classification Maximum frame size
: 0 : : : : : : : : : : : : :
Yes No 0 No No Speed(0)/Duplex(Unknown) PSE No No No Signal Class 0 9216
Otevřeme si živý Python a budem trochu zkoušet. Nejdřív si zkusíme vypsat jen ty řádky, kde je informace o našich portech. >>> import comware >>> result = comware.CLI('display lldp neighbor-information verbose', False).get_output() >>> for line in result: ... if 'LLDP neighbor-information of port' in line: print line ... LLDP neighbor-information of port 3[GigabitEthernet1/0/2]: LLDP neighbor-information of port 6[GigabitEthernet1/0/5]: >>>
A takhle bychom se dostali k řádkům, kde je systémové jméno souseda: >>> for ... ... System System >>>
line in result: if 'System name' in line: print line name name
: Switch2 : Switch3
Stačí nám tedy vymyslet, jak tyto informace parsovat. Co se týče názvu portu – jakmile máme vhodný řádek (to už najít umíme) tak nás zajíma text, který je uzavřený v hranatých závorkách. Zajímá nás tedy jen ta část celé řádky, která začína na pozici znaku ‘[‘ a končí na pozici znaku ‘]’. To uděláme takto: >>> for line in result: ... if 'LLDP neighbor-information of port' in line: ... start = line.rindex('[') + 1 ... end = line.rindex(']', start) ... print line[start:end] ... GigabitEthernet1/0/2 GigabitEthernet1/0/5 >>>
15 | H P s k r i p t o v á n í v C o m w a r e
Nádhera. A teď totéž pro systémové jméno. Tam jak vidno hledáme text, který následuje po dvojtečce, ale za to je ještě jedna mezera. Pak na zajímá vše do konce řádky. To uděláme takto: >>> for line in result: ... if 'System name' in line: ... start = line.rindex(':') + 2 ... end = len(line) ... print line[start:end] ... Switch2 Switch3 >>>
Protože ve výpisu vždy začínáme portem a pokračujeme systémovým jménem soused požijeme proměnné a vypíšeme obě informace najednou (a to je základem pro náš budoucí skript). >>> port = '' >>> name = '' >>> for line in result: ... if 'LLDP neighbor-information of port' in line: ... start = line.rindex('[') + 1 ... end = line.rindex(']', start) ... port = line[start:end] ... if 'System name' in line: ... start = line.rindex(':') + 2 ... end = len(line) ... name = line[start:end] ... print 'Na portu ' + port + ' je ' + name ... Na portu GigabitEthernet1/0/2 je Switch2 Na portu GigabitEthernet1/0/5 je Switch3 >>>
Pak už stačí v rámci cyklu místo tisku posílat příkazy: comware.CLI('system-view ; interface ' + port + ' ; description ' + name +' ; return ; ', False)
Teď už známe vše potřebné k vytvoření skriptu. Otevřete na počítači textový editor, vytvořte soubor portnames.py a vložte do něj následující: import comware def main(): print 'Will set port descriptions to LLDP connected devices to to_sysname' result = comware.CLI('display lldp neighbor-information verbose', False).get_output() port = '' name = '' for line in result:
16 | H P s k r i p t o v á n í v C o m w a r e
if 'LLDP neighbor-information of port' in line: start = line.rindex('[') + 1 end = line.rindex(']', start) port = line[start:end] if 'System name' in line: start = line.rindex(':') + 2 end = len(line) name = 'to_' + line[start:end] print 'Setting ' + port + ' description to ' + name comware.CLI('system-view ; interface ' + port + ' ; description ' + name +' ; return ; ', False) if __name__ == "__main__": main()
Nakopírujte do zařízení a můžeme vyzkoušet. Vyskočte z živého Python do user úrovně a vypište si aktuální porty. <Switch1>dis interface brief Brief information on interface(s) under route mode: Link: ADM - administratively down; Stby - standby Protocol: (s) - spoofing Interface Link Protocol Main IP Description InLoop0 UP UP(s) -M-E1/0/1 UP UP 172.16.1.2 NULL0 UP UP(s) -REG0 DOWN --Brief information on interface(s) under bridge mode: Link: ADM - administratively down; Stby - standby Speed or Duplex: (a)/A - auto; H - half; F - full Type: A - access; T - trunk; H - hybrid Interface Link Speed Duplex Type PVID Description GE1/0/2 UP 1G(a) F(a) A 1 GE1/0/3 ADM auto A A 1 GE1/0/4 ADM auto A A 1 GE1/0/5 UP 1G(a) F(a) A 1 GE1/0/6 ADM auto A A 1 GE1/0/7 ADM auto A A 1 GE1/0/8 ADM auto A A 1 <Switch1>
Jak vidno, nikde žádná description není. Spustíme tedy náš skript a zkusíme to znovu. <Switch1>python portnames.py Will set port descriptions to LLDP connected devices to to_sysname Setting GigabitEthernet1/0/2 description to to_Switch2 Setting GigabitEthernet1/0/5 description to to_Switch3 <Switch1>dis interface brief Brief information on interface(s) under route mode: Link: ADM - administratively down; Stby - standby
17 | H P s k r i p t o v á n í v C o m w a r e
Protocol: (s) - spoofing Interface Link InLoop0 UP M-E1/0/1 UP NULL0 UP REG0 DOWN
Protocol UP(s) UP UP(s) --
Main IP -172.16.1.2 ---
Description
Brief information on interface(s) under bridge mode: Link: ADM - administratively down; Stby - standby Speed or Duplex: (a)/A - auto; H - half; F - full Type: A - access; T - trunk; H - hybrid Interface Link Speed Duplex Type PVID Description GE1/0/2 UP 1G(a) F(a) A 1 to_Switch2 GE1/0/3 ADM auto A A 1 GE1/0/4 ADM auto A A 1 GE1/0/5 UP 1G(a) F(a) A 1 to_Switch3 GE1/0/6 ADM auto A A 1 GE1/0/7 ADM auto A A 1 GE1/0/8 ADM auto A A 1 <Switch1>
A tím je náš druhý skript na světě. Pokud se bude zamýšlet, jak by se to dalo dál vylepšovat, takdy je pár nápadů: Kontrolujte, zda port už nějakou description nemá, pokud ano upozorněte na to Využite informace z LLDP pro ještě chytřejší názvy portů pokud se detekuje třeba bezdrátový bod (description AP-sysname)
Generování náhodných routes V první řadě chci upozornit, že následující skript rozhodně není určený na testování kapacit směrovacích tabulek v Comware a to hned ze dvou důvodů. Za prvé je počet záznamů definovaných staticky v Comware omezený, takže na plnou kapacitu se stejnak staticky nedostanete (potřeba definovat 1M statických cest je čiré šílenství). Druhá potíž je, že naznačený způsob je extrémně neefektivní co do rychlosti přidávání záznamů a spotřeby systémových zdrojů, protože každá cesta se zadavá samostatně a spouští mnoho věcí (interpret, zařazení do RIB, zkoumání, zda lze patří i do FIB apod.). Chcete-li testovat rychlost instalace záznamů do RIB/FIB a jejich kapacity použijte běžné techniky vstřikování přes směrovací protokol (třeba ze Spirent). Pokud ale pro vaše testování nebo školení směrovacích protokolů potřebujete vytvořit pár stovek náhodně generovaných cest je použití zabudovaného Python docela dobrá volba. Spusťte si živý Python v prvku a nejprve zkusíme trochu experimentovat. >>> import comware,random >>> random.randrange(1,254,1) 169 >>> random.randrange(1,254,1) 93 >>>
18 | H P s k r i p t o v á n í v C o m w a r e
Takhle si tedy generujeme náhodné číslo v zadaném rozsahu. Pojďme z toho udělat IP adresu tak, že první element bude 10 a další tři budou náhodné. Nezapomínejme take, že jde o čísla, ale IP adresu budeme chtít jako řetězec. >>> n1 = str(10) >>> n2 = str(random.randrange(1,254,1)) >>> n3 = str(random.randrange(1,254,1)) >>> n4 = str(random.randrange(1,254,1)) >>> ip = n1 + '.' + n2 + '.' + n3 + '.' + n4 >>> print ip 10.101.78.48 >>>
To bychom měli – tuto adresu bude vkládat do příkazu na definici statické cesty. Aby se nám to dobře dělalo, použijeme funkci „format“ a do řetězce si na správná místa vložíme IP adresu a také odchozí bránu (pro testování použiji NULL0). >>> gateway = 'NULL0' >>> routestatic = 'ip route-static {0} 32 {1}' >>> print routestatic.format(ip, gateway) ip route-static 10.101.78.48 32 NULL0 >>>
Takových příkazů si už můžeme pár vygenerovat, třeba 10. >>> for i in range(10): ... n1 = str(10) ... n2 = str(random.randrange(1,254,1)) ... n3 = str(random.randrange(1,254,1)) ... n4 = str(random.randrange(1,254,1)) ... ip = n1 + '.' + n2 + '.' + n3 + '.' + n4 ... print routestatic.format(ip, gateway) ... ip route-static 10.116.132.247 32 NULL0 ip route-static 10.30.79.63 32 NULL0 ip route-static 10.56.74.122 32 NULL0 ip route-static 10.59.108.72 32 NULL0 ip route-static 10.242.109.90 32 NULL0 ip route-static 10.157.128.152 32 NULL0 ip route-static 10.243.62.185 32 NULL0 ip route-static 10.104.242.13 32 NULL0 ip route-static 10.142.227.59 32 NULL0 ip route-static 10.126.195.160 32 NULL0 >>>
Následně z toho uděláme příkazy v CLI. >>> command = 'system-view ; ' >>> for i in range(10): ... n1 = str(10)
19 | H P s k r i p t o v á n í v C o m w a r e
... n2 = str(random.randrange(1,254,1)) ... n3 = str(random.randrange(1,254,1)) ... n4 = str(random.randrange(1,254,1)) ... ip = n1 + '.' + n2 + '.' + n3 + '.' + n4 ... command = command + routestatic.format(ip, gateway) + ' ; ' ... >>> <Switch1>system-view System View: return to User View with Ctrl+Z. [Switch1]ip route-static 10.203.184.98 32 NULL0 [Switch1]ip route-static 10.210.228.162 32 NULL0 [Switch1]ip route-static 10.36.80.130 32 NULL0 [Switch1]ip route-static 10.104.138.203 32 NULL0 [Switch1]ip route-static 10.99.102.246 32 NULL0 [Switch1]ip route-static 10.119.71.91 32 NULL0 [Switch1]ip route-static 10.127.182.88 32 NULL0 [Switch1]ip route-static 10.65.58.209 32 NULL0 [Switch1]ip route-static 10.95.227.31 32 NULL0 [Switch1]ip route-static 10.216.125.213 32 NULL0 >>>
Můžeme vyskočit z živě Python quit() a zkontrolovat výsledek. <Switch1>display ip routing-table Destinations : 23 Destination/Mask 0.0.0.0/32 10.0.0.1/32 10.36.80.130/32 10.65.58.209/32 10.95.227.31/32 10.99.102.246/32 10.104.138.203/32 10.119.71.91/32 10.127.182.88/32 10.203.184.98/32 10.210.228.162/32 10.216.125.213/32
Routes : 23 Proto Direct Direct Static Static Static Static Static Static Static Static Static Static
Pre 0 0 60 60 60 60 60 60 60 60 60 60
Cost 0 0 0 0 0 0 0 0 0 0 0 0
NextHop 127.0.0.1 127.0.0.1 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0
Interface InLoop0 InLoop0 NULL0 NULL0 NULL0 NULL0 NULL0 NULL0 NULL0 NULL0 NULL0 NULL0
Výborně, jsou tam. Teď už nám zbývá jen z toho udělat skript, kde jako vstupní argument zadáme počet záznamů ke generování a gateway. Vytvořte nový soubor v počítači (routegen.py) s tímto obsahem. import comware, sys, getopt, random def main(argv): count = 0 gateway = 'NULL0'
20 | H P s k r i p t o v á n í v C o m w a r e
if len(sys.argv) < 2: print 'routegen.py -c -g ' sys.exit() try: opts, args = getopt.getopt(argv,"hc:g:",["count=","gateway="]) except getopt.GetoptError: print 'routegen.py -c -g ' sys.exit(2) for opt, arg in opts: if opt == '-h': print 'routegen.py -c -g ' sys.exit() elif opt in ("-c", "--count"): try: count = int(arg) except ValueError: print 'Count needs to be a number' sys.exit() elif opt in ("-g", "--gateway"): gateway = arg routestatic = 'ip route-static {0} 32 NULL0' command = 'system-view ; ' print 'Generating routes' for i in range(count): n1 = str(10) n2 = str(random.randrange(1, 254, 1)) n3 = str(random.randrange(1, 254, 1)) n4 = str(random.randrange(1, 254, 1)) ip = n1 + '.' + n2 + '.' + n3 + '.' + n4 command = command + routestatic.format(ip) + ' ; ' print 'Installing routes' comware.CLI(command, False) if __name__ == "__main__": main(sys.argv[1:])
Přišel čas náš skript otestovat. Nejprve si vypíšeme statistiku směrovací tabulky. <Switch1>display ip routing-table statistics Proto DIRECT STATIC RIP OSPF IS-IS BGP Total <Switch1>
route 13 0 0 0 0 0 13
active 13 0 0 0 0 0 13
added 13 0 0 0 0 0 13
deleted 0 0 0 0 0 0 0
21 | H P s k r i p t o v á n í v C o m w a r e
Vygenerujeme 200 záznamů naším skriptem a prozkoumáme výsledek. <Switch1>python routegen.py -c 200 -g NULL0 Generating routes Installing routes <Switch1>display ip routing-table statistics Proto DIRECT STATIC RIP OSPF IS-IS BGP Total <Switch1>
route 13 200 0 0 0 0 213
active 13 200 0 0 0 0 213
added 13 200 0 0 0 0 213
deleted 0 0 0 0 0 0 0
Trénujete kolegy nebo zákazníky na základy směrovacích protokolů? K zamyšlení může být rozšíření těchto možností o další situace. Interní skriptování vám umožní automatizovaně vytvářet testovací prostředí a efektivně se učit (místo přebouchávání složitých konfigurací).
Zálohování konfigurace na FTP server Možná vám bude připadat, že vytvářet Python skript jen na zálohování konfigurace nepřináší žádnou hodnotu. Máte pravdu, lze to jedním příkazem udělat z běžného CLI. Nicméně nám se skript bude hodit v dalších částech tohoto dokumentu – lze jej totiž spustit v reakci na nějakou událost nebo naplánovat pravidelné spouštění. A to už je skript potřeba například kvůli tomu, aby automaticky generoval název souboru. Začněme opět v živém Python a vyzkoušíme si pár věcí před tím, než vytvoříme vlastní skript. Importujeme knihovnu pro práci s časem a otestujeme ji. >>> import datetime >>> datetime.datetime.now() datetime.datetime(2014, 4, 10, 16, 24, 6, 519745) >>> datetime.datetime.now().year 2014 >>> datetime.datetime.now().month 4
Do názvu souboru budeme chtít vložit časové razítko s přesností na minuty, abychom odlišili jednotlivé zálohy mezi sebou. Now() je možné spřáhnout s formátováním a určit si přesně jak chceme, aby výsledek vypadal. >>> datetime.datetime.now().strftime("%Y") '2014' >>> datetime.datetime.now().strftime("%y") '14' >>> datetime.datetime.now().strftime("%d") '10' >>> datetime.datetime.now().strftime("%d. %m. %Y") '10. 04. 2014' >>>
Jako razítko do názvu souboru pro nás bude ideální tohle: 22 | H P s k r i p t o v á n í v C o m w a r e
>>> datetime.datetime.now().strftime("%y%m%d%H%M") '1404101629' >>>
Pokud budeme zálohu posílat na FTP server a uděláme to z vícero zařízení musíme soubory rozeznat – vložíme do něj tedy systémové jméno. To získáme takto: >>> socket.gethostname() 'Switch1' >>>
Podobně lze získat i jméno uživatele – to si vyzkoušíme, ale v názvu souboru nebudeme používat pro případ, že jej voláme automatizovaně (v ten okamžik není uživatel přihláše a končí to chybou). Nicméně pokud chceme volat skript sami z příkazové řádky příkazem python filename.py, tak by to šlo. >>> import os >>> os.environ.get('LOGNAME') 'test' >>>
Vyzkoušejme si tedy sestavit název souboru a pod tímto uložit konfiguraci. >>> timestamp = datetime.datetime.now().strftime("%y%m%d%H%M") >>> sysname = socket.gethostname() >>> filename = sysname + '_' + timestamp + '.cfg' >>> print filename Switch1_1404101632.cfg >>> comware.CLI('save ' + filename)
Připravme si ještě URL FTP serveru a můžeme provést zálohu. >>> username = 'ftpuser' >>> password = 'ftppassword' >>> ip = '172.16.1.3' >>> path = 'ftp://' + username + ':' + password + '@' + ip + '/' >>> print path ftp://ftpuser:[email protected]/ >>> comware.CLI('copy ' + filename + ' ' + path)
Tak a teď už to vlastně jen dáme všechno dohromady. Přidáme vstupní argumenty (-s pro IP FTP serveru, -u a –p pro jméno a heslo a volitelné –d pro smazání souboru z flash po přenesení na FTP). Pokud ovšem žádný parametr neobjevíme, nebudeme zálohovat na FTP a jednoduše provedeme lokální zálohu na flash. V počítači vytvořte soubor cfgsave.py s tímto obsahem: import comware, sys, getopt, os, datetime, socket def main(argv): ip = '' username = '' password = '' delete = False try: opts, args = getopt.getopt(argv,"hds:p:u:",["server=","username=","password="])
23 | H P s k r i p t o v á n í v C o m w a r e
except getopt.GetoptError: print 'usage ftpsave.py -s <serverIP> -u -p -d (to delete file after transfer)' sys.exit(2) for opt, arg in opts: if opt == '-h': print 'usage ftpsave.py -s <serverIP> -u -p -d (to delete file after transfer)' sys.exit() elif opt in ("-s", "--server"): ip = arg elif opt in ("-u", "--username"): username = arg elif opt in ("-p", "--password"): password = arg elif opt in ("-d", "--delete"): delete = True timestamp = datetime.datetime.now().strftime("%y%m%d%H%M") sysname = socket.gethostname() filename = sysname + '_' + timestamp + '.cfg' filenamemdb = sysname + '_' + timestamp + '.mdb' comware.CLI('save ' + filename) if ip != '': path = 'ftp://' + username + ':' + password + '@' + ip + '/' comware.CLI('copy ' + filename + ' ' + path) if delete: comware.CLI('delete ' + filename) comware.CLI('delete ' + filenamemdb) if __name__ == "__main__": main(sys.argv[1:])
Nakopírujte do prvku a vyzkoušíme – spusťe skript (bez argumentů pokud nemáte připraven FTP server, s argumenty pokud ano) a vypište si obsah flash. Konfigurace by tam měla být. <Switch1>python cfgsave.py <Switch1>save Switch1_1404101640.cfg The current configuration will be saved to flash:/Switch1_1404101640.cfg. Continue? [Y/N]: Now saving current configuration to the device. Saving configuration flash:/Switch1_1404101640.cfg.Please wait... Configuration is saved to device successfully. <Switch1>dir Directory of flash: 0 -rw12644 Apr 10 2014 16:40:30 Switch1_1404101640.cfg 1 -rw199452 Apr 10 2014 16:40:30 Switch1_1404101640.mdb
Nic moc? Užitečnější to bude, až naplánujeme iniciování zálohy z prvky na konkrétní časy či intervaly nebo budeme reagovat na jiné události v systému spuštěním tohoto skriptu. Chcete skript rozvíjet dál? Zkuste přidat přepínač, kterým určíte další zálohovací metody (SCP, SFTP). 24 | H P s k r i p t o v á n í v C o m w a r e
Embedded Automation Architecture (EAA) V předchozí části jsme si ukázali, jak je možné využít zabudovaný Python v Comware 7 pro skriptování. Výsledný skript jsme pak vyvolali na požádání příkazem. Comware 7 zahrnuje i automatizační engine, který dokáže reagovat na různé události v systému a na základě nich spouštět v zásadě co vás napadne.
Na co lze reagovat Reakci lze spouštět různám způsobem.
CLI monitor Můžete reagovat na dění v příkazové řádce a toto definovat jako regulární výraz (RegEx). Existující v zásadě tři typy spouštění – při zadání příkazu (odklepnutí), při stisknutí tlačítka nápovědy (otazník v rozepsaném příkazu) a stisknutí tlačítka doplnění (tab v rozepsaném příkazu). Dále je možné určit, zda se akce vyvolávají synchronně (tedy exekuce příkazu bude čekat na dokončení reakce) nebo asynchronně (příkaz se vyvolá a v jiném vláknu běží navázané akce). Klíčovým slovem skip je možné exekuci původního příkazu rovnou zastavit a nahradit jinou reakcí.
Syslog Reakce je navázána na objevení se určité zprávy v logu a není nutné reagovat hned při prvním výskytu – lze například spustit reakci až v okamžiku, kdy se hláška objeví 5x během jedné minuty.
SNMP notifikace Reakce se spustí v okamžiku, kdy systém vygeneruje SNMP zprávu o daném OID.
SNMP hodnota Reakce se spouští v okamžiku, kdy sledovaná SNMP hodnota přesáhne určitou mez definovanou jako start hodnota (například zatížení CPU přesáhne 80%). Pokud následně hodnota zůstává přes 80%, reakce se znova nespouští. Jakmile monitorovaná hodnota klesne pod úroveň definovanou jako reset, spouští se reakce znovu (například CPU klesne zpět pod 50%) a tím se systém vyresetoval (tedy příště se spustí až při zátěži CPU nad 80%).
Process Tento monitor reaguje ne změnu stavu procesu – například start, stop apod. Například je tak možné reagovat na reset BGP procesu.
Hotplug Monitor dostupný u prvků typu chassis, který spuští reakci v okamžiku vložení linkové karty.
Interface Podobně jako u SNMP čítačů je reakce navázána na přešvihnutí hodnoty některého z interface ukazatelů a podruhé v okamžiku, kdy klesne pod jinou hodnotu. Možnosti sledování jsou tyto: input-drops Number of packets dropped from input input-errors Number of errored packets received output-drops Number of packets dropped from output output-errors Number of packets errored on output rcv-bps Interface receive rate in bits/sec rcv-broadcasts Number of broadcast packets received rcv-pps Interface receive rate in pkts/sec tx-bps Interface transmit rate in bits/sec tx-pps Interface transmit rate in pkts/sec
25 | H P s k r i p t o v á n í v C o m w a r e
Jak reakce vypadá Každý monitoring události může jednu a více akcí, které jsou číslované a prováděné v pořadí podle čísel. Jde o spuštění CLI příkazu, vyvolání reboot zařízení nebo karty, switchover na záložní MPU nebo vygenerování vlastní syslog zprávy.
Další konfigurovatelné vlastnosti Zbývá doplnit případné časové omezení reakce (system se bude pokoušet reagovat, ale pokud bude neúspěšný po nějakou dobu, tak reakci vzdá) a user-role (tedy v jaké roli uživatele se bude reakce realizovat, tedy zda například má mít zapistovací práva apod.).
Zápis na FTP server při uložení konfigurace Setkal jsem s požadavkem poslat konfiguraci na FTP server pokaždé, když někdo konfiguraci změní. Na to můžeme využít náš hotový Python skript a navázat ho na nějakou událost v EAA architektuře. Ideální samozřejmě bude událost typu CLI v režimu execute reagující na “save*“. To znamená, že kdykoli bude iniciováno uložení konfigurace, asynchroně s tím bude zavolán náš Python skript a provede současně zálohu na FTP server (s jménem generovaným ve skriptu) a využijeme jeho přepínač –d, aby po této operaci kopii našeho souboru vymazal z flash (nicméně příkaz save normálně proběhne, takže konfigurace je uložena jako normálně). Máte-li python skript už nakopírovaný v zařízení, připravený FTP server (můj je na adrese 172.16.1.3 s username ftp a heslem ftp) tak zadejte tyto příkazy: [Switch1]rtm cli-policy ftp_backup [Switch1-rtm-ftp_backup]event cli async mode execute pattern save* [Switch1-rtm-ftp_backup]action 0 cli python cfgsave.py -s 172.16.1.3 -u ftp –p ftp -d [Switch1-rtm-ftp_backup]user-role network-admin [Switch1-rtm-ftp_backup]commit [Switch1-rtm-ftp_backup]
Při každé změně nastavení je potřeba znovu dát commit. Tím bychom měli mít hotovo, můžeme nastartovat FTP server a vyzkoušet. <Switch1>save The current configuration will be written to the device. Are you sure? [Y/N]:y Please input the file name(*.cfg)[flash:/startup.cfg] (To leave the existing filename unchanged, press the enter key): flash:/startup.cfg exists, overwrite? [Y/N]:y Validating file. Please wait... Saved the current configuration to mainboard device successfully. <Switch1>
Hmm…to vypadá celkem normálně. Přesně tak – skript spouštíme asynchronně, takže běžnou operaci save nám nijak neovlivňuje ani nezpomaluje. Přesto na pozadí proběhlo vše potřebné – podívejte se na váš FTP server (v mém případě je to druhý HP switch se zapnutým FTP serverem, ale v praxi by to byl skutečný server). <Switch2>%Apr 10 17:00:40:408 2014 Switch2 FTP/6/AUTH: -MDC=1; User N/[email protected] for connection. %Apr 10 17:00:40:462 2014 Switch2 FTP/6/AUTH: -MDC=1; User [email protected] login.
26 | H P s k r i p t o v á n í v C o m w a r e
%Apr 10 17:00:40:484 2014 Switch2 FTP/5/OPER: -MDC=1; User [email protected] uploaded flash:/Switch1_1404101656.cfg. %Apr 10 17:00:40:501 2014 Switch2 FTP/6/LOGOUT: -MDC=1; User [email protected] logout. ¨
Všechno tedy funguje, jak jsme chtěli. Chcete rozvíjet skript dál? Změňte Python skript tak, aby do názvu souboru vložil i jméno přihlášeného operátora. Ideálně jako volitelnou možnost s přepínačem (protože později při plánování samospouštění skriptu by nám to havarovalo, když není přihlášen nikdo) Připravte i varianty (přepínačem) s TFTP a SFTP Připravte instalační skript, aby nebylo nutné rtm příkazy zadávat. Tak například udělejte přepínač --install v našem skriptu, který rtm příkazy provede (dle argumentů pro FTP/SFTP/TFTP nebo s interaktivním průvodcem
Update port description na základě nového LLDP souseda V předchozí části jsme si vytvořili Python skript na pojmenování portů (description) podle sysname jejich LLDP souseda. Abychom to provedli, museli jsme skript spustit. Pojďme teď zajistit automatické spuštění skriptu v okamžiku, kdy se nový LLDP soused objeví. Pokud máte předchozí skript nahraný v zařízení, stačí přidat EAA politiku navázanou na zprávu v logu. Budeme tedy reagovat o událost v logu obsahující řetězec LLDP_CREATE_NEIGHBOR a to okamžitě (tedy hned při prvním výskytu během vteřiny). [Switch1]rtm cli-policy LLDP_update [Switch1-rtm-LLDP_update]event syslog priority all msg LLDP_CREATE_NEIGHBOR occurs 1 period 1 [Switch1-rtm-LLDP_update]action 0 cli python portnames.py [Switch1-rtm-LLDP_update]user-role network-admin [Switch1-rtm-LLDP_update]commit
A to je všechno co potřebujeme. Vyjdeme ze situace, kdy žádné description na portech nejsou a port vedoucí k sousedovi je zatím vypnutý. [Switch1]dis int br Brief information on interface(s) under route mode: Link: ADM - administratively down; Stby - standby Protocol: (s) - spoofing Interface Link Protocol Main IP Description InLoop0 UP UP(s) -Loop1 UP UP(s) 10.0.0.1 M-E1/0/1 UP UP 172.16.1.2 NULL0 UP UP(s) -REG0 DOWN --Brief information on interface(s) under bridge mode: Link: ADM - administratively down; Stby - standby Speed or Duplex: (a)/A - auto; H - half; F - full Type: A - access; T - trunk; H - hybrid Interface Link Speed Duplex Type PVID Description GE1/0/2 ADM auto A A 1
27 | H P s k r i p t o v á n í v C o m w a r e
GE1/0/3 GE1/0/4 GE1/0/5 GE1/0/6 GE1/0/7 GE1/0/8
ADM ADM ADM ADM ADM ADM
auto auto auto auto auto auto
A A A A A A
A A A A A A
1 1 1 1 1 1
Nahodíme teď port, za kterým je skryto zařízení schopné LLDP komunikace. Objevení nového LLDP souseda generuje zprávu do logu a na tu my reagujeme spuštěním skriptu. Nemusíme tak nic dělat, ani být v tu chvíli do prvku připojeni a description se nám zaktualizuje automaticky. [Switch1]int g 1/0/2 [Switch1-GigabitEthernet1/0/2]undo shut [Switch1-GigabitEthernet1/0/2]%Apr 11 07:56:50:341 2014 Switch1 LLDP/6/LLDP_CREATE_NEIGHBOR: -MDC=1; Nearest bridge agent neighbor created on port GigabitEthernet1/0/2 (IfIndex 3), neighbor's chassis ID is 00e00200-0000, port ID is GigabitEthernet1/0/2. %Apr 11 07:56:50:354 2014 Switch1 IFNET/3/PHY_UPDOWN: -MDC=1; Physical state on the interface GigabitEthernet1/0/2 changed to up. %Apr 11 07:56:50:359 2014 Switch1 IFNET/5/LINK_UPDOWN: -MDC=1; Line protocol state on the interface GigabitEthernet1/0/2 changed to up. %Apr 11 07:56:56:904 2014 Switch1 RTM/6/RTM_POLICY: -MDC=1; CLI policy LLDP_update is running successfully. [Switch1-GigabitEthernet1/0/2]dis int br Brief information on interface(s) under route mode: Link: ADM - administratively down; Stby - standby Protocol: (s) - spoofing Interface Link Protocol Main IP Description InLoop0 UP UP(s) -Loop1 UP UP(s) 10.0.0.1 M-E1/0/1 UP UP 172.16.1.2 NULL0 UP UP(s) -REG0 DOWN --Brief information on interface(s) under bridge mode: Link: ADM - administratively down; Stby - standby Speed or Duplex: (a)/A - auto; H - half; F - full Type: A - access; T - trunk; H - hybrid Interface Link Speed Duplex Type PVID Description GE1/0/2 UP 1G(a) F(a) A 1 to_Switch2 GE1/0/3 ADM auto A A 1 GE1/0/4 ADM auto A A 1 GE1/0/5 ADM auto A A 1 GE1/0/6 ADM auto A A 1 GE1/0/7 ADM auto A A 1 GE1/0/8 ADM auto A A 1
To bychom měli … přemýšlíte, co se skriptem dál? Podobně jako v předshozím kroku zvažte automatickou instalaci do RTM ze skriptů (--install nebo průvodce apod.), případně reagujte na situace, kdy už tam description je a nesedí. 28 | H P s k r i p t o v á n í v C o m w a r e
Přetížený port Na závěr kapitoly si vyzkoušíme ještě reakci na události na portech, konkrétně zkusíme překročení čitače počtu přijmutích paketů za vteřinu. Odpovědí na událost nám tentokrát nebude spuštění skriptu, ale vygenerujeme si vlastní syslog zprávu. Nastavujeme tedy přijaté pakety za vteřinu (rcvpps) jako objekt, na který reagujeme a spustit událost chceme, pokud překročí (ge) hodnotu 5. Vyresetovat (tedy znovu aktivovat možnost reakce) nastavíme při poklesu zatížení pod (le) 2 pps. Countery na portech budeme sledovat v intervalu 1 vteřina. [HP]rtm cli-policy reaguj_port [HP-rtm-reaguj_port]event interface g2/0 monitor-obj rcv-pps start-op ge start-val 5 restart-op le restart-val 2 interval 1 [HP-rtm-reaguj_port]action 0 syslog priority 3 facility local0 msg Mame pretizeny port g 2/0 [HP-rtm-reaguj_port]user-role network-admin [HP-rtm-reaguj_port]commit
Připravíme si prostředí a můžeme vyzkoušet. dis counter rate inbound interface g 2/0 Interface Total (pps) Broadcast (pps) (pps) GE2/0 0 ---
Multicast
Overflow: More than 14 digits. --: Not supported. %Apr 12 19:22:16:035 2014 HP RTM/3/RTM_ACTION: Mame pretizeny port g 2/0 %Apr 12 19:22:16:038 2014 HP RTM/6/RTM_POLICY: CLI policy reaguj_port is running successfully. dis counter rate inbound interface g 2/0 Interface Total (pps) Broadcast (pps) (pps) GE2/0 6 ---
Multicast
Overflow: More than 14 digits. --: Not supported.
29 | H P s k r i p t o v á n í v C o m w a r e
Plánování úloh Comware 7 dovoluje plánování spouštění CLI příkazů a to těmito způsoby: once at HH:MM (spusť dnes v zadaný čas) once delay HH:MM (spusť od teď za zadaný počet minut, případně i hodin) repeating at HH:MM (spusť každý den v zadaný čas) repeating delay HH:MM (od teď opakuj každých X minut nebo hodin) Scheduler tedy podle nastavení spustí to, čemu se v Comware 7 říká job (ten je potřeba nejdřív definovat) – vytvoří se mu název a pak následuje číslovaný seznam CLI příkazů. A jedním z těchto příkazů může být i spuštění Python skriptu tak, jak toho využijeme my. [Switch1]scheduler job ftp_archive [Switch1-job-ftp_archive]command 0 python cfgsave.py -s 172.16.1.3 -u ftp p ftp -d [Switch1-job-ftp_archive]quit [Switch1]scheduler schedule autobackup [Switch1-schedule-autobackup]user-role network-admin [Switch1-schedule-autobackup]job ftp_archive [Switch1-schedule-autobackup]time repeating interval 2 [Switch1-schedule-autobackup]quit [Switch1]
A teď už stačí jen čekat a každé dvě minuty (resp. o něco málo déle … ne že by v praxi hrálo roli) bychom měli dostat zálohu na FTP server (nezapomeňte mimo lab použít nějaký rozumnější, myšleno delší, interval). Obvyklejší bude záloha třeba každou hodinu nebo každý den v zadaný čas. <Switch2>%Apr 10 17:15:34:243 2014 Switch2 FTP/6/AUTH: -MDC=1; User N/[email protected] for connection. %Apr 10 17:15:34:265 2014 Switch2 FTP/6/AUTH: -MDC=1; User [email protected] login. %Apr 10 17:15:34:279 2014 Switch2 FTP/5/OPER: -MDC=1; User [email protected] uploaded flash:/Switch1_1404101710.cfg. %Apr 10 17:15:34:289 2014 Switch2 FTP/6/LOGOUT: -MDC=1; User [email protected] logout. <Switch2>%Apr 10 17:17:55:231 2014 Switch2 FTP/6/AUTH: -MDC=1; User N/[email protected] for connection. %Apr 10 17:17:55:268 2014 Switch2 FTP/6/AUTH: -MDC=1; User [email protected] login. %Apr 10 17:17:55:291 2014 Switch2 FTP/5/OPER: -MDC=1; User [email protected] uploaded flash:/Switch1_1404101712.cfg. %Apr 10 17:17:55:300 2014 Switch2 FTP/6/LOGOUT: -MDC=1; User [email protected] logout. <Switch2>%Apr 10 17:20:12:452 2014 Switch2 FTP/6/AUTH: -MDC=1; User N/[email protected] for connection. %Apr 10 17:20:12:491 2014 Switch2 FTP/6/AUTH: -MDC=1; User [email protected] login. %Apr 10 17:20:12:503 2014 Switch2 FTP/5/OPER: -MDC=1; User [email protected] uploaded flash:/Switch1_1404101714.cfg. %Apr 10 17:20:12:512 2014 Switch2 FTP/6/LOGOUT: -MDC=1; User [email protected] logout.
30 | H P s k r i p t o v á n í v C o m w a r e
31 | H P s k r i p t o v á n í v C o m w a r e
Závěr Tento materiál zahrnoval Python, EAA a job plánování v Comware OS verze 7. Kromě toho obsahují tyto verze i TCL skriptování, které ale není předmětem tohoto dokumentu. Tímto jsme si tedy vyzkoušili skriptování uvnitř Comware s Python a v jiném dokumentu na www.netsvet.cz už dnes najdete skriptování v Python pro HP VAN SDN Controller. V některých dalších částech se podíváme na to, jak využít přístupu k zařízením přes NETCONF a také prozkoumáme programovatelné rozhranní v iMC (eAPI). Sledujte naše stránky, jednoho dne se to tam určitě objeví. Mnoho zdaru a inspirace ! Tomáš Kubica
32 | H P s k r i p t o v á n í v C o m w a r e