Заметка: из раздела по подписке

Задача: Написать скрипт как выполнять бекап настроек (running-config) Cisco WS-C2960S-24TS-L

Просто раньше вся офисная сеть была построена исключительно на Mikrotik (Core, Коммутаторы, Wifi-точки, PowerBox), когда учредители решили сменить руководителя IT-департамента, то каждый приходящий мнил себя богом системного администрирования и не с кем ни считался. Последний, так вообще отдел IT не ставил ни во что, а только убедил генерального что нам нужно заменить все Mikrotik на Cisco. И вот мы стали на Avito покупать Cisco 3850, Cisco WS-C2960S-24TS-L (c SFP модулями: GLX-BX-U – GLX-BX-D), Wi-fi контроллеры Сisco_AIR-CT5508-50-K9. Все конечно хорошо, но как же осуществлять резервное копирование, которым заведую Я, т.к. никому не нужно. Выдались свободные минуты, которые я решил посвятить проработке написания скрипта по бекапированию настроек Cisco, с учетом текущего в последствии смогу адаптировать и для другого оборудования в этой компании.

Набросил план как я себе это вижу:

  • Поднять tftp
  • Подключаюсь по SSH к Cisco
  • Инициализирую команду: Copy running-config tftp
  • Отключаюсь от Cisco

И все

Ниже мое видение решение задачи:

Шаг №1: Пробую подключиться по SSH с Ubuntu 20.04 Server к коммутатору Cisco 2960:

Если есть сложно, то смотреть заметку: "Подключение по SSH с Ubuntu 20.04 Server к Cisco WS-C2960S-24TS-L"

Шаг №2: Задействуем заметку "Поднимаем TFTPD на Ubuntu 20.04 Server"

Поднимаем TFTPD на Ubuntu 20.04 Server

Шаг №3: Итого первоначальный скрипт для резервного копирования одного коммутатора:

ekzorchik@srv-backup:~$ sudo apt-get install -y expect 
ekzorchik@srv-backup:~$ nano cisco1
#!/usr/bin/expect -f
##!/usr/bin/expect -f - подключаем интерпретатор, ключ -f означает, что команды будут считываться из файла скрипта.

set host "sw002.polygon.local"
set username "ekzorchik"
set password "712mbddr@"
set secpassword "712mbddr@"

set now [clock seconds]
set date [clock format $now -format {%b-%d-%Y-%H-%M}]

sleep 2

#начало сценария
spawn ssh $username@$host;
expect "*assword: "
send "$password\r"
sleep 2

#Ожидаем приглашение Cisco в обычном режиме
expect ">"
#посылаем команду входа в привилегированный режим
send "en\r"

#ожидаем ввода пароля
expect "Password:"
#вводим пароль
send "$secpassword\r"
sleep 2

#Ожидаем приглашения Cisco в привилегированном режиме
expect "#"

#Копируем текущий конфиг на tftp
send "copy running-config tftp\r"
sleep 2
expect "Address or name of remote host []?"
send "192.168.9.130\r"
sleep 2

expect "Destination filename []?"
send "sw002-config-$date\r"
sleep 2

#Ожидаем приглашения Cisco в привилегированном режиме
expect "#"

#Выходим из сценария
send "exit\r"
expect eof
ekzorchik@srv-backup:~$ chmod +x cisco1

Шаг №4: Результат выполнения скрипта для одного коммутатора:

ekzorchik@srv-backup:~$ ./cisco1
spawn ssh ekzorchik@sw002.polygon.local
Password:
sw002>en
Password:
sw002#copy running-config tftp
Address or name of remote host []? 192.168.9.130
Destination filename [sw002-confg]? sw002-config-Apr-05-2022-10-37
!!
4482 bytes copied in 0.865 secs (5182 bytes/sec)
sw002#exit
Connection to sw002.polygon.local closed.
ekzorchik@srv-backup:~$

Шаг №5: Смотрю содержимое каталога /tftpboot после выполнения скрипта резервного копирования для одного коммутатора:

ekzorchik@srv-backup:~$ ls /tftpboot/
sw002-config-Apr-05-2022-10-46
ekzorchik@srv-backup:~$ file /tftpboot/sw002-config-Apr-05-2022-10-46
/tftpboot/sw002-config-Apr-05-2022-10-46: ASCII text
ekzorchik@srv-backup:~$ cat /tftpboot/sw002-config-Apr-05-2022-10-46 | head -n20

!
! Last configuration change at 12:14:57 MSK Tue Apr 5 2022 by ekzorchik
! NVRAM config last updated at 16:07:00 MSK Fri Apr 1 2022
!
version 15.2
no service pad
service timestamps debug datetime msec
service timestamps log datetime localtime
no service password-encryption
!
hostname sw002
!
boot-start-marker
boot-end-marker
!
no logging console
enable secret 5 $1$lOGU$8V3XiJvfAG.K6S.m.l9SM/
!
username ekzorchik secret 5 $2$E8Ib$QckulRxA6LGvqhXbdFovl.
ekzorchik@srv-backup:~$

Получается, что я могу для каждого коммутатора Cisco создать по такому скрипту и через cron запускать создание резервных копий, пусть не могу сделать один большой скрипт, но и такого для моих 3 коммутаторов будет достаточно.

Шаг №6: А если все же хосты коммутаторов объединить в один скрипт, но сперва предопределим параметры подключения к Cisco коммутаторам в /etc/ssh/ssh_config:

ekzorchik@srv-backup:~$ sudo nano /etc/ssh/ssh_config
Host sw001.polygon.local
        Port 22
        StrictHostKeyChecking no
        PasswordAuthentication yes
        Ciphers aes256-cbc
        KexAlgorithms +diffie-hellman-group1-sha1

Host sw002.polygon.local
        Port 22
        StrictHostKeyChecking no
        PasswordAuthentication yes
        Ciphers aes256-cbc
        KexAlgorithms +diffie-hellman-group1-sha1

Host sw004.polygon.local
        Port 22
        StrictHostKeyChecking no
        PasswordAuthentication yes
        Ciphers aes256-cbc
        KexAlgorithms +diffie-hellman-group1-sha1

После не забываем сохранить внесенные изменения.

На заметку: Также хосты добавить в

ekzorchik@srv-backup:~$ sudo nano /etc/ssh/known_hosts
sw001.polygon.local
sw002.polygon.local
w004.polygon.local

Шаг №7: Копирую первый скрипт во второй дабы не задавать атрибуты выполнения и привожу его содержимое к виду:

ekzorchik@srv-backup:~$ cp cisco1 cisco2
ekzorchik@srv-backup:~$ nano cisco2
#!/usr/bin/expect -f
##!/usr/bin/expect -f - подключаем интерпретатор, ключ -f означает, что команды будут считываться из файла скрипта.

#set host1 "sw001.polygon.local"
#set host2 "sw002.polygon.local"
#set host4 "sw004.polygon..local"
set username "ekzorchik"
set password "712mbddr@"
set secpassword "712mbddr@"

set now [clock seconds]
set date [clock format $now -format {%b-%d-%Y-%H-%M}]

sleep 2


# while 1 {
 foreach host {sw001.polygon.local sw002.polygon.local sw004.polygon.local} {
  spawn ssh $username@$host;
  expect "*assword: "
  send "$password\r"
  sleep 2

#Ожидаем приглашение Cisco в обычном режиме
expect ">"
#посылаем команду входа в привилегированный режим
send "en\r"

#ожидаем ввода пароля
expect "Password:"
#вводим пароль
send "$secpassword\r"
sleep 2

#Ожидаем приглашения Cisco в привилегированном режиме
expect "#"

#Копируем текущий конфиг на tftp
send "copy running-config tftp\r"
sleep 2
expect "Address or name of remote host []?"
send "192.168.9.130\r"
sleep 2

expect "Destination filename []?"
send "$host-config-$date\r"
sleep 2

#Ожидаем приглашения Cisco в привилегированном режиме
expect "#"

#Выходим из сценария
send "exit\r"
expect eof
}

Шаг №8: Результат работы скрипта бекапирования нескольких коммутаторов:

ekzorchik@srv-backup:~$ ./cisco2
spawn ssh ekzorchik@sw001.polygon.local
Password:
sw001>en
Password:
sw001#copy running-config tftp
Address or name of remote host []? 192.168.9.130
Destination filename [sw001-confg]? sw001.polygon.local-config-Apr-05-2022-11-10
!!
5292 bytes copied in 0.886 secs (5973 bytes/sec)
sw001#exit
Connection to sw001.polygon.local closed.
spawn ssh ekzorchik@sw002.polygon.local
Password:
sw002>en
Password:
sw002#copy running-config tftp
Address or name of remote host []? 192.168.9.130
Destination filename [sw002-confg]? sw002.polygon.local-config-Apr-05-2022-11-10
!!
4482 bytes copied in 0.865 secs (5182 bytes/sec)
sw002#exit
Connection to sw002.polygon.local closed.
spawn ssh ekzorchik@sw004.polygon.local
Password:
sw004>en
Password:
sw004#copy running-config tftp
Address or name of remote host []? 192.168.9.130
Destination filename [sw004-confg]? sw004.polygon.local-config-Apr-05-2022-11-10
!!
5166 bytes copied in 0.860 secs (6007 bytes/sec)
sw004#exit
Connection to sw004.polygon.local closed.
ekzorchik@srv-backup:~$

Шаг №9: Содержимое каталога /tftpboot после выполнения скрипта cisco2:

ekzorchik@srv-backup:~$ ls /tftpboot/ -lh
total 24K
-rw-rw-rw- 1 tftp tftp 5.2K Apr  5 11:10 sw001.polygon.local-config-Apr-05-2022-11-10
-rw-rw-rw- 1 tftp tftp 4.4K Apr  5 11:10 sw002.polygon.local-config-Apr-05-2022-11-10
-rw-rw-rw- 1 tftp tftp 5.1K Apr  5 11:10 sw004.polygon.local-config-Apr-05-2022-11-10
ekzorchik@srv-backup:~$

Круто! Я молодец, я не только проработал как сделать единичный бекап текущей конфигурации моего коммутатора Cisco WS-C2960S-24TS-L, но и доработал скрипт дабы в цикле подключаться к каждому из 3 и создавать резервную копию. Думаю, такой вариант решения поставленной задачи мне подойдет.

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

aollo@srv-tablo:~$ sudo /etc/script/bcisco3850
spawn ssh ollo@192.168.3.201
The authenticity of host '192.168.3.201 (192.168.3.201)' can't be established.
RSA key fingerprint is SHA256:Z6hQAgFWQ49uXv7Hb34BoOrvHtvoDirIYDbxYX/pZD0.
Are you sure you want to continue connecting (yes/no)? Amigo.Local
Please type 'yes' or 'no': en
Please type 'yes' or 'no': Amigo.Local
Please type 'yes' or 'no': copy running-config tftp
Please type 'yes' or 'no': 192.168.9.128
Please type 'yes' or 'no': 192.168.3.201-config-Nov-20-2022-09-33
Please type 'yes' or 'no': copy flash:vlan.dat tftp:
Please type 'yes' or 'no': 192.168.9.128
Please type 'yes' or 'no': 192.168.3.201-vlan.dat-Nov-20-2022-09-33
Please type 'yes' or 'no': exit
Please type 'yes' or 'no': yes

не знаю почему, но решилось добавлением в /etc/ssh/ssh_config и после скрипт начал отрабатывать успешно

#=====================
Host 192.168.3.200
        Port 22
        StrictHostKeyChecking no
        PasswordAuthentication yes

Host 192.168.3.201
        Port 22
        StrictHostKeyChecking no
        PasswordAuthentication yes

Host 192.168.3.202
        Port 22
        StrictHostKeyChecking no
        PasswordAuthentication yes

От 21.02.2023

В данную заметку можно добавить, что при резервном копировании коммутаторов Cisco нужно помимо конфигурационного файла бекапировать и файл содержащий vlan (vlan.dat)

#!/usr/bin/expect -f
##!/usr/bin/expect -f - подключаем интерпретатор, ключ -f означает, что команды будут считываться из файла скрипта.

set username "ekzorchik"
set password "Aa1234567aA"
set secpassword "712mbddr@"

set now [clock seconds]
set date [clock format $now -format {%b-%d-%Y-%H-%M}]

sleep 2


# while 1 {
# foreach host {sw01.polygon.local sw02.polygon.local sw03.polygon.local} {
 foreach host {192.168.3.201 192.168.3.202 192.168.3.200} {
  spawn ssh $username@$host;
# expect {Are you sure you want to continue connecting (yes/no/[fingerprint])? }
#  send "yes\r"
  sleep 2
  expect "*assword: "
  send "$password\r"
  sleep 2

#Ожидаем приглашение Cisco в обычном режиме
expect ">"
#посылаем команду входа в привилегированный режим
send "en\r"

#ожидаем ввода пароля
expect "Password:"
#вводим пароль
send "$secpassword\r"
sleep 2

#Ожидаем приглашения Cisco в привилегированном режиме
expect "#"

#Копируем текущий конфиг на tftp
send "copy running-config tftp\r"
sleep 2
expect "Address or name of remote host []?"
send "192.168.9.128\r"
sleep 2

expect "Destination filename []?"
send "$host-config-$date\r"
sleep 2

#Ожидаем приглашения Cisco в привилегированном режиме
expect "#"


send "copy flash:vlan.dat tftp:\r"
sleep 2
expect "Address or name of remote host []?"
send "192.168.9.128\r"
sleep 2
expect "Destination filename []?"
send "$host-vlan.dat-$date\r"
sleep 2
expect "#"

#Выходим из сценария
send "exit\r"
expect eof
}

Результат выполнения:

aollo@srv-backup:~$ ls /tftpboot/ | grep -Feb-19
192.168.3.200-config-Feb-19-2023-08-55
192.168.3.200-vlan.dat-Feb-19-2023-08-55
192.168.3.201-config-Feb-19-2023-08-55
192.168.3.201-vlan.dat-Feb-19-2023-08-55
192.168.3.202-config-Feb-19-2023-08-55
192.168.3.202-vlan.dat-Feb-19-2023-08-55
aollo@srv-backup:~$

На этом у меня все, с уважением автор блога Олло Александр aka ekzorchik.