Cet article est l'article du 14ème jour du Calendrier de l'Avent NIFTY 2016. Hier, c'était @ntoofu's Manage Ansible configuration information with graph DB.
Bonjour. Dans mon travail quotidien, je construis, exploite et entretiens l'infrastructure réseau de Nifty Cloud. Cette fois, je voudrais écrire un peu sur l'automatisation du fonctionnement des appareils physiques dans le réseau, qui ne peut pas être vue du côté service de Nifty Cloud.
-Le redémarrage de l'appareil a été exécuté
-L'interface de l'appareil est tombée en panne
-Le module a échoué
-Quoi qu'il en soit, quelque chose ne va pas
Il arrive souvent que quelque chose comme ... se produise et que vous souhaitiez vérifier immédiatement l'état de l'appareil. Dans ces cas, connectez-vous à l'appareil (tant qu'il est toujours accessible) et Il est nécessaire d'appuyer rapidement sur les commandes show pour sécuriser les informations.
On peut dire que les commandes à ce moment-là sont normalisées dans une certaine mesure. (Ce qui suit est une liste que vous pouvez lister ces commandes quel que soit le périphérique / système d'exploitation spécifique)
show running-config
show interfaces
show logging
show inventory
show modules
show tech-support
···Tel. Par exemple, pour les périphériques réseau et les systèmes d'exploitation tels que Cisco IOS, vous pouvez vérifier les informations de configuration et l'état en entrant la commande ci-dessus.
Surtout dans une situation très urgente telle qu'une panne J'aimerais faire un travail de routine avec le moins d'intervention humaine possible afin de consacrer du temps à l'enquête.
Dans cet article, afin d'obtenir rapidement le résultat de la commande ci-dessus Je vais présenter l'histoire de l'implémentation d'un script en Python qui se connecte automatiquement à l'appareil, entre les commandes et acquiert la sortie.
En général, nous pensons que les opérations pour les périphériques réseau peuvent être divisées en trois types.
--Vérifier les paramètres Entrez des commandes pour vérifier l'état et les paramètres du périphérique, comme la commande show mentionnée ci-dessus.
--Modifier les paramètres Commandes d'entrée pour modifier l'état / les paramètres du périphérique tels que le mode de configuration, la validation et l'écriture
--Surveillance de l'état Surveillance du débit de trafic par SNMP, acquisition de Syslog
En particulier, cet article se concentre sur la vérification des paramètres.
Comme indiqué dans l'article introduit dans la section de référence, Parmi les méthodes de fonctionnement pour les périphériques réseau, le fonctionnement général est par CLI. Le flux de trafic, etc. peut être obtenu par SNMP, mais les types d'informations sont limités. Des API peuvent être implémentées, mais elles varient d'un fabricant à l'autre.
Tous les périphériques sont basés sur le fonctionnement de la CLI, c'est-à-dire que le fonctionnement après la connexion avec ssh ou telnet est la méthode de fonctionnement des périphériques réseau à usage général.
En d'autres termes, automatiser ces opérations signifie Cela signifie que les opérations suivantes que les humains exécutent normalement sur l'interface de ligne de commande sont exécutées par le script.
$ telnet 192.168.0.2
Trying 192.168.0.2...
Connected to 192.168.0.2 (192.168.0.2).
Escape character is '^]'.
User Access Verification
Username: root
Password:
(hostname)#show run
...production
(hostname)#
Je vais expliquer le contenu du script.
Utilisation du module pexpect en Python3 Implémente une opération de proxy pour l'interface CLI par expect.
Tout d'abord, utilisez pexpect.spawn () pour lancer un processus enfant. Le processus enfant est nommé ici enfant et le processus se poursuit par la suite pour l'enfant. Dans l'argument de spawn, il est nécessaire de spécifier le processus à démarrer dans l'instruction de commande, et ici c'est telnet.
En plaçant le descripteur de fichier du fichier journal dans la variable child.logfile_read, Vous pouvez spécifier la destination de sortie du processus enfant lancé dans un fichier. Vous pouvez également affecter la sortie standard (sys.stdout) à cette variable et voir la sortie sur la console.
def login(ipaddr, passwd):
child = pexpect.spawn("telnet " + ipaddr)
logname = "./log/" + "log_" + ipaddr + \
"_" + datetime.now().strftime("%s") + ".log"
wb = open(logname, 'wb')
child.logfile_read = wb
Traitement utilisant expect, non limité à pexpect,
1. sendline()Envoyer la commande par
2. expect()En attente de la sortie de la chaîne de caractères attendue par
Sera répété. Dans le cas de pexpect, la chaîne de caractères à attendre peut être spécifiée dans la liste, et ici elle est spécifiée comme suit en fonction de la chaîne de caractères attendue.
expect_list = [u"#",
u">",
u"\nlogin: ",
u"Username: ",
u"Password: ",
u"Connection closed by foreign host.",
u"Login incorrect"]
Lorsque vous exécutez pexpect.spawn (telnet [adresseip]), telnet est en cours d'exécution sur le périphérique et le périphérique attend l'entrée suivante. Autrement dit, lorsqu'il est exécuté manuellement, l'état de l'image est le suivant.
$ telnet 192.168.0.2
Trying 192.168.0.2...
Connected to 192.168.0.2 (192.168.0.2).
Escape character is '^]'.
User Access Verification
Username: [Cursor]
Maintenant, exécutez expect comme indiqué ci-dessous.
index = child.expect(expect_list)
A ce moment, l'élément "Username:" stocké dans le troisième de la liste correspond à la dernière ligne de la sortie de l'appareil. Si une liste est spécifiée comme argument dans expect, la valeur de retour sera le numéro d'élément de la liste. Par conséquent, "3" est stocké dans la variable appelée index. S'il n'y a pas de chaîne correspondante, expect () continuera d'attendre plus de sortie du périphérique. Dans ce cas, le traitement ne se termine pas jusqu'à ce qu'il expire, mais il est également possible de mettre en œuvre le traitement des erreurs en attendant le délai à ce moment.
Dans l'implémentation actuelle, le traitement suivant est effectué en fonction de la valeur d'index. Selon l'appareil et le système d'exploitation, votre nom d'utilisateur peut vous être demandé ou votre mot de passe peut vous être demandé soudainement. Même si vous vous connectez avec succès, vous devrez peut-être saisir à nouveau le mot de passe si le périphérique vous demande d'exécuter enable. Puisqu'il y a une limite à la description du traitement individuellement pour ces appareils, la mise en œuvre par while est maintenant calme. Pour tous les appareils et systèmes d'exploitation censés se connecter, vérifiez le déroulement du processus de connexion en cas d'opération manuelle. Il doit être conçu de manière à ce que le branchement et le traitement se déroulent normalement.
while True:
if index == 0: # success to login.
return child
elif index == 1: # need to promoted to enable mode.
child.sendline("enable")
index = child.expect(expect_list)
elif index == 2 or index == 3: # need to input "root".
child.sendline("root")
index = child.expect(expect_list)
elif index == 4: # need to input password.
child.sendline(passwd)
index = child.expect(expect_list)
elif index == 5: # Connection is closed.
print("Unmatched password, or connection is closed.")
return -1
elif index == 6: # incorrect password.
print("\nFault: incorrect password.")
return -1
Dans les exemples jusqu'à présent, index contient 3 comme valeur, il sera donc dans la troisième instruction if en tant que branche. Envoie la chaîne demandée par sendline () comme nom d'utilisateur. (la racine est un exemple) À ce stade, la sortie de l'appareil est manuellement comme suit.
Username: root
Password: [Cursor]
Cela correspond au "Mot de passe:" stocké dans expect_list, et la boucle while va plus loin. De même, le mot de passe est entré dans l'appareil et si l'authentification réussit, la connexion est terminée.
Ici, la connexion est terminée lorsque "#" est reçu. Cela suppose une connexion en mode privilégié comme indiqué ci-dessous, mais il y a place à amélioration car cela peut mal fonctionner selon le système d'exploitation.
Username: root
Password:
(hostname)#
Lorsque la connexion est terminée, l'appareil écoute la commande suivante. Cette fois, en supposant l'entrée de commande de type confirmation (show), j'ai créé la fonction suivante. commandes est une liste, et on suppose que les commandes telles que "show interfaces" sont stockées sous forme de chaîne de caractères pour chaque élément. En particulier, la gestion des erreurs n'est pas implémentée ici.
def exec_command(commands, child):
expect_list = u"#"
for c in commands:
child.sendline(c)
child.expect(expect_list)
Si vous souhaitez entrer une commande de changement de paramètre, vous devez vérifier les paramètres à l'avance et déterminer s'il se trouve dans un état approprié pour entrer la commande que vous êtes sur le point de définir. Et même après la saisie, il est nécessaire de vérifier si les paramètres sont reflétés en toute sécurité et s'il existe d'autres journaux étranges. Les implémenter en mode veille de chaîne comme décrit jusqu'à présent nécessite beaucoup de patience.
Certaines des tâches qui ont été complètement stylisées sont implémentées parce que la sortie peut être attendue. D'un autre côté, puisqu'il s'agit d'un script qui place le contenu assez près du travail réel, je voudrais m'abstenir de le présenter ici.
À propos, pour "child.logfile_read" défini au démarrage du processus enfant, Toute la sortie des commandes exécutées jusqu'à la connexion est écrite. Cette fois, il s'agit d'une implémentation de démonstration, mais après avoir saisi le mot de passe dans le script, Si vous le définissez pour lancer ce script lorsque vous voyez un Syslog particulier, Par exemple, il est possible d'acquérir les paramètres et l'état de l'appareil immédiatement après l'émission d'une erreur de module.
Certaines commandes nécessitent que des informations de maintenance soient générées à l'intérieur de l'appareil et acquises manuellement par FTP, etc. Je voudrais saisir une autre occasion pour faire ces automatisations.
Cette fois, j'ai introduit l'automatisation des opérations CLI à l'aide de pexpect. C'est une manière assez boueuse, mais d'un autre côté, il n'y a pas de périphériques réseau qui ne peuvent pas être exploités avec telnet (?), Donc C'est également une méthode qui peut être utilisée avec n'importe quel appareil si elle est correctement conçue.
Je voudrais parler des API REST fournies par des fabricants spécifiques tels que PyEz de Juniper.
Merci beaucoup.
Demain est un message de @hitsumabushi.
Recommended Posts