[PYTHON] Que faites-vous avec la gestion de la configuration d'un serveur qui a été implémenté Ansible mais qui est déjà en cours d'exécution? Je rencontre le problème

Ceux qui seraient heureux si vous pouviez le lire

introduction

Je suis une personne du département d'infrastructure qui vérifie, construit, teste et fournit souvent des exigences autour de MW en fonction des exigences métier.

D'avril à septembre 2016, en tant que membre de l'équipe d'automatisation, j'ai créé et implémenté le playbook d'Ansible.

Ansible est très pratique, n'est-ce pas? Avant la mise en œuvre, le processus de construction prenait beaucoup de temps car une grande quantité de matériaux de conception et de preuves de construction et de test devait être créée de la demande à la livraison du côté commercial.

Après avoir implémenté Ansible, créer un fichier Vars qui répond aux exigences ~ Demander un examen avec une demande de tirage sur GitHub ~ Jenkins ~ L'exécution du travail et les travaux de construction deviennent très simples, et il n'est pas nécessaire de préparer des manuels de procédure ou de créer des preuves de test. C'est donc beaucoup plus facile.

Mais n'est-il pas très difficile de mettre les informations de configuration d'un serveur ou d'une instance qui s'exécute déjà dans le code Ansible?

Cet article se concentre sur la manière d'aborder les problèmes qui ont été rencontrés après être devenu Ansible.

À propos, l'équipe à laquelle j'appartiens dessine la feuille de route suivante pour l'implémentation d'Ansible. Cet article est le contenu de ②.

Prémisse. Je souhaite gérer la configuration d'un groupe d'environnement de construction manuel qui a un certain degré de configuration

  1. Création d'un playbook et d'un rôle avec la même configuration que l'environnement de construction manuelle → J'ai réalisé que créer des vars pour un environnement de construction manuelle était mortellement douloureux (début de cet article)
  2. J'ai commencé à créer un outil de vidage (maintenant ici) </ font>
  3. Réaliser la gestion de la configuration avec la même configuration que la construction manuelle (à partir de maintenant)
  4. Changez la configuration pour celle qui convient à la construction automatique (à partir de maintenant)

Résumé de cet article

  • En introduisant Ansible & Serverspec dans les travaux de construction, nous avons pu créer un environnement qui réduit la main-d'œuvre et les erreurs. ――Cependant, la gestion de la configuration du serveur fonctionnant dans l'environnement existant est mortelle (il est trop gênant de créer manuellement le fichier Vars).
  • En réponse, nous avons commencé à créer un outil qui génère automatiquement divers fichiers de paramètres Ansible (vars / host_vars / group_vars), y compris les fichiers Vars à partir des fichiers de paramètres du serveur déjà exécuté sur Python 3.4.
  • Quand ceci est exécuté, le fichier Vars est automatiquement créé à partir du fichier Config de l'environnement existant, c'est donc un casse-tête de regarder la machine réelle et de créer le fichier Vars en copiant. Pas besoin </ font>

Comment gérer la configuration de l'environnement existant après l'implémentation d'Ansible)

Comme mentionné ci-dessus, en mettant en œuvre Ansible, le travail de construction lui-même est devenu plus facile. En outre, pour les départements métiers qui préparent l'infrastructure pour le «nouveau» Le demandeur envoie une demande d'extraction GitHub, et lorsque le personnel de l'infrastructure confirme et approuve la partie modifiée, le paramètre est reflété dans la branche Maseter et les travaux de construction sont terminés. Était

Illustrer une opération GitHub Flow plus simple qui intègre des pull requests / reviews (1/2) http://www.atmarkit.co.jp/ait/articles/1401/21/news042.html

Cependant, cela n'a pas été si facile pour les départements commerciaux qui ont un environnement existant.

Si on me demandait de modifier les paramètres MW d'un certain serveur, je devais préparer divers fichiers de paramètres Ansible tels que le fichier Vars à partir de zéro, ce qui était une situation très gênante.

J'ai eu l'idée de créer un outil de création automatique de fichiers d'inventaire.

En raison des problèmes mentionnés ci-dessus, j'ai proposé un outil qui génère automatiquement des fichiers de paramètres Ansible à partir du serveur dans l'environnement existant.

イメージ図.png

J'ai fait un diagramme d'image minable. Le flux de l'outil est le suivant

  1. Spécifiez les SV et MW à exécuter sur le PC local
  2. Appuyez sur git
  3. A partir de l'interface graphique jenkins, spécifiez le fichier mentionné dans ② et exécutez le travail.
  4. Le serveur d'exécution jenkins clone le référentiel maître git et obtient le serveur cible spécifié et le fichier de configuration MW par sftp.
  5. Après l'acquisition, le script de conversion en fichier Ansible est exécuté et le fichier de paramètres Ansible est créé sous le répertoire d'exécution (vars / host_vars / group_vars).
  6. Divers fichiers de paramètres créés sont téléchargés sur git

Démo (essayez de créer automatiquement un fichier vars à partir du fichier de configuration en utilisant apache comme exemple)

Ici, je voudrais extraire le fichier de configuration Apache et créer automatiquement le fichier Vars suivant. C'est une image d'écrire en fait une partie de ⑤ En fait, il est divisé en différents modules afin de pouvoir répondre à diverses exigences, mais comme il s'agit d'une démo, il est extrait pour des paramètres simples d'Apache.

environnement

・ Python3.4 ・ Apache 2.2.15

Fichier Vars à créer

Après l'exécution de l'outil, les informations du fichier de paramètres (/etc/httpd/conf/httpd.conf) sont extraites et stockées dans les éléments suivants.

KeepAlive: ''
KeepAliveTimeout: ''
MaxKeepAliveRequests: '100'
PidFile: run/httpd.pid
ServerRoot: '"/etc/httpd"'
ServerTokens: OS
Timeout: '60'
load_module:[]

Préparation

Installez apache et créez main.py directement dans le répertoire / etc / httpd Assurez-vous que httpd.conf, qui est la cible de l'extraction des paramètres, est localisé.

[root@localhost httpd]$ sudo yum install httpd
[root@localhost httpd]$ pwd
/etc/httpd
[root@localhost httpd]# ls conf/httpd.conf
conf/httpd.conf
[root@localhost httpd]$vi main.py

Créer main.py

main.py


# coding: UTF-8
import yaml
from pathlib import Path
import re


#Décrire le processus d'extraction des paramètres
class CommonFunc:
    def __init__(self):
        pass

    # file_Stocke le contenu du fichier cible spécifié par l'argument de nom dans un tableau ligne par ligne
    def func_read_files(self, file_name):
        lines = []
        with file_name.open() as f:
            lines.extend(f.readlines())
        return lines

    #Stocker la ligne contenant la chaîne de caractères spécifiée par paramètre dans le tableau
    def func_search_parameter(self, lines, parameter):
        searched_line = []
        for line_tmp in lines:
            #Supprimer l'espace blanc de début
            line = re.sub(r'^\s+', '', line_tmp)
            try:
                if line.startswith(parameter):
                    #Supprimer la ligne commentée
                    tmp = re.sub(r"^\s*#.*", "", line)
                    searched_line.append(tmp.rstrip('\r\n'))
            except:
                searched_line = ""

        return searched_line

    #Recherche la ligne contenant la chaîne de caractères spécifiée par paramètre et la stocke dans le tableau. Sortie de la différence du fichier modèle à l'aide de l'ensemble
    def func_set_parameter(self, lines, compared_lines, parameter):
        src_list = []
        dst_list = []
        for line in lines:
            if line.find(parameter) >= 0:
                src_list.append(line.rstrip('\r\n'))
        for compared_line in compared_lines:
            dst_list.append(compared_line.rstrip('\r\n'))
        src_set = set(src_list)
        return src_set.difference(dst_list)

    #Recherchez les lignes contenant la chaîne spécifiée par paramètre. Séparez par un espace et stockez le second dans le tableau
    def func_split_line_unique(self, lines, parameter):
        splited_line = []
        for line_tmp in lines:
            #Supprimer l'espace blanc de début
            line = re.sub(r'^\s+', '', line_tmp)
            if line.startswith(parameter):
                try:
                    splited_line = line.split()[1]
                except:
                    splited_line = ""
        return splited_line


#Créez un dictionnaire et stockez la valeur dans Value. Le processus d'extraction des paramètres réels appelle le processus de CommonFunc.
class MakeApacheDictionary(CommonFunc):

    def __init__(self):
        self.output_files = "test_vars.yml"
        self.httpd_conf_path = Path("/etc", "httpd", "conf", "httpd.conf")
        self.module_template_path = Path("/etc", "httpd", "load_module_template.txt")
        self.httpd_lines = self.func_read_files(self.httpd_conf_path)
        self.base_module_lines = self.func_search_parameter(self.httpd_lines, "LoadModule")
        self.base_module_template_lines = self.func_read_files(self.module_template_path)



    def apache_yaml_dict(self):
        self.yml_list = {
        #Unique par exemple
            'ServerTokens': "",
            'ServerRoot': "",
            'PidFile': "",
            'Timeout': "",
            'KeepAlive': "",
            'MaxKeepAliveRequests': "",
            'KeepAliveTimeout': "",
        #Affiche la différence par rapport au fichier modèle sous forme d'ensemble
            'load_module': []}

        d = self.yml_list
        d['ServerTokens'] = self.func_split_line_unique(self.httpd_lines, "ServerTokens")
        d['ServerRoot'] = self.func_split_line_unique(self.httpd_lines, "ServerRoot")
        d['PidFile'] = self.func_split_line_unique(self.httpd_lines, "PidFile")
        d['Timeout'] = self.func_split_line_unique(self.httpd_lines, "Timeout")
        d['MaxKeepAliveRequests'] = self.func_split_line_unique(self.httpd_lines, "MaxKeepAliveRequests")
        d['load_module'].extend(self.func_set_parameter(self.base_module_lines, self.base_module_template_lines,"LoadModule"))


    def create_yaml(self):
        with open(self.output_files, 'w') as f:
            f.write(yaml.safe_dump(self.yml_list, default_flow_style=False))


#Génération d'instance
a = MakeApacheDictionary()
a.apache_yaml_dict()
a.create_yaml()

La description

--Class est divisé en classe "CommonFunc" qui décrit le processus d'extraction des paramètres et MakeApacheDictionary qui crée un dictionnaire et le vide sous forme de fichier yaml.

  • La dernière classe hérite de la première afin que le processus d'extraction puisse être utilisé.
  • Des valeurs uniques dans les fichiers de configuration tels que ServerRoot et TimeOut peuvent être obtenues en utilisant la méthode startswith et en les fractionnant comme décrit dans func_split_line_unique.
  • Pour les éléments tels que LoadModule et RewriteCond qui ont plusieurs paramètres pour le même élément, préparez les paramètres standard séparément en tant que fichier modèle et affichez les différences à l'aide d'un ensemble.

Exemple de modèle

Dans func_set_parameter, les lignes commençant par LoadModule dans httpd.conf sont recherchées et répertoriées, comparées au contenu décrit dans le fichier modèle, et la différence est générée.

[root@localhost collect_config]# more load_module_template.txt
LoadModule authn_alias_module modules/mod_authn_alias.so
LoadModule authn_anon_module modules/mod_authn_anon.so
LoadModule authn_dbm_module modules/mod_authn_dbm.so
etc ...

Résultat d'exécution

Le dictionnaire créé Passé à la fonction create_yml (où le module yaml.safe_dump est utilisé) et sauvegardé dans le répertoire d'exécution du script

[root@localhost httpd]# python main.py
[root@localhost httpd]# more test_vars.yml
KeepAlive: 'Off'
KeepAliveTimeout: '15'
MaxKeepAliveRequests: '100'
PidFile: run/httpd.pid
ServerRoot: '"/etc/httpd"'
ServerTokens: OS
Timeout: '60'
load_module:
- LoadModule auth_basic_module modules/mod_auth_basic.so
- LoadModule authn_file_module modules/mod_authn_file.so
- LoadModule auth_digest_module modules/mod_auth_digest.so
[root@localhost httpd]#

À la fin

Merci d'avoir lu jusqu'au bout. J'espère qu'il sera utile pour ceux qui sont également préoccupés par la gestion de la configuration de l'environnement existant.

Recommended Posts