Exécutez Ansible à partir de Python à l'aide de l'API

en premier

Ansible est pratique, n'est-ce pas? Quand je fais le même travail sur de nombreux serveurs, je pense que c'est Dieu.

On a l'impression que c'est entièrement automatisé simplement en accédant au playbook, mais je voulais aussi automatiser l'exécution du playbook d'une manière agréable. Vous pouvez écrire un script shell, mais l'analyse des résultats, etc. est problématique.

Donc, cette fois, je voudrais frapper Ansible de Python dans le bon sens. Je n'ai pas pu trouver l'article de manière inattendue.

Code source

Il est facile de comprendre si vous lisez depuis __main__. Un playbook qui exécute ls -la / sur 192.168.0.1. Si vous avez utilisé Ansible dans les commandes, vous devriez pouvoir le lire facilement. Veuillez vous référer aux simples commentaires ici et là.

pip3 install ansible
import json
import shutil
from ansible.module_utils.common.collections import ImmutableDict
from ansible.parsing.dataloader import DataLoader
from ansible.vars.manager import VariableManager
from ansible.inventory.manager import InventoryManager
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
from ansible import context
import ansible.constants as C


class ResultCallback(CallbackBase):
    def __init__(self, *args, **kwargs):
        super(ResultCallback, self).__init__(*args, **kwargs)
        self.host_ok = {}
        self.host_unreachable = {}
        self.host_failed = {}

    def v2_runner_on_unreachable(self, result):
        host = result._host
        self.host_unreachable[host.get_name()] = result

    def v2_runner_on_ok(self, result, *args, **kwargs):
        host = result._host
        self.host_ok[host.get_name()] = result

    def v2_runner_on_failed(self, result, *args, **kwargs):
        host = result._host
        self.host_failed[host.get_name()] = result

def ansible_run(play_source, host_list):
    # ansible-Identique à l'argument qui peut être spécifié dans le playbook
    context.CLIARGS = ImmutableDict(
        tags={}, 
        listtags=False, 
        listtasks=False, 
        listhosts=False, 
        syntax=False, 
        connection='ssh',                
        module_path=None, 
        forks=100, 
        private_key_file=None,
        ssh_common_args=None, 
        ssh_extra_args=None, 
        sftp_extra_args=None, 
        scp_extra_args=None, 
        become=False,
        become_method='Sudo', 
        become_user='root', 
        verbosity=True, 
        check=False, 
        start_at_task=None
    )

    #La priorité est donnée à l'authentification par clé et elle n'est utilisée que lorsque le mot de passe est demandé. Si tu ne veux pas écrire, c'est OK
    passwords = dict(vault_pass='secret')

    #Instanciation de rappel
    results_callback = ResultCallback()

    #Convertir l'inventaire au format 1 ligne
    sources = ','.join(host_list)
    if len(host_list) == 1:
        sources += ','
    loader = DataLoader()
    inventory = InventoryManager(loader=loader, sources=sources)

    #Définir la valeur
    variable_manager = VariableManager(loader=loader, inventory=inventory)
    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

    #Courir
    tqm = None
    try:
        tqm = TaskQueueManager(
                inventory=inventory,
                variable_manager=variable_manager,
                loader=loader,
                passwords=passwords,
                stdout_callback=results_callback, 
            )
        result = tqm.run(play)
    finally:
        #Suppression des fichiers temporaires après avoir quitté
        if tqm is not None:
            tqm.cleanup()
        # Remove ansible tmpdir
        shutil.rmtree(C.DEFAULT_LOCAL_TMP, True)
        return results_callback

if __name__ == "__main__":
    #Spécifiez l'hôte d'exécution (également spécifié dans l'inventaire)
    host_list = [ "[email protected]" ]

    #Définir le playbook
    play_source =  dict(
        name = "Ansible Play",
        hosts = host_list,
        gather_facts = 'no',
        tasks = [
            dict(action=dict(module='shell', args='ls -l /'), register='shell_out')
        ]
    )
    
    results = ansible_run(play_source=play_source, host_list=host_list)

    for host, result in results.host_ok.items():
        print(host)
        print(json.dumps(result._result, indent=4))
    
    for host, result in results.host_failed.items():
        print(host)
        print(json.dumps(result._result, indent=4))
    
    for host, result in results.host_unreachable.items():
        print(host)
        print(json.dumps(result._result, indent=4))
    

Vous pouvez obtenir le dictionnaire des résultats d'exécution comme ceci. Ce qui suit est un extrait de ce qui a été produit par Json.

{
    "cmd": "ls -l /",
    "stdout": "total 28\nlrwxrwxrwx.    1 root root    7 May 11  2019 bin -> usr/bin\ndr-xr-xr-x.    6 root root 4096 Nov 12 18:17 boot\ndrwxr-xr-x.    7 root root   65 Nov 17 00:41 data\ndrwxr-xr-x.   21 root root 3580 Nov 23 12:10 dev\ndrwxr-xr-x.  104 root root 8192 Nov 22 14:11 etc\ndrwxr-xr-x.    6 root root 4096 Nov 20 13:06 gvolume0\ndrwxr-xr-x.    3 root root 4096 Nov 17 00:47 gvolume1\ndrwxr-xr-x.    3 root root   19 Nov 10 01:24 home\nlrwxrwxrwx.    1 root root    7 May 11  2019 lib -> usr/lib\nlrwxrwxrwx.    1 root root    9 May 11  2019 lib64 -> usr/lib64\ndrwxr-xr-x.    2 root root    6 May 11  2019 media\ndrwxr-xr-x.    2 root root    6 May 11  2019 mnt\ndrwxr-xr-x.    2 root root    6 May 11  2019 opt\ndr-xr-xr-x. 1056 root root    0 Nov 22 14:04 proc\ndr-xr-x---.    4 root root  192 Nov 23 11:27 root\ndrwxr-xr-x.   32 root root 1100 Nov 22 14:46 run\nlrwxrwxrwx.    1 root root    8 May 11  2019 sbin -> usr/sbin\ndrwxr-xr-x.    2 root root    6 May 11  2019 srv\ndr-xr-xr-x.   13 root root    0 Nov 22 14:04 sys\ndrwxrwxrwt.    9 root root  212 Nov 23 22:51 tmp\ndrwxr-xr-x.   12 root root  144 Nov 10 01:22 usr\ndrwxr-xr-x.   21 root root 4096 Nov 10 01:28 var",
    "stderr": "",
    "rc": 0,
    "start": "2020-11-23 22:51:11.787866",
    "end": "2020-11-23 22:51:11.793951",
    "delta": "0:00:00.006085",
    "changed": true,
    "invocation": {
        "module_args": {
            "_raw_params": "ls -l /",
            "_uses_shell": true,
            "warn": true,
            "stdin_add_newline": true,
            "strip_empty_ends": true,
            "argv": null,
            "chdir": null,
            "executable": null,
            "creates": null,
            "removes": null,
            "stdin": null
        }
    },
    "stdout_lines": [
        "total 28",
        "lrwxrwxrwx.    1 root root    7 May 11  2019 bin -> usr/bin",
        "dr-xr-xr-x.    6 root root 4096 Nov 12 18:17 boot",
        "drwxr-xr-x.    7 root root   65 Nov 17 00:41 data",
        "drwxr-xr-x.   21 root root 3580 Nov 23 12:10 dev",
        "drwxr-xr-x.  104 root root 8192 Nov 22 14:11 etc",
        "drwxr-xr-x.    6 root root 4096 Nov 20 13:06 gvolume0",
        "drwxr-xr-x.    3 root root 4096 Nov 17 00:47 gvolume1",
        "drwxr-xr-x.    3 root root   19 Nov 10 01:24 home",
        "lrwxrwxrwx.    1 root root    7 May 11  2019 lib -> usr/lib",
        "lrwxrwxrwx.    1 root root    9 May 11  2019 lib64 -> usr/lib64",
        "drwxr-xr-x.    2 root root    6 May 11  2019 media",
        "drwxr-xr-x.    2 root root    6 May 11  2019 mnt",
        "drwxr-xr-x.    2 root root    6 May 11  2019 opt",
        "dr-xr-xr-x. 1056 root root    0 Nov 22 14:04 proc",
        "dr-xr-x---.    4 root root  192 Nov 23 11:27 root",
        "drwxr-xr-x.   32 root root 1100 Nov 22 14:46 run",
        "lrwxrwxrwx.    1 root root    8 May 11  2019 sbin -> usr/sbin",
        "drwxr-xr-x.    2 root root    6 May 11  2019 srv",
        "dr-xr-xr-x.   13 root root    0 Nov 22 14:04 sys",
        "drwxrwxrwt.    9 root root  212 Nov 23 22:51 tmp",
        "drwxr-xr-x.   12 root root  144 Nov 10 01:22 usr",
        "drwxr-xr-x.   21 root root 4096 Nov 10 01:28 var"
    ],
    "stderr_lines": [],
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "_ansible_no_log": false
}

À la fin

Les résultats sont également faciles à utiliser en Python, il est donc facile de les combiner avec d'autres systèmes. Je cherchais cette méthode parce que je voulais frapper Ansible à partir du système Python que j'écris comme passe-temps. Ce serait formidable si cela pouvait être utile à d'autres personnes.

référence

Recommended Posts

Exécutez Ansible à partir de Python à l'aide de l'API
J'ai essayé d'utiliser l'API UnityCloudBuild de Python
Exécutez Python à partir d'Excel
Exécutez des fichiers Python à partir de HTML en utilisant Django
Exécutez des scripts Python à partir d'Excel (en utilisant xlwings)
Aplatir à l'aide du rendement Python de
Exécutez le script illustrator à partir de python
Utilisez l'API e-Stat de Python
Notification PUSH de Python vers Android à l'aide de l'API de Google
Acquisition de données à l'aide de l'API googlemap de python
Utilisation de Rstan de Python avec PypeR
Installez Python à partir des sources avec Ansible
[Python3] Google translate google translation sans utiliser l'API
Remarques sur l'utilisation de MeCab depuis Python
Essayez d'utiliser l'API de Pleasant (python / FastAPI)
Utiliser Cloud Storage depuis Python3 (Introduction)
Exécutez Aprili depuis Python sur Orange
Utilisez l'API kabu Station® de Python
Utilisez l'API Flickr de Python
Détection d'erreur Python exécutée à partir de Powershell
python Obtenez la météo à venir de l'API météo
Essayez d'utiliser l'API d'action de Python argparse
Exécutez des scripts Python de manière synchrone à partir de C #
Prédire le sexe à partir du nom à l'aide de l'API Gender et de Pykakasi en Python
Précautions lors de l'utilisation de phantomjs de python
Accéder aux feuilles de calcul à partir de Python à l'aide d'OAuth 2.0
Utiliser l'API Google Analytics de Python
Gérer l'API SOAP depuis Python (Zeep)
Exécutez le script Python à partir de Cisco Memorandum_EEM
Essayez d'utiliser Amazon DynamoDB à partir de Python
Comment obtenir des abonnés et des abonnés de Python à l'aide de l'API Mastodon
Collecter des informations sur Twitter avec Python (API Twitter)
Fonctionnement de la souris à l'aide de l'API Windows en Python
[Python] Application Web à partir de 0! Pratique (3) - Mise en œuvre de l'API
Exécutez Cloud Dataflow (Python) depuis AppEngine
Essayez d'utiliser l'API Wunderlist en Python
De Python à l'utilisation de MeCab (et CaboCha)
Essayez d'utiliser l'API Kraken avec Python
Tweet à l'aide de l'API Twitter en Python
Obtenez des données Youtube en Python à l'aide de l'API Youtube Data
Exécutez un servomoteur en utilisant python sur Raspberry Pi 3
Créer une feuille de calcul Google à l'aide de l'API Python / Google Data
Explication API pour toucher mastodonte de python
Connectez-vous à l'API Websocket de Coincheck depuis Python
Commencez à utiliser Python
sql à sql
Détectez les caractères japonais à partir d'images à l'aide de l'API Cloud Vision de Google avec Python
Scraping à l'aide de Python
Exécuter des scripts Python à partir d'applications C # GUI
Procédure pour utiliser l'API WEB de TeamGant (en utilisant python)
Je souhaite envoyer un e-mail depuis Gmail en utilisant Python.
Exécutez l'API Google Analytics (core v3) en python
Obtenir l'URL de l'image à l'aide de l'API Flickr en Python
Jugons les émotions à l'aide de l'API Emotion en Python
Création récente de classement à l'aide de l'API Qiita avec Python
Manipulez des objets à l'aide de l'API Python de bas niveau de Blender 2.8
Exécutez l'API vSphere de VMware vSphere 6 avec le script Python (pyvmomi)
Charger des images à partir d'une URL à l'aide de Pillow dans Python 3
Téléchargement anonyme d'images à l'aide de l'API Imgur (à l'aide de Python)