Книга: PyNEng
Назад: Pexpect
Дальше: Paramiko

Telnetlib

Модуль telnetlib

Модуль telnetlib входит в стандартную библиотеку Python. Это реализация клиента telnet.

Подключиться по telnet можно и используя pexpect. Плюс telnetlib в том, что этот модуль входит в стандартную библиотеку Python.

Принцип работы telnetlib напоминает pexpect, но есть несколько отличий. Самое заметное отличие в том, что telnetlib требует передачи байтовой строки, а не обычной.

Подключение выполняется таким образом:

In [1]: telnet = telnetlib.Telnet('192.168.100.1') 

С помощью метода read_until указывается до какой строки считать вывод. При этом, как аргумент надо передавать не обычную строку, а байты:

In [2]: telnet.read_until(b'Username') Out[2]: b'\r\n\r\nUser Access Verification\r\n\r\nUsername' 

Метод read_until возвращает все, что он считал до указанной строки.

Для передачи данных используется метод write. Ему нужно передавать байтовую строку:

In [3]: telnet.write(b'cisco\n') 

Читаем вывод до слова Password и передаем пароль:

In [4]: telnet.read_until(b'Password') Out[4]: b': cisco\r\nPassword'  In [5]: telnet.write(b'cisco\n') 

Теперь можно указать, что надо считать вывод до приглашения, а затем отправить команду:

In [6]: telnet.read_until(b'>') Out[6]: b': \r\nR1>'  In [7]: telnet.write(b'sh ip int br\n') 

После отправки команды можно продолжать использовать метод read_until:

In [8]: telnet.read_until(b'>') Out[8]: b'sh ip int br\r\nInterface                  IP-Address      OK? Method Status                Protocol\r\nEthernet0/0                192.168.100.1   YES NVRAM  up                    up      \r\nEthernet0/1                192.168.200.1   YES NVRAM  up                    up      \r\nEthernet0/2                19.1.1.1        YES NVRAM  up                    up      \r\nEthernet0/3                192.168.230.1   YES NVRAM  up                    up      \r\nEthernet0/3.100            10.100.0.1      YES NVRAM  up                    up      \r\nEthernet0/3.200            10.200.0.1      YES NVRAM  up                    up      \r\nEthernet0/3.300            10.30.0.1       YES NVRAM  up                    up      \r\nR1>' 

Или использовать еще один метод для чтения read_very_eager.

При использовании метода read_very_eager, можно отправить несколько команд, а затем считать весь доступный вывод:

In [9]: telnet.write(b'sh arp\n')  In [10]: telnet.write(b'sh clock\n')  In [11]: telnet.write(b'sh ip int br\n')  In [12]: all_result = telnet.read_very_eager().decode('utf-8')  In [13]: print(all_result) sh arp Protocol  Address          Age (min)  Hardware Addr   Type   Interface Internet  10.30.0.1               -   aabb.cc00.6530  ARPA   Ethernet0/3.300 Internet  10.100.0.1              -   aabb.cc00.6530  ARPA   Ethernet0/3.100 Internet  10.200.0.1              -   aabb.cc00.6530  ARPA   Ethernet0/3.200 Internet  19.1.1.1                -   aabb.cc00.6520  ARPA   Ethernet0/2 Internet  192.168.100.1           -   aabb.cc00.6500  ARPA   Ethernet0/0 Internet  192.168.100.2         124   aabb.cc00.6600  ARPA   Ethernet0/0 Internet  192.168.100.3         143   aabb.cc00.6700  ARPA   Ethernet0/0 Internet  192.168.100.100       160   aabb.cc80.c900  ARPA   Ethernet0/0 Internet  192.168.200.1           -   0203.e800.6510  ARPA   Ethernet0/1 Internet  192.168.200.100        13   0800.27ac.16db  ARPA   Ethernet0/1 Internet  192.168.230.1           -   aabb.cc00.6530  ARPA   Ethernet0/3 R1>sh clock *19:18:57.980 UTC Fri Nov 3 2017 R1>sh ip int br Interface                  IP-Address      OK? Method Status                Protocol Ethernet0/0                192.168.100.1   YES NVRAM  up                    up Ethernet0/1                192.168.200.1   YES NVRAM  up                    up Ethernet0/2                19.1.1.1        YES NVRAM  up                    up Ethernet0/3                192.168.230.1   YES NVRAM  up                    up Ethernet0/3.100            10.100.0.1      YES NVRAM  up                    up Ethernet0/3.200            10.200.0.1      YES NVRAM  up                    up Ethernet0/3.300            10.30.0.1       YES NVRAM  up                    up R1> 

С read_until будет немного другой подход. Можно выполнить те же три команды, но затем получать вывод по одной за счет чтения до строки с приглашением:

In [14]: telnet.write(b'sh arp\n')  In [15]: telnet.write(b'sh clock\n')  In [16]: telnet.write(b'sh ip int br\n')  In [17]: telnet.read_until(b'>') Out[17]: b'sh arp\r\nProtocol  Address          Age (min)  Hardware Addr   Type   Interface\r\nInternet  10.30.0.1               -   aabb.cc00.6530  ARPA   Ethernet0/3.300\r\nInternet  10.100.0.1              -   aabb.cc00.6530  ARPA   Ethernet0/3.100\r\nInternet  10.200.0.1              -   aabb.cc00.6530  ARPA   Ethernet0/3.200\r\nInternet  19.1.1.1                -   aabb.cc00.6520  ARPA   Ethernet0/2\r\nInternet  192.168.100.1           -   aabb.cc00.6500  ARPA   Ethernet0/0\r\nInternet  192.168.100.2         126   aabb.cc00.6600  ARPA   Ethernet0/0\r\nInternet  192.168.100.3         145   aabb.cc00.6700  ARPA   Ethernet0/0\r\nInternet  192.168.100.100       162   aabb.cc80.c900  ARPA   Ethernet0/0\r\nInternet  192.168.200.1           -   0203.e800.6510  ARPA   Ethernet0/1\r\nInternet  192.168.200.100        15   0800.27ac.16db  ARPA   Ethernet0/1\r\nInternet  192.168.230.1           -   aabb.cc00.6530  ARPA   Ethernet0/3\r\nR1>'  In [18]: telnet.read_until(b'>') Out[18]: b'sh clock\r\n*19:20:39.388 UTC Fri Nov 3 2017\r\nR1>'  In [19]: telnet.read_until(b'>') Out[19]: b'sh ip int br\r\nInterface                  IP-Address      OK? Method Status                Protocol\r\nEthernet0/0                192.168.100.1   YES NVRAM  up                    up      \r\nEthernet0/1                192.168.200.1   YES NVRAM  up                    up      \r\nEthernet0/2                19.1.1.1        YES NVRAM  up                    up      \r\nEthernet0/3                192.168.230.1   YES NVRAM  up                    up      \r\nEthernet0/3.100            10.100.0.1      YES NVRAM  up                    up      \r\nEthernet0/3.200            10.200.0.1      YES NVRAM  up                    up      \r\nEthernet0/3.300            10.30.0.1       YES NVRAM  up                    up      \r\nR1>' 

Важное отличие между read_until и read_very_eager заключается в том, как они реагируют на отсутствие вывода.

Метод read_until ждет определенную строку. По умолчанию, если ее нет, метод "зависнет". Опциональный параметр timeout позволяет указать сколько ждать нужную строку:

In [20]: telnet.read_until(b'>', timeout=5) Out[20]: b'' 

Если за указанное время строка не появилась, возвращается пустая строка.

Метод read_very_eager просто вернет пустую строку, если вывода нет:

In [21]: telnet.read_very_eager() Out[21]: b'' 

Метод expect позволяет указывать список с регулярными выражениями. Он работает похоже на pexpect, но в модуле telnetlib всегда надо передавать список регулярных выражений.

При этом, можно передавать байтовые строки или компилированные регулярные выражения:

In [22]: telnet.write(b'sh clock\n')  In [23]: telnet.expect([b'[>#]']) Out[23]: (0,  <_sre.SRE_Match object; span=(46, 47), match=b'>'>,  b'sh clock\r\n*19:35:10.984 UTC Fri Nov 3 2017\r\nR1>') 

Метод expect возвращает кортеж их трех элементов:

  • индекс выражения, которое совпало
  • объект Match
  • байтовая строка, которая содержит все считанное до регулярного выражения и включая его

Соответственно, при необходимости, с этими элементами можно дальше работать:

In [24]: telnet.write(b'sh clock\n')  In [25]: regex_idx, match, output = telnet.expect([b'[>#]'])  In [26]: regex_idx Out[26]: 0  In [27]: match.group() Out[27]: b'>'  In [28]: match Out[28]: <_sre.SRE_Match object; span=(46, 47), match=b'>'>  In [29]: match.group() Out[29]: b'>'  In [30]: output Out[30]: b'sh clock\r\n*19:37:21.577 UTC Fri Nov 3 2017\r\nR1>'  In [31]: output.decode('utf-8') Out[31]: 'sh clock\r\n*19:37:21.577 UTC Fri Nov 3 2017\r\nR1>' 

Закрывается соединение методом close:

In [32]: telnet.close() 
Назад: Pexpect
Дальше: Paramiko