16 de abr. de 2018

Fazendo Backup de Routers Cisco IOS utilizando Netmiko

Olá Pessoal Boa Tarde, depois de um tempo sumido por problemas diversos vamos continuar com nossos posts de automatização.

O dia de hoje vou criar um script em python que se coneta a vários roteadores Cisco IOS executa o comando "sh run", e armazena o resultado em um diretório de backups.


A Topologia que vou utilizar é a seguinte:



O roteador IOU1, IOU2 e IOU4 rodam OSPF entre eles.  Eu tenho conetividade SSH a eles via interfaces de Loopback:

IOU1: 1.1.1.1
IOU2: 2.2.2.2
IOU4: 4.4.4.4

Todos eles tem configurado um usuário e senha padrão cisco/cisco e um enable também de cisco.

A configuração dos roteadores não é importante para esse post. O que é do nosso interesse é como armazenar a saída do comando "sh run" em um arquivo de texto.

O primeiro passo é definir os roteadores, cada roteador tem uma ip, usuário, senha, nome de host etc. Para isso vamos utilizar um dicciónario por cada roteador:

cisco_iou1={'device_type':'cisco_ios','ip':'1.1.1.1','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou2={'device_type':'cisco_ios','ip':'2.2.2.2','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou3={'device_type':'cisco_ios','ip':'3.3.3.3','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou4={'device_type':'cisco_ios','ip':'4.4.4.4','username':'cisco','password':'cisco','secret':'cisco','timeout':10}

Vocês podem ver que eu adicionei um roteador a mais o IOU3, no decorrer do post vocês iram ver o porque de eu fazer isso.

Logo eu vou definir uma lista contendo cada um dos roteadores:

cisco_routers=[cisco_iou1,cisco_iou2,cisco_iou3,cisco_iou4]


Agora que temos definido quais elementos queremos coletar informação, o seguinte passo é fazer uma varredura em todos esses elementos, para isso utilizamos um laço "for".

for cisco_router in cisco_routers:
 net_connect=ConnectHandler(**cisco_router)
 net_connect.enable()
 output=net_connect.send_command('sh run')
 print output
 net_connect.exit_enable_mode()
 net_connect.disconnect()

O código acima pode ser explicado como: "para cada roteador, abre uma sessão SSH, troca para o modo enable,executa o comando "sh run", printa na tela o resultado ...logo sai do enable, e fecha a conexão"....Simples verdad!!..

O script completo ficaria:

#!/usr/bin/python


from netmiko import ConnectHandler

cisco_iou1={'device_type':'cisco_ios','ip':'1.1.1.1','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou2={'device_type':'cisco_ios','ip':'2.2.2.2','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou3={'device_type':'cisco_ios','ip':'3.3.3.3','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou4={'device_type':'cisco_ios','ip':'4.4.4.4','username':'cisco','password':'cisco','secret':'cisco','timeout':10}


cisco_routers=[cisco_iou1,cisco_iou2,cisco_iou3,cisco_iou4]

for cisco_router in cisco_routers:
 net_connect=ConnectHandler(**cisco_router)
 net_connect.enable()
 output=net_connect.send_command('sh run')
 print output
 net_connect.exit_enable_mode()
 net_connect.disconnect()

Vamos rodar ele e ver o que acontece:

jose@rejane:~/Automatizacao$ ./backup.py 
Building configuration...

Current configuration : 2199 bytes
!
! Last configuration change at 11:44:14 -03 Mon Apr 16 2018
version 15.2
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname IOU1
......
......
line vty 0 4
 login local
 transport input ssh
!
!
end

Traceback (most recent call last):
  File "./backup.py", line 15, in <module>
    net_connect=ConnectHandler(**cisco_router)
  File "/usr/local/lib/python2.7/dist-packages/netmiko/ssh_dispatcher.py", line 173, in ConnectHandler
    return ConnectionClass(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/netmiko/base_connection.py", line 187, in __init__
    self.establish_connection()
  File "/usr/local/lib/python2.7/dist-packages/netmiko/base_connection.py", line 654, in establish_connection
    raise NetMikoTimeoutException(msg)
netmiko.ssh_exception.NetMikoTimeoutException: Connection to device timed-out: cisco_ios 3.3.3.3:22
jose@rejane:~/Automatizacao$ 

Hummm...o script começou a rodar, ele printou o "sh run" do IOU1, IOU2 e parou em IOU3, o qual esta certo, visto que IOU3 não existe, mas nós queriamos o print de IOU4 que sabemos é um roteador ativo...o que fazer???.........Lembram da sentença "try...except"... ela é uma sentença que tenta fazer alguma coisa e se der erro executa um código de exceção e depois continua com o código normal...

Vamos modificar o nosso código para uma nova versão "backupv2.py", dessa vez com a sentença "try..except":

Script backupv2.py

#!/usr/bin/python


from netmiko import ConnectHandler

cisco_iou1={'device_type':'cisco_ios','ip':'1.1.1.1','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou2={'device_type':'cisco_ios','ip':'2.2.2.2','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou3={'device_type':'cisco_ios','ip':'3.3.3.3','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou4={'device_type':'cisco_ios','ip':'4.4.4.4','username':'cisco','password':'cisco','secret':'cisco','timeout':10}


cisco_routers=[cisco_iou1,cisco_iou2,cisco_iou3,cisco_iou4]

for cisco_router in cisco_routers:
 try:
  net_connect=ConnectHandler(**cisco_router)
  net_connect.enable()
  output=net_connect.send_command('sh run')
  print output
  net_connect.exit_enable_mode()
  net_connect.disconnect()
 except:
  print("Erro de conexao ao roteador %s" % cisco_router['ip'])

Executando o mesmo temos:

jose@rejane:~/Automatizacao$ ./backupv2.py 
Building configuration...

Current configuration : 2199 bytes
!
! Last configuration change at 11:44:14 -03 Mon Apr 16 2018
version 15.2
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname IOU1
!
.....
.....
Erro de conexao ao roteador 3.3.3.3
Building configuration...
....
.....

Beleza!..agora nosso script funciona, e quando da algum erro em algum elemento, o script printa uma mensagem de erro.

Agora que o "core" do nosso script funciona, precisamos lhe adicionar algumas coisas, como por exemplo um arquivo log, de forma a que tudo o que seja feito por nosso script seja armazenado logeado, dessa forma é possivél detetar e corrigir falhas. Também precisamos que os "sh run" dos roteadores sejam armazenados em arquivos e não somente que sejam printados na tela.

Primeiro vou criar dois diretorios no home da minha máquina Linux:

mkdir /home/jose/backupciscorouters
mkdir /home/jose/backupciscorouters/logs

No primeiro diretório seram armazenados os "sh run", e no segundo o arquivo log, um arquivo log por dia.

O arquivos de "sh run", assim como o arquivo log precisam ter uma extensão que nos diga a data que foram criados. Para isso vamos utilizar as funções dos módulos "time" e "datetime". Para a criação do arquivo log, utilizamos o módulo "logging".

O script completo fico assim:

#!/usr/bin/python

from netmiko import ConnectHandler
import time
import datetime
import logging

#Diretorio de Backup
BackupDir='/home/jose/backupciscorouters'
#Data que sera concatenada no nome do arquivo log: backup.YYYYMMDD.log , um arquivo log por dia
LogData=datetime.datetime.now().strftime("%Y%m%d")
Log = BackupDir + "/logs/backup." + LogData + ".log"
#Configuracao basica do logging, o nivel de logging vai ser INFO, caso seja preciso mais informacao podemos colocar DEBUG
logging.basicConfig(filename=Log,
                            filemode='a',
                            format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
                            datefmt='%H:%M:%S',
                            level=logging.INFO)

#Inicio do Script, escrevo no arquivo log
logging.info('Inicio')
logging.info(datetime.datetime.now().strftime("%Y-%m-%d %H%M%S"))

#Definicao dos nossos roteadores
cisco_iou1={'device_type':'cisco_ios','ip':'1.1.1.1','host':'IOU1','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou2={'device_type':'cisco_ios','ip':'2.2.2.2','host':'IOU2','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou3={'device_type':'cisco_ios','ip':'3.3.3.3','host':'IOU3','username':'cisco','password':'cisco','secret':'cisco','timeout':10}
cisco_iou4={'device_type':'cisco_ios','ip':'4.4.4.4','host':'IOU4','username':'cisco','password':'cisco','secret':'cisco','timeout':10}

#Lista com os nossos roteadores
cisco_routers=[cisco_iou1,cisco_iou2,cisco_iou3,cisco_iou4]

#Laco para executar o comando sh run roteador por roteador
for cisco_router in cisco_routers:
 try:
  #Abrindo uma conexao SSH
  net_connect=ConnectHandler(**cisco_router)
  #Trocando para enable
  net_connect.enable()
  #Executando o comando sh run
  output=net_connect.send_command('sh run')
  #Nome do arquivo de backup no formato hostname.YYYY-MM-DD-HH:MM:SS
  BackupNameOfFile=BackupDir + "/" + cisco_router['host'] + "." + datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S")
  #Escrevendo no arquivo a saida do comando sh run
  with open(BackupNameOfFile,'w') as fh:
   fh.write(output)
  #Saindo do enable
  net_connect.exit_enable_mode()
  #Fechando a sessao SSH
  net_connect.disconnect()
 except:
  logging.info("Erro de conexao ao roteador %s" % cisco_router['ip'])

#Escrevendo lo log a palavra Fim e colocando a hora que finalizou
logging.info('Fim')
logging.info(datetime.datetime.now().strftime("%Y-%m-%d %H%M%S"))

Ao rodar o mesmo obtemos como resultado:

jose@rejane:~/Automatizacao$ ./backupv3.py 
jose@rejane:~/Automatizacao$ 

Ele nao mostra nada na tela, isso esta ok. Vejamos o diretório de backup:

jose@rejane:~/backupciscorouters$ ls -ltrah
total 40K
drwxr-xr-x 82 jose jose  20K Abr 16 12:27 ..
drwxrwxr-x  2 jose jose 4,0K Abr 16 21:07 logs
-rw-rw-r--  1 jose jose 2,3K Abr 16 21:07 IOU1.2018-04-16-21:07:37
-rw-rw-r--  1 jose jose 2,1K Abr 16 21:07 IOU2.2018-04-16-21:07:42
-rw-rw-r--  1 jose jose 2,1K Abr 16 21:07 IOU4.2018-04-16-21:07:48
drwxrwxr-x  3 jose jose 4,0K Abr 16 21:07 .
jose@rejane:~/backupciscorouters$ 

Show!..os arquivos com o conteúdo do "sh run" foram criados e eles tem a data que foram criados.

E o arquivo log como será que fico?..Vejamos:

jose@rejane:~/backupciscorouters/logs$ ls -ltrah
total 12K
drwxrwxr-x 2 jose jose 4,0K Abr 16 21:07 .
drwxrwxr-x 3 jose jose 4,0K Abr 16 21:07 ..
-rw-rw-r-- 1 jose jose  662 Abr 16 21:07 backup.20180416.log
jose@rejane:~/backupciscorouters/logs$ 

jose@rejane:~/backupciscorouters/logs$ more backup.20180416.log 
21:07:32,282 root INFO Inicio
21:07:32,283 root INFO 2018-04-16 210732
21:07:32,331 paramiko.transport INFO Connected (version 2.0, client Cisco-1.25)
21:07:32,623 paramiko.transport INFO Authentication (password) successful!
21:07:37,800 paramiko.transport INFO Connected (version 2.0, client Cisco-1.25)
21:07:38,75 paramiko.transport INFO Authentication (password) successful!
21:07:43,194 root INFO Erro de conexao ao roteador 3.3.3.3
21:07:43,221 paramiko.transport INFO Connected (version 2.0, client Cisco-1.25)
21:07:43,490 paramiko.transport INFO Authentication (password) successful!
21:07:48,620 root INFO Fim
21:07:48,621 root INFO 2018-04-16 210748
jose@rejane:~/backupciscorouters/logs$ 

O arquivo log ficou OK também. E ele nos informa da falha na conexão ao roteador 3.3.3.3.

Podemos utilizar multiprocess para executar várias sessões SSH em paralelo, ou se por exemplo se minha rede tiver 20 roteadores, posso utilizar 4 scripts cada um rodando para 5 roteadores, e fazer o agendamento na cron do Linux.

Por hoje é isso pessoal, próximos posts vamos continuar com mais automatização e exemplos.

Abcs
Jose

Nenhum comentário:

Postar um comentário