[PYTHON] Une histoire qui réduit l'effort de fonctionnement / maintenance

supposition

Le terminal de travail est Windows. Il existe des dizaines de serveurs Unix pour l'exploitation / la maintenance. Le but est de générer les données nécessaires au format CSV sur ce serveur basé sur Unix et de les presser sous Windows. Les langages suivants sont ksh93 et Python

La situation à ce moment-là

Je me suis connecté à chaque serveur, j'ai lancé une commande et j'ai pris les données sous forme de texte. Il ne peut y avoir une telle inefficacité. Je vais l'améliorer!

Amélioration

Premier mouvement

Distribuez un script (ci-après moge.sh) qui convertit les données nécessaires en CSV sur chaque serveur Unix. Cela le raccourcit à quelques minutes par unité. Après avoir exécuté le script sur des dizaines d'unités, récupérez-le avec Filezilla, etc. Alors devenez fou sur Windows. Toujours gênant.

2ème coup

Rendons possible de démarrer des scripts sur tous les serveurs sur un serveur, puis copions-les. Comme ça

kicker.ksh


cat servers.list | while read HOST ; do
    ssh ${HOST} -n /hoge/moge.sh
    scp ${HOST}:/hoge/moge.csv ./data/${HOST}.csv
done

Lorsque vous avez terminé, récupérez tous les CSV d'un avec Filezilla, etc. Mais ** série **, il faut donc ** 1 heure ** pour terminer le script.

3e coup

Puisque ssh est lent, vous devriez le mettre en arrière-plan. C'est pourquoi ça ressemble à ça

kicker2.ksh


cat servers.list | while read HOST ; do
    ssh ${HOST} /hoge/moge.sh &
    PID[${HOST}]=$!
done

while [[ ${#PID[*]} -ne 0 ]] ; do
    for HOST in ${!PID[*]} ; do
        if ! ps -ef | grep -w ${PID[${HOST}]} ; then
            scp ${HOST}:/hoge/moge.csv ./data/${HOST}.csv
            unset PID[${LPAR}]
        fi
    done
    sleep 1
done

Cela n'a pris que quelques minutes, mais après tout, les éléments de type Filezilla sous Windows étaient gênants.

4ème coup

Le langage a été choisi car Python, qui peut créer Excel, est pratique pour bousiller CSV.

kicker3.py



with open("server.lst", "r", encoding='shift-jis') as fd:
    for host in fd:
        proc = subprocess.Popen(["ssh", host, "/hoge/moge.sh"], stdout=DEVNULL, stderr=DEVNULL)
        proclist[proc.pid] = proc

while proclist:
    for pid in list(proclist):
        if proclist[pid].poll() is not None:
            del proc[pid]
            subprocess.Popen(["scp", host + ":/hoge/moge.csv", "./" + host + ".csv"], stdout=DEVNULL, stderr=DEVNULL)
    sleep(1)

Cela fonctionne avec WSL, mais ** s'arrête au milieu ** pour les invites de commande. Cela fonctionne si vous réduisez le contenu de server.list (jusqu'à 5 à 6). Pourquoi?

Extension de 4ème coup

Je n'ai pas du tout compris, donc pour le moment, il vaut mieux l'exécuter de manière asynchrone avec asyncio de Python. Cela peut être bon. Alors j'ai commencé des recherches. Après de nombreux rebondissements, ça ressemble à ça.

kicker4.py


async def _run(host):
    ssh = "ssh %s /hoge/moge.sh" % host
    p = await asyncio.create_subprocess_exec(ssh, stdout=DEVNULL, stderr=DEVNULL)
    await p.wait()
    scp = ["scp", host + ":/hoge/moge.csv", "./" + host + "%s.csv"]
    p = subprocess.run(scp, stdoutDEVNULL, stderr=DEVNULL)

loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)

with open("server.lst", "r", encoding='shift-jis') as fd:
    funcs = asyncio.gather(*[_run(host) for host in fd])

loop.run_until_complete(funcs)

Cela ne fonctionne pas non plus. L'événement ne change pas du tout. Ce que j'ai remarqué ici. ** Déplacez-vous lorsque vous appuyez sur * Entrée * lorsque vous vous arrêtez **. Pourquoi? Y a-t-il un problème avec l'entrée standard?

Solution

La bonne réponse est écrite dans le premier script ksh. Cela est dû à l'option ** "-n" ** de ssh. Dans ksh, read et ssh sont en conflit avec l'entrée standard, j'ai donc pensé que "-n" était nécessaire, donc Je le portais depuis le début. Cependant, Python a une entrée standard autre que ssh. Il semble que le préjugé selon lequel il était normal de ne rien faire était un problème. Il semble que l'entrée standard nécessite un contrôle lors du lancement de plusieurs ssh en arrière-plan. (stdin = subprocess.DEVNULL était inutile) Le fait que cela ait fonctionné avec WSL reste un mystère, mais je ne vais pas l'étudier car je ne l'utilise plus.

Pourquoi j'ai arrêté d'utiliser WSL

Dans mon script Python, j'utilise également openpyxl pour Gonyo Gonyo sous Windows. Si c'est sur WSL, il mange parfois BSOD, donc cela fonctionne à partir de l'invite de commande Il a été réparé comme suit.

Question simple

Pourquoi existe-t-il plusieurs façons de donner des commandes au sous-processus? J'aimerais pouvoir l'unifier.

Recommended Posts

Une histoire qui réduit l'effort de fonctionnement / maintenance
L'histoire de la création d'un package qui accélère le fonctionnement de Juman (Juman ++) & KNP
Une histoire qui a analysé la livraison de Nico Nama.
L'histoire de l'exportation d'un programme
Une histoire qui a trébuché sur un calcul de comparaison
L'histoire de la création d'un site qui répertorie les dates de sortie des livres
L'histoire du traitement A du blackjack (python)
L'histoire de la création d'un module qui ignore le courrier avec python
Une histoire qui visualise le présent de Qiita avec Qiita API + Elasticsearch + Kibana
L'histoire du développement d'une application WEB qui génère automatiquement des copies de capture [MeCab]
L'histoire de la création d'un générateur d'icônes mel
L'histoire de sys.path.append ()
L'histoire de l'adresse IPv6 que je souhaite conserver au minimum
L'histoire de la fabrication d'une boîte qui interconnecte la mémoire AL de Pepper et MQTT
L'histoire de la création d'une application Web qui enregistre des lectures approfondies avec Django
L'histoire de Django créant une bibliothèque qui pourrait être un peu plus utile
L'histoire de la création d'un Line Bot qui nous raconte le calendrier de la programmation du concours
L'histoire du lancement d'un serveur Minecraft depuis Discord
[Python] Un programme qui compte le nombre de vallées
Créez un BOT qui raccourcit l'URL Discord
#Une fonction qui renvoie le code de caractère d'une chaîne de caractères
L'histoire de la création d'un réseau neuronal de génération musicale
Une histoire qui a eu du mal avec l'ensemble commun HTTP_PROXY = ~
Générer cette forme du fond d'une bouteille pour animaux de compagnie
Une histoire sur le changement du nom principal de BlueZ
L'histoire selon laquelle la valeur de retour de tape.gradient () était None
Le problème Zip 4 Gbyte est une histoire du passé
[Python] Un programme qui compare les positions des kangourous.
L'histoire de la construction de Zabbix 4.4
Un outil qui transforme automatiquement le gacha de Soshage
L'histoire de la création d'un canal VIP dans le chatwork en interne
L'histoire du champ de modèle Django disparaissant de la classe
L'histoire de la création d'une base de données à l'aide de l'API Google Analytics
L'histoire de la création d'un bot de boîte à questions avec discord.py
Script Python qui compare le contenu de deux répertoires
Lors de l'incrémentation de la valeur d'une clé qui n'existe pas
Une histoire coincée avec l'installation de la bibliothèque de machine learning JAX
L'histoire selon laquelle la version de python 3.7.7 n'était pas adaptée à Heroku
L'histoire de Python et l'histoire de NaN
pandas Récupère le nom d'une colonne contenant un caractère spécifique
L'histoire de la participation à AtCoder
L'histoire de l'erreur de hachage est apparue lors de l'utilisation de Pipenv
Une formule qui calcule simplement l'âge à partir de la date de naissance
Une histoire qui a vérifié si le nombre de coronas augmente vraiment rapidement chez les jeunes
L'histoire de la création d'un pilote standard pour db avec python.
Une fonction qui mesure le temps de traitement d'une méthode en python
L'histoire du travail de sortie de l'application que Google ne raconte pas
L'histoire du "trou" dans le fichier
Une petite histoire addictive avec les permissions du répertoire spécifié par expdp (pour les débutants)
J'ai fait un bot mou qui m'informe de la température
Une histoire qui prend en charge la notation électronique des examens avec reconnaissance d'image
L'histoire de la création d'un outil qui fonctionne sur Mac et Windows sur le site de développement de jeux
L'histoire du remontage du serveur d'application
[python] Une note que j'ai commencé à comprendre le comportement de matplotlib.pyplot
L'histoire de la création d'un Bot qui affiche les membres actifs dans un canal spécifique de Slack avec Python