Script para automatización en configuración de Router Cisco Catalyst 3640

Page 1

Universidad Tecnológica de León Ingeniería en Redes Inteligentes y Ciberseguridad

Asignatura: Automatización de Infraestructura Digital I

Profesor: José Luis Alejandro Hernández Ramírez

Título del trabajo: Script para automatización en configuración de Router Cisco Catalyst 3640

Presenta: Fátima Abigail Porras Noriega

Matrícula: 18002125

Grupo: IRIC 901

León, Guanajuato. A 20 de agosto de 2021


INTRODUCCIÓN Con todo lo aprendido en el curso, y hasta el momento, se puede hablar de la gran utilidad la implementación de sistemas de automatización en la red. Esto se refiere al simple hecho de usar programas informáticos para configurar, administrar y/o obtener información de distintos dispositivos en la red. Anteriormente, la llegada de protocolos como Telnet y SSH, facilitaron las tareas de administración de los dispositivos mediante conexiones remotas que dan una sensación de estar interactuando directamente sin preocuparse por las limitaciones geográficas, aunque esto tenía una limitante, el uso de consolas de comandos en las cuales es fácil cometer errores de dedo que podrían estropear la configuración del equipo, para este tipo de situaciones, algunos años más tarde, se implementaron interfaces gráficas de administración en algunos dispositivos de red, para facilitarle a los administradores la lectura de la información y reducir la probabilidad de error al cometer una acción o ingresar algún dato. Hoy en día, algunos usuarios prefieren interfaces gráficas y algunos otros siguen prefiriendo utilizar líneas de comandos, y ambas son muy diferentes al momento de llevar a cabo alguna operación, pero en un entorno productivo y de alta demanda, ¿cuál es la mejor opción? Realmente ninguna, ya que en la actualidad en la que vivimos, un entorno de alta demanda de red es demasiado para un simple administrador que tiene que configurar todo manualmente y tiene una alta probabilidad de cometer algún error. La opción por la que muchos profesionales optan es la de automatizar la red, es decir, crear programas que permitan la administración de equipos de red de una manera más eficiente, rápida y sin riesgo de cometer errores. En este reporte se presenta una práctica realizada para crear un script de automatización a un router Cisco Catalyst 3640, el cual permite configurar de manera casi instantánea una interfaz de red, mientras se almacenan las credenciales de acceso al dispositivo en una base de datos que puede consultarse en cualquier momento y llevar todas las acciones necesaria para mantener la información actualizada al día. Esta práctica se compone de distintas fases y en cada una de ellas se explica el código desarrollado.


PARCIAL LLL: SCRIPT PARA AUT OMAT IZACIÓN EN CONFIGURACIÓN DE ROUTER CISCO CATALYST 3640 Creación del entorno de trabajo Creación de los directorios Para una mejor organización en el desarrollo de este proyecto, todos los archivos, módulos y componentes que lo hacen funcionar se guardaron en una directorio específico, donde se almacenaron todos los módulos, bases de datos y plantillas. Una vez creada la carpeta del proyecto, se añadió una carpeta dentro de esta llamada “modelo”, para almacenar el modelo de conexión a los equipos y la base de datos de SQLite, de manera en que quedó una estructura de la siguiente manera: Proyecto parcial 3 └─── modelo

Creación de la base de datos Una de las capacidades del proyecto es que tuviera la capacidad de almacenar los datos de conexión de cada uno de los dispositivos para su administración, es decir, su dirección IP, modelo, credenciales SSH, hostname, entre otras, para hacer esto posible se creó una base de datos administrada por el motor de SQLite. Con la ayuda de SQLiteStudio como gestor de base de datos, se creó la base de datos llamada equipos y a esta se le agregó una nueva tabla con el nombre configuracion con las siguientes columnas y tipos de dato:

Esta base de datos se guardó en el directorio modelo, de manera que la estructura de los archivos quedó: Proyecto parcial 3 └───modelo equipos.db

Creación del módulo de conexión a la base de datos Dentro del directorio modelo se creó el módulo para hacer todas las interacciones a la base de datos, este fue nombrado mod_equipos.py y hasta el momento se dejó como vacío. Por otra parte, el script principal sería ejecutado desde el directorio raíz del proyecto, por lo que fue necesario agregar al directorio modelo el archivo __init__.py para que el script principal pudiera detectar este directorio como un paquete y pudiera acceder a los módulos:


Proyecto parcial 3 └───modelo equipos.db mod_equipos.py __init__.py

Desarrollo del módulo de conexión (mod_equipos.py) Como fue mencionado anteriormente, el módulo de conexión sería el encargado de hacer todas las interacciones con la base de datos, es decir, un CRUD completo y otras utilidades como la verificación de registros existentes y la aplicación de distintos filtros de búsqueda. Carga de módulos Se hizo la carga correspondiente de los módulos utilizados para las interacciones con la base de datos, en este caso se utilizó sqlite3 y os que ya vienen preinstalados en las versiones más nuevas de Python 3.

import sqlite3 import os Creación de la clase Dentro del mismo archivo, se creó la clase conexion_equipos.

class conexion_equipos: pass Constructor La intención del script, es que una vez que se cree el objeto de conexión, se hiciera la conexión directa con la base de datos y se crearan los cursores y objetos para ejecutar los scripts SQL en la base de datos.

def __init__(self): try: dbpath ='equipos.db' path = os.path.dirname(os.path.abspath(__file__)) print(path) db = os.path.join(path, dbpath) self.conn = sqlite3.connect(db) self.conexion = sqlite3.connect(db) self.cursor = self.conexion.cursor() print('ok') except Exception as Error: print(Error)


Se puede apreciar que se hace la llamada a la base de datos y se imprime un mensaje de ok indicando que la conexión fue satisfactoria, asimismo, se imprime un mensaje de error en caso de que una de las acciones del constructor no se ejecute como se espera. Función Insertar Para la función insertar de esta clase, se reciben como parámetro una tupla o una lista, las cuales contienen la información a agregar y en orden con respecto al nombre del equipo, modelo, número de serie, dirección IP, usuario, y contraseña de acceso y contraseña para modo privilegiado. Al ejecutar la consulta con éxito, se retornan dos valores, un True y un mensaje de que el registro se ha agregado con éxito.

def insertar(self,tupla): try: sql = "INSERT INTO configuracion(nombre,modelo,serie,ip,usuario,password,s ecret) VALUES (?,?,?,?,?,?,?);" self.cursor.execute(sql,tupla) self.conexion.commit() return True, 'Registro agregado con éxito' except Exception as Error: return False, 'No se ha podido agregar el registro' Función Eliminar La función de eliminar tiene el mismo principio, a diferencia de que solo se envía como parámetro el id del registro, se ejecuta la consulta desde el cursor y se verifica que realmente exista algo que borrar (un registro con el id ingresado) y finalmente se envía un mensaje de que el registro se ha podido eliminar en caso de que si haya una coincidencia con los registros o un mensaje de error en caso de que no exista.

def borrar (self, id): try: sql = 'DELETE FROM configuracion WHERE id = ?' num = self.cursor.execute(sql,id).rowcount if num >= 1: self.conexion.commit() return f'Se ha eliminado el registro con ID: {id}' else: return f'No se ha encontrado ningun registro con ID: {id}' except Exception as Error: return Error


Función Modificar En esta función se recibe como parámetro la tupla o lista que contiene los datos a actualizar, como en la función de insertar, a diferencia de que en esta se tiene que agregar el número de id al final. Una vez que se ejecuta el script correctamente, se retorna un mensaje al usuario diciendo que se ejecutó de manera satisfactoria la modificación del registro, o en caso contrario, el mensaje de error correspondiente.

def modificar(self,tupla): try: sql = 'UPDATE configuracion SET nombre=?, modelo = ?, serie = ?, ip = ?, u suario = ?, password = ?, secret = ? WHERE id = ?' self.cursor.execute(sql,tupla) self.conexion.commit() return 'Se ha agregado ha hecho la modificación en le registro' except Exception as Error: return Error Función Mostrar Todos Esta función no lleva ningún parámetro ya que solamente se encarga de regresar como resultado una lista con el contenido de todos los registros, en caso de que no sea posible, se retorna un objeto de error.

def mostrar_todos(self): try: sql = 'SELECT * FROM configuracion' self.cursor.execute(sql) self.conexion.commit() return self.cursor.fetchall() except Exception as Error: return Error Función Mostrar por ID De la misma forma que en la función de eliminar, esta función recibe como parámetro únicamente el id del objeto a eliminar y se retorna una lista con el registro o un mensaje de error en caso de que falle.

def mostrar(self,id): try: sql = 'SELECT * FROM configuracion WHERE id = ?' self.cursor.execute(sql,id) self.conexion.commit() return self.cursor.fetchall()


except Exception as Error: return Error Función Borrar Todos Esta función se debe ejecutar con especial cuidado, ya que no requiere ningún parámetro y se encarga de borrar todos los registros existentes en la base de datos.

def borrarTodos (self): try: sql = 'DELETE FROM configuracion' num = self.cursor.execute(sql).rowcount if num >= 1: self.conexion.commit() return f'Se han eliminado todos los registros' else: return f'No se han podido eliminar los registros' except Exception as Error: return Error Función Registro Existe Una función muy sencilla pero muy útil al utilizarse en conjunto con otras, ya que se encarga de regresar un True o False según sea posible encontrar un registro existente en la base de datos recibiendo el id como parámetro.

def registroExiste(self, id): try: sql = 'SELECT * FROM configuracion WHERE id = ?' self.cursor.execute(sql,id) num = len(self.cursor.fetchall()) if num >= 1: self.conexion.commit() return True else: return False except Exception as Error: return Error

Desarrollo del script principal (conexion.py) Ya teniendo el módulo finalizado, se creó el archivo principal para hacer todos los menús e interaccionar de una manera más amigable con la base de datos, aunque solo sean menús sencillos a través de la línea de comandos, el archivo fue nombrado conexion.py.


└───Proyecto parcial 3 │ conexion.py │ └───modelo │ equipos.db │ mod_equipos.py │ __init__.py │ └───__pycache__ mod_equipos.cpython-39.pyc __init__.cpython-39.pyc

Los módulos importados para este script fueron los siguientes:

from os import set_inheritable import modelo.mod_equipos as mod_eq from tabulate import tabulate import yaml from jinja2 import FileSystemLoader, Environment import napalm import os from pathlib import Path

Después, se procedió a crear un objeto para su utilización de manera global, este objeto es de tipo mod_equipos (de la clase que se creó con anterioridad).

md_eq = mod_eq.conexion_equipos()

Definición de los menús El menú interactivo por programar quedó definido de la siguiente manera: •

ADMINISTRAR EQUIPOS: Desde este menú se selecciona uno de los equipos y se hace una conexión SSH para administrarlo. o

Hostname: Se imprime en pantalla el nombre de host.

o

Usuario: Se imprime el usuario activo en la sesión SSH.

o

Password: Se imprimen los hashes de las contraseñas de los usuarios.

o

Usuarios: Se imprime en pantalla los usuarios existentes en el dispositivo.

o

Interfaces: Se imprime la información de las interfaces activas en el dispositivo.

o

Aplicar Configuración: Se ejecuta un script para aplicar la configuración almacenada en los archivos de configuración .yaml.

o •

Menú Anterior: Permite al usuario regresar al menú principal.

CONFIGURAR EQUIPOS: Este menú permite configurar los datos almacenados de cada dispositivo en la base de datos. o

Agregar Registro: Permite al usuario agregar un nuevo registro de dispositivo.

o

Eliminar Registro: Permite al usuario eliminar de manera permanente un registro.


o

Eliminar Todos: Permite al usuario eliminar de manera permanente todos los registro.

o

Mostrar Registro: Permite al usuario localizar un registro ingresando un id.

o

Mostrar Todos: Se muestran en pantalla todos los registros existentes.

o

Menú anterior: Permite al usuario regresar al menú principal.

SALIR: Se finaliza la ejecución del script.

Creación del menú principal Aparentemente programar la configuración entre los menús es bastante sencillo. Se empezó creando el menú principal, el cual únicamente consta de tres opciones.

def mostrarMenuPrincipal(): #MENU PRINCIPAL menu = """ 1) ADMINISTRAR EQUIPOS 2) CONFIGURAR EQUIPOS 3) SALIR """ while True: print(menu) op = input(">") if op == '1': mostrarMenuAdministracion() elif op == '2': mostrarMenuConfiguracion() elif op == '3': break else: print("Opción no válida, intente de nuevo por favor")

Se puede apreciar que hay una serie de tres condiciones, las cuales corresponden a las funciones de mostrar los menús de administración y configuración (se mostrarán estos menús más adelante), además de un botón para salir y una última condicional en caso de que el usuario ingrese un dato erróneo. Para ejecutar este menú de manera automática al iniciar el script, simplemente se agregaron las siguientes líneas por debajo y fuera de esta función para llamarla:

if __name__ == '__main__': mostrarMenuPrincipal()

Al ejecutar el script, se pudo apreciar correctamente el menú principal.


Creación del menú de configuración (Opción 2) Se decidió empezar con el menú de la opción 2 ya que este solamente se encarga de interactuar con la base de datos, que hasta el momento, es la única parte que se tiene preparada. De manera similar al menú principal, la selección del usuario varía por una serie de condicionales que le permite ir entre distintas funciones como agregar registros, eliminar, modificar, mostrar y salir al menú anterior. Todas las funciones llamadas desde este menú se encuentran dentro de una función print() ya que cada una de estas devuelven un mensaje respecto al estatus de la ejecución, es decir, el script es capaz de indicar si la tarea fue ejecutada correctamente o no, y en ese caso, qué es lo que salió mal.

def mostrarMenuConfiguracion(): menu = """ 1) AGREGAR REGISTRO 2) ELIMINAR REGISTRO 3) ELIMINAR TODOS 4) MODIFICAR REGISTRO 5) MOSTRAR REGISTRO 6) MOSTRAR TODOS 7) SALIR """ while True: print(menu) op = input(">") if op == '1': print(capturarRegistro()) elif op == '2': print(borrarRegistro()) elif op == '3': print(borrarTodos()) elif op == '4': print(modificarRegistro()) elif op == '5': print(buscarRegistro()) elif op == '6': print(mostrarRegistros()) elif op == '7': break else: print('Opción incorrecta, intente de nuevo')

Creación del menú de Administración (Opción 1)


Este menú fue igual de sencillo, pero fue el ultimo en realizarse ya que hasta el momento no se ha creado nada para hacerlo funcionar, más adelante se mostrarán los pasos necesarios para hacer funcionar cada menú. Cuando se selecciona esta opción, lo primero que se le pide al usuario, es seleccionar uno de los dispositivos de la base de datos para hacer su conexión correspondiente. Este menú es un poco más complejo, ya que a partir de la selección, se manda un objeto como parámetro para abrir la función que muestra las opciones del menú, y en caso de que el usuario escriba una opción que no corresponde, el script se lo indica y le pide ingresar nuevamente un id correcto o presionar x para cancelar.

def mostrarMenuAdministracion(): print(mostrarRegistros()) registro = None seleccion = input("Seleccione un dispositivo a administrar: ") while True: if md_eq.registroExiste(seleccion): headers = ['NOMBRE','MODELO','SERIE','IP','USUARIO','PASSWORD','SECRET'] registro = md_eq.mostrar(seleccion) #ya se puede crear el objeto y ver las propiedades print(type(registro)) datosDispositivo = registro[0] equipo = Equipos() equipo.setNombre(datosDispositivo[1]) equipo.setModelo(datosDispositivo[2]) equipo.setSerie(datosDispositivo[3]) equipo.setIP(datosDispositivo[4]) equipo.setUsuario(datosDispositivo[5]) equipo.setPassword(datosDispositivo[6]) equipo.setSecret(datosDispositivo[7]) equipo.conexion() mostrarMenuEquipo(equipo) else: seleccion = input("No se ha encontrado registro con ese ID, ingrese un ID válido o presione X para cancelar:" ) if seleccion == 'x' or seleccion == 'X': break

Se puede apreciar que se crea un objeto Equipos (el cual será explicado más adelante) y se manda como parámetro de la función del menú, en el cual se puede acceder a distintos atributos del dispositivo una vez que se haya realizado la conexión y además de que se pueden aplicar las configuraciones deseadas.


def mostrarMenuEquipo(registro): while True: print('1) HOSTNAME\n' \ '2) USUARIO\n' \ '3) PASSWORD\n' \ '4) USUARIOS\n' \ '5) INTERFACES\n' \ '6) APLICAR CONFIGURACION\n' \ '7) MENU ANTERIOR\n') op_m3 = int(input('ELIGE OPCION: ')) if op_m3 == 7: break elif op_m3 == 1: print(registro.hostname()) elif op_m3 == 2: print(registro.user()) elif op_m3 == 3: print(registro.clave()) elif op_m3 == 4: print(registro.get_usuarios()) elif op_m3 == 5: print(registro.get_interfaces()) elif op_m3 == 6: print(registro.set_configuracion()) else: print('¡OPCION NO VALIDA!\n')

Funciones del menú de configuración Capturar registro La primera opción del menú de configuración de equipos es la de capturar un registro nuevo. Cuando se manda a llamar a esta función se crea una lista con una lista de encabezados de la tabla y se crea una lista vacía con el nombre de tupla. En un ciclo for se recorre la lista y se pide al usuario que ingrese cada uno de estos datos, si el usuario ingresa un valor nulo, el script le pedirá ingresar de nuevo un valor para el campo correspondiente. Finalmente se manda a llamar a la función insertar del modelo de conexión y se manda como parámetro la tupla recién creada. Una vez terminada esta operación, se muestra un mensaje de que se ha agregado de manera satisfactoria el registro.

def capturarRegistro(): headers = ['NOMBRE','MODELO','SERIE','IP','USUARIO','PASSWORD','SECRET'] tupla = [] for clave in headers: while True:


campo = input(clave + ':') if len (campo) > 0: tupla.append(campo) break else: print("VALOR PUEDE SER NULO") md_eq.insertar(tupla) return "Registro agregado" Realizando la prueba de ejecución de esta opción, se pudo observar que se ejecutó correctamente.

Incluso, echando un vistazo en la base de datos, los registros se muestran agregados correctamente, después de agregar un par de estos, la base de datos quedó de la siguiente manera.

Mostrar registros Una vez teniendo registros en la base de datos, se hizo la opción número seis del menú, la que se encarga de mostrar todos los registros. En esta función se hace uso del módulo tabulate para mostrar los registros de la base de datos en un formato de tabla.

def mostrarRegistros(): headers = ['ID','NOMBRE','MODELO','SERIE','IP','USUARIO','PASSWORD','SECRET'] registros = md_eq.mostrar_todos() registros.insert(0,headers) return tabulate(registros,headers='firstrow',tablefmt='fancy_grid')

Se ejecutó la función para comprobar que realmente muestra la información requerida.


Buscar registro Similar a la anterior, esta función se encarga de mostrar en la pantalla el registro con el id ingresado. Esta función le pide al usuario ingresar un número de usuario y se comprueba si este registro existe con la función registroExiste() del módulo de equipos. En caso de que se encuentre, se mostrará la información, en caso de que no, se le indica al usuario que capture un id válido o presione x para cancelar la operación.

def buscarRegistro(): seleccion = input("Seleccione el registro que desea ver: ") while True: if md_eq.registroExiste(seleccion): headers = ['NOMBRE','MODELO','SERIE','IP','USUARIO','PASSWORD','SECRET'] registros = md_eq.mostrar(seleccion) registros.insert(0,headers) return tabulate(registros,headers='firstrow',tablefmt='fancy_grid') else: seleccion = input("No se ha encontrado registro con ese ID, ingrese un ID válido o presione X para cancelar:" ) if seleccion == 'x' or seleccion == 'X': break Se comprobó que la función hiciera el trabajo de manera correcta ingresando un id existente.


Y también con un id no disponible.

Modificar registro La función para modificar uno de los registros muestra un listado de los existentes y pide al usuario ingresar un número de id, el cual, en caso de no ser encontrado, pedirá ingresarlo de nuevo o presionar x para salir. En caso de que se haya encontrado el registro, se inicia un proceso de captura que se almacena en una lista, al final se le agrega el id para ejecutar la función de modificar del módulo de conexión.

def modificarRegistro(): print(mostrarRegistros()) seleccion = input("Seleccione el registro que desea modificar: ") while True: if md_eq.registroExiste(seleccion): headers = ['NOMBRE','MODELO','SERIE','IP','USUARIO','PASSWORD','SECRET'] tupla = [] for clave in headers: while True: campo = input(clave + ':') if len (campo) > 0: tupla.append(campo) break else: print("VALOR PUEDE SER NULO") tupla.append(seleccion) return md_eq.modificar(tupla) else:


seleccion = input("No se ha encontrado registro con ese ID, ingrese un ID válido o presione X para cancelar:" ) if seleccion == 'x' or seleccion == 'X': break return "Registro agregado"

Se realizó la prueba utilizando uno de los registros y se comprobó que se haya modificado la información.

Al ejecutar la opción para buscar un registro, se pudo verificar que el registro modificado se guardó satisfactoria mente.

Eliminar los registros Cuando se borra un registro en específico, se muestra la lista de dispositivos y se pide al usuario que ingrese un id válido, después se le pide una confirmación ingresando una letra S o s. Una vez que confirma la acción se llama a la función borrar del módulo de conexión. En caso de que se ingrese una N o n en la configuración, se muestra en pantalla que la acción ha sido cancelada por el usuario.

def borrarRegistro(): registros = mostrarRegistros() print(registros) seleccion = input('Seleccione el registro a eliminar: ')


while True: confirmacion = input('Está seguro de que desea continuar? (S/N): ') if confirmacion == 's' or confirmacion == 'S': return md_eq.borrar(seleccion) break elif confirmacion == 'n' or confirmacion == 'N': print('Accion cancelada por el usuario') break else: 'Respuesta no valida, por favor intente de nuevo.'

Probando la función, se pudo confirmar que el registro se ha eliminado de manera satisfactoria.

Eliminar todos los registros Esta función es un poco más sencilla que la anterior, ya que únicamente muestra en una tabla los registros existentes y pide la confirmación del usuario para ejecutar la función borrarTodos del módulo de conexión. Y se mandan notificaciones en caso de que la acción haya sido ejecutada de manera correcta o se haya cancelado.

def borrarTodos(): registros = mostrarRegistros() print(registros) while True: confirmacion = input('Está seguro de que desea eliminar todos los registros? ( S/N): ') if confirmacion == 's' or confirmacion == 'S': return md_eq.borrarTodos() elif confirmacion == 'n' or confirmacion == 'N': return 'Accion cancelada por el usuario' else: 'Respuesta no valida, por favor intente de nuevo.'


Funciones para la administración de equipos (opción 2) Hasta este punto es posible agregar, consultar, eliminar y modificar registros a la base de datos. El siguiente paso es hacer interacciones con un dispositivo mediante su conexión por SSH, para esto, se han realizado un serie de pasos para preparar el entorno de trabajo y tener un proyecto ordenado. El menú de administración le permite al usuario consultar distintos datos del equipo seleccionado y le permite aplicar de manera automática una serie de configuraciones a las interfaces de red configuradas a través de un archivo de texto. Archivos de configuración Cuando se realiza una conexión con un equipo, una de las opciones que se tienen es la de aplicar las configuraciones de las interfaces, por lo que para esto, es necesario crear unos archivos que son necesarios para aplicar las configuraciones. Previamente se creó una carpeta para almacenar todos estos con el nombre de plantillas. Proyecto parcial 3 │ conexion.py │ ├───modelo │ │ equipos.db │ │ mod_equipos.py │ │ __init__.py │ │ │ └───__pycache__ │ mod_equipos.cpython-39.pyc │ __init__.cpython-39.pyc │ └───plantillas

En este directorio deben existir dos tipos de archivos, el primero es la plantilla de configuración y el segundo es el archivo de configuración que contiene la información de la configuración a aplicar a cada dispositivo. En el caso de la plantilla, este archivo se nombró como cisco_template.j2, las principales características de este es que contiene todos los comandos en una plantilla para aplicar la configuración correspondiente a una o más interfaces del router a configurar. Solamente es requerida una copia de este archivo y su contenido es el siguiente.

{% for if_name,if_data in interfaces.items() %} interface {{if_name}} description {{if_data.description}} ip address {{if_data.ipv4_addr}} {{if_data.ipv4_mask}} no shutdown {% endfor %}

En el caso de los archivos de configuración, estos contienen la información de los parámetros a aplicar en las interfaces indicadas por este. Para este archivo, debe existir uno por cada dispositivo que se desea configurar y debe ser nombrado con el número de serie del router añadiendo _template con la extensión yml. Para esta


práctica el archivo de configuración utilizado se nombró FF1045C5_template.yml; y el contenido de este son las interfaces a configurar, especificando su nombre, descripción, dirección IPv4 y máscara de subred.

interfaces: FastEthernet1/0: description: "Conexion to WAN" ipv4_addr: 172.16.0.1 ipv4_mask: 255.255.255.0

Al crear ambos archivos, la estructura del directorio del proyecto, quedó: Proyecto parcial 3 │ conexion.py │ ├───modelo │ │ equipos.db │ │ mod_equipos.py │ │ __init__.py │ │ │ └───__pycache__ │ mod_equipos.cpython-39.pyc │ __init__.cpython-39.pyc │ └───plantillas cisco_template.j2 FF1045C5_template.yml

Creación de la clase equipos Dentro del script principal se creó una clase llamada Equipos para facilitar la administración de cada uno, el primer paso después de crearla fue agregar los métodos necesarios para obtener información de sus atributos y establecerla (setters y getters).

class Equipos: def __init__(self): pass def setNombre(self,nombre): self.nombre = nombre def setModelo(self,modelo): self.modelo = modelo def setSerie(self,serie): self.serie = serie def setIP(self,ip): self.ip = ip


def setUsuario(self,usuario): self.usuario = usuario def setPassword(self,password): self.password = password def setSecret(self, secret): self.secret = secret def getNombre(self): return self.nombre def getModelo(self): return self.modelo def getSerie(self): return self.serie def getIP(self): return self.ip def getUsuario(self): return self.usuario def getPassword(self): return self.password def getSecret(self): return self.secret

Conexión al dispositivo Se creó un método para conectar al dispositivo Se creó un método en la clase para conectar al dispositivo, este se apoya del módulo napalm para la administración de dispositivos. Como se puede observar en el script, solo es necesario declarar un diccionario con la información de las credenciales de acceso, dirección y puerto, declarar un tipo de controlador (el tipo de sistema para el dispositivo) y cargar la información para abrir la conexión.

def conexion(self): CONFIG = { 'hostname': self.ip, 'username': self.usuario, 'password': self.password, 'optional_args': {'port':22,'secret': self.secret}


} self.driver_ios = napalm.get_network_driver("ios") self.device = self.driver_ios(**CONFIG) self.device.open() Obtener información del dispositivo Una de las ventajas al usar napalm para la conexión a routers, es la facilidad que da para obtener la información de estos, ya que se encarga de retornar la información en un mismo formato, ya sean cadenas de texto o diccionarios sin importar el modelo o fabricante del dispositivo. Como es posible observar, atributos como el nombre de host, contraseña y usuario actual se regresan en una cadena de texto, mientras que se puede obtener información de todas las interfaces o usuarios mediante un diccionario.

def hostname(self): return self.device.hostname def clave(self): return self.device.password def user(self): return self.device.username def get_usuarios(self): usuarios = self.device.get_users() for key,valores in usuarios.items(): print('usuario: ' + key) for k,v in valores.items(): print(' ' + k + str(v)) def get_interfaces(self): interfaces = self.device.get_interfaces() for key,valores in interfaces.items(): print('interface: ' + key) for k,v in valores.items(): print(' ' + k + str(v))

Aplicar configuración Este ultimo método se encarga de cargar el archivo de configuración basándose en su número de serie, la plantilla de configuración definida, y utilizando este último se crea la configuración final renderizando la información del archivo de configuración del dispositivo, para que finalmente se cargue y se envíen al dispositivo.


def set_configuracion(self): archivo = 'plantillas\\'+'{}_template.yml'.format(self.serie) script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in rel_path = archivo abs_file_path = os.path.join(script_dir, rel_path) print(abs_file_path) obj_arch = Path(abs_file_path) config_data = yaml.load(open(obj_arch), Loader=yaml.FullLoader) a_cargar = FileSystemLoader('plantillas') env = Environment(loader=a_cargar) template = env.get_template('cisco_template.j2') print(template.render(config_data)) renderizado = template.render(config_data) self.device.load_merge_candidate(filename=None, config=renderizado) self.device.commit_config()

Pruebas en la administración Para realizar las pruebas en el menú de administración se utilizó un router Cisco Catalyst 3640 con la preferencias de fábrica y se le agregaron las siguientes configuraciones en modo de configuración global:

username cisco privilege 15 secret cisco enable secret class ip scp server enable ip ssh version 2 ip ssh time-out 120 ip domain name utl.edu crypto key generate rsa 1024 line vty 0 871 login local int fast0/0 ip address dhcp no shut

Se consideró para esta práctica, que la configuración del router, ya se encontraba almacenada en la base de datos con los registros anteriormente agregados, por lo que no fue necesario agregar ningún otro. Se inició el script y se seleccionó la opción de Administrar Equipos.


Se seleccionó el id del equipo a administrar y una vez hecho esto, se inició el proceso de conexión, el cual tomó menos de 4 segundos para mostrar el siguiente menú.

Este menú sirve para listar algunos de los atributos del router (el código se encuentra en el diseño de los menús).

Aplicar configuración


La última opción es la de aplicar la configuración existente en las plantillas para el dispositivo. Al seleccionar esta, solamente tomó de unos pocos segundos para ver los cambios reflejados en el router.


CONCLUSIÓN En este reporte se explicó a manera general cómo desarrollar un script para configurar las interfaces de red de un dispositivo Cisco Catalyst 3460. Se explicaron los modelo de conexión a base de datos utilizando el motor SQLite y desarrollando un CRUD completo para la administración de las credenciales de acceso por SSH a los dispositivos a configurar, para que finalmente se hiciera la conexión y se pudiera obtener información existente en cada uno de los dispositivos y aplicar la configuración deseada en cuestión de segundos. En esta práctica se reunieron los conocimientos obtenidos durante el cuatrimestre, donde se demuestra la importancia y gran ventaja competitiva de automatizar los ajustes en la red y las posibilidades que ofrecen a los administradores de la red, pues hay una mayor eficiencia en el tiempo, se interrumpe menos el servicio y hay una probabilidad mucho menor de cometer algún error. Considero personalmente, que en este tipo de tópicos, hay bastante información, porque ahora, también los fabricantes tienen sus propias soluciones para automatizar la red, por lo que es entonces, responsabilidad de cada uno de nosotros, aprender de las novedades y tendencias en el mercado para desarrollar la mejor estrategia para administrar la red de la que seamos responsables, así mismo, también debemos ser responsables de adaptarnos al cambio y a ver nuevas posibilidades para problemas actuales y nuevos, pues de esta manera se demuestra una mentalidad fresca y dispuesta a seguir aprendiendo.


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.