Instructions: comment tester les rÎles ansibles et découvrir les problÚmes avant la production

Bonjour Ă  tous!


Je travaille en tant qu'ingénieur DevOps dans le service de réservation d'hÎtel Ostrovok.ru . Dans cet article, je veux parler de notre expérience dans le test des rÎles ansibles.


Chez Ostrovok.ru, nous utilisons ansible comme gestionnaire de configuration. Nous avons rĂ©cemment trouvĂ© la nĂ©cessitĂ© de tester les rĂŽles, mais il s'est avĂ©rĂ© qu'il n'y avait pas beaucoup d'outils pour cela - le framework Molecule est peut-ĂȘtre le plus populaire, nous avons donc dĂ©cidĂ© de l'utiliser. Mais il s'est avĂ©rĂ© que sa documentation Ă©tait muette sur de nombreux piĂšges. Nous n'avons pas trouvĂ© de guide suffisamment dĂ©taillĂ© en russe, nous avons donc dĂ©cidĂ© d'Ă©crire cet article.



Molécule


Molécule - un cadre pour aider à tester les rÎles ansibles.


Description simplifiée: la molécule crée une instance sur la plateforme que vous spécifiez (cloud, machine virtuelle, conteneur; pour plus de détails, voir la section Pilote ), y exécute votre rÎle, puis exécute les tests et supprime l'instance. En cas d'échec à l'une des étapes, la Molécule vous en informera.


Maintenant plus en détail.


Un peu de théorie


Considérez les deux entités clés de la molécule: scénario et pilote.


Scénario


Le script contient une description de quoi, oĂč, comment et dans quelle sĂ©quence sera effectuĂ©e. Un rĂŽle peut avoir plusieurs scripts, et chacun est un rĂ©pertoire sur le chemin <role>/molecule/<scenario> , qui contient des descriptions des actions nĂ©cessaires pour le test. Le script default doit ĂȘtre prĂ©sent et sera automatiquement créé si vous initialisez le rĂŽle Ă  l'aide de la molĂ©cule. Les noms des scĂ©narios suivants sont choisis Ă  votre discrĂ©tion.


La séquence de tests dans le script est appelée matrice et, par défaut, elle est la suivante:


(Les étapes marquées d'un ? ignorées par défaut si elles ne sont pas décrites par l'utilisateur)


  • lint - run linter. Par dĂ©faut, yamllint et flake8 ,
  • destroy - supprime les instances du dernier lancement de Molecule (si laissĂ©),
  • dependency ? - mise en place d'une dĂ©pendance ansible du rĂŽle testĂ©,
  • syntax - vĂ©rifier la syntaxe d'un rĂŽle en utilisant ansible-playbook --syntax-check ,
  • create - crĂ©e une instance,
  • prepare ? - prĂ©paration de l'instance; par exemple vĂ©rifier / installer python2
  • converge - lancement du playbook testĂ©,
  • idempotence - redĂ©marrez le playbook pour le test d'idempotence,
  • side_effect ? - actions non directement liĂ©es au rĂŽle, mais nĂ©cessaires aux tests,
  • verify - exĂ©cuter des tests de la configuration rĂ©sultante en utilisant testinfra (par dĂ©faut) / goss / inspec ,
  • cleanup ? - (dans les nouvelles versions) - grosso modo, le «nettoyage» des infrastructures externes affectĂ©es par la MolĂ©cule,
  • destroy - supprime une instance.

Cette séquence couvre la plupart des cas, mais vous pouvez la modifier si nécessaire.


Chacune des Ă©tapes ci-dessus peut ĂȘtre exĂ©cutĂ©e sĂ©parĂ©ment en utilisant la molecule <command> . Mais il vaut la peine de comprendre que pour chacune de ces commandes cli, il peut exister sa propre sĂ©quence d’actions, qui peut ĂȘtre reconnue en exĂ©cutant la molecule matrix <command> . Par exemple, lorsque vous exĂ©cutez la commande de converge (exĂ©cutez le playbook testĂ©), les actions suivantes seront effectuĂ©es:


 $ molecule matrix converge ... └── default #   ├── dependency #   ├── create #   ├── prepare #   └── converge #   

La sĂ©quence de ces actions peut ĂȘtre modifiĂ©e. Si quelque chose de la liste est dĂ©jĂ  terminĂ©, il sera ignorĂ©. L'Ă©tat actuel, ainsi que la configuration de l'instance, sont stockĂ©s dans le $TMPDIR/molecule/<role>/<scenario> .


Ajouter des étapes avec ? Vous pouvez, aprÚs avoir décrit les actions souhaitées au format ansible-playbook, et faire le nom du fichier selon l'étape: prepare.yml / side_effect.yml . La molécule attendra ces fichiers dans le dossier de script.


Chauffeur


Un pilote est une entité dans laquelle des instances de test sont créées.
La liste des pilotes standard pour lesquels la molĂ©cule a des modĂšles prĂȘts est la suivante: Azure, Docker, EC2, GCE, LXC, LXD, OpenStack, Vagrant, Delegated.


Dans la plupart des cas, les modÚles sont les destroy.yml create.yml et destroy.yml dans le dossier de script qui décrivent respectivement la création et la suppression de l'instance.
Les exceptions sont Docker et Vagrant, car les interactions avec leurs modules peuvent se produire sans les fichiers ci-dessus.


Il convient de souligner le pilote dĂ©lĂ©guĂ©, car s'il est utilisĂ© dans les fichiers pour crĂ©er et supprimer une instance, seul le travail avec la configuration des instances est dĂ©crit, le reste doit ĂȘtre dĂ©crit par l'ingĂ©nieur.


Le pilote par défaut est Docker.


Maintenant, nous nous tournons vers la pratique et considérons d'autres fonctionnalités.


Pour commencer


En tant que "bonjour le monde", nous testons le rÎle simple de l'installation de nginx. Nous choisirons docker comme pilote - je pense qu'il est installé sur la plupart d'entre vous (et rappelez-vous que docker est le pilote par défaut).


Préparez virtualenv et installez-y la molecule :


 > pip install virtualenv > virtualenv -p `which python2` venv > source venv/bin/activate > pip install molecule docker # molecule  ansible  ; docker   

L'étape suivante consiste à initialiser un nouveau rÎle.
L'initialisation d'un nouveau rÎle, ainsi que d'un nouveau scénario, s'effectue à l'aide de la commande molecule init <params> :


 > molecule init role -r nginx --> Initializing new role nginx... Initialized role in <path>/nginx successfully. > cd nginx > tree -L 1 . ├── README.md ├── defaults ├── handlers ├── meta ├── molecule ├── tasks └── vars 6 directories, 1 file 

Le résultat fut un rÎle ansible typique. De plus, toutes les interactions avec les molécules CLI sont faites à partir de la racine du rÎle.


Voyons ce qu'il y a dans le répertoire des rÎles:


 > tree molecule/default/ molecule/default/ ├── Dockerfile.j2 # Jinja-  Dockerfile ├── INSTALL.rst. #       ├── molecule.yml #   ├── playbook.yml #    └── tests #     verify └── test_default.py 1 directory, 6 files 

Analysons la configuration molecule/default/molecule.yml (nous ne remplacerons que l'image docker):


 --- dependency: name: galaxy driver: name: docker lint: name: yamllint platforms: - name: instance image: centos:7 provisioner: name: ansible lint: name: ansible-lint scenario: name: default verifier: name: testinfra lint: name: flake8 

dépendance


Cette section décrit la source des dépendances.


Options possibles: galaxie , dorure , coquille.


Shell est juste un shell de commande qui est utilisé si la galaxie et la dorure ne couvrent pas vos besoins.


Je ne m'arrĂȘterai pas ici longtemps, c'est assez dĂ©crit dans la documentation .


chauffeur


Le nom du conducteur. Nous avons ce docker.


peluche


Comme linter, le yamllint est utilisé.


Les options utiles dans cette partie de la configuration sont la possibilité de spécifier un fichier de configuration pour yamllint, de transmettre les variables d'environnement ou de désactiver le linter:


 lint: name: yamllint options: config-file: foo/bar env: FOO: bar enabled: False 

plateformes


Décrit la configuration des instances.
Dans le cas du docker en tant que pilote, la molécule est itérée sur cette section et chaque élément de la liste est disponible dans Dockerfile.j2 tant que variable d' item .


Dans le cas du pilote, dans lequel create.yml et destroy.yml , la section y est disponible en tant que molecule_yml.platforms , et les itérations sur celui-ci sont déjà décrites dans ces fichiers.


Étant donnĂ© que la molĂ©cule fournit un contrĂŽle d'instance pour les modules ansible, une liste des paramĂštres possibles doit y ĂȘtre recherchĂ©e. Pour docker, par exemple, le module docker_container_module est utilisĂ© . Les modules utilisĂ©s dans d'autres pilotes se trouvent dans la documentation .


Et des exemples d'utilisation de divers pilotes peuvent ĂȘtre trouvĂ©s dans les tests de la molĂ©cule elle-mĂȘme .


Remplacez centos: 7 sur ubuntu ici .


approvisionneur


"Fournisseur" est l'entitĂ© qui contrĂŽle les instances. Dans le cas de la MolĂ©cule, c'est ansible, le support des autres n'est pas prĂ©vu, donc cette section peut ĂȘtre appelĂ©e avec rĂ©serve la configuration Ă©tendue d'ansible.
Ici, vous pouvez spécifier beaucoup de choses, je vais souligner les principaux moments, à mon avis,:


  • playbooks : vous pouvez spĂ©cifier les playbooks Ă  utiliser Ă  certaines Ă©tapes.

 provisioner: name: ansible playbooks: create: create.yml destroy: ../default/destroy.yml converge: playbook.yml side_effect: side_effect.yml cleanup: cleanup.yml 


 provisioner: name: ansible config_options: defaults: fact_caching: jsonfile ssh_connection: scp_if_ssh: True 

  • connection_options : paramĂštres de connexion

 provisioner: name: ansible connection_options: ansible_ssh_common_args: "-o 'UserKnownHostsFile=/dev/null' -o 'ForwardAgent=yes'" 

  • options : options et variables d'environnement possibles

 provisioner: name: ansible options: vvv: true diff: true env: FOO: BAR 

scénario


Le nom et la description des séquences de script.
Vous pouvez modifier la matrice d'actions par défaut d'une <command>_sequence ajoutant la <command>_sequence et en déterminant la liste des étapes dont nous avons besoin comme valeur.
Supposons que nous voulons changer la séquence d'actions lors de l'exécution de la commande playbook run: molecule converge


 # : # - dependency # - create # - prepare # - converge scenario: name: default converge_sequence: - create - converge 

vérificateur


Mise en place du cadre pour les tests et le linter à lui. Par défaut, testinfra et flake8 sont utilisés testinfra flake8 . Les options possibles sont similaires à celles ci-dessus:


 verifier: name: testinfra additional_files_or_dirs: - ../path/to/test_1.py - ../path/to/test_2.py - ../path/to/directory/* options: n: 1 enabled: False env: FOO: bar lint: name: flake8 options: benchmark: True enabled: False env: FOO: bar 

Revenons Ă  notre rĂŽle. Modifiez le tasks/main.yml pour qu'il ressemble Ă  ceci:


 --- - name: Install nginx apt: name: nginx state: present - name: Start nginx service: name: nginx state: started 

Et ajoutez les tests Ă  la molecule/default/tests/test_default.py


 def test_nginx_is_installed(host): nginx = host.package("nginx") assert nginx.is_installed def test_nginx_running_and_enabled(host): nginx = host.service("nginx") assert nginx.is_running assert nginx.is_enabled def test_nginx_config(host): host.run("nginx -t") 

Terminé, il ne reste plus qu'à courir (depuis la racine du rÎle, je vous le rappelle):


 > molecule test 

Échappement long sous le becquet:
 --> Validating schema <path>/nginx/molecule/default/molecule.yml. Validation completed successfully. --> Test matrix └── default ├── lint ├── destroy ├── dependency ├── syntax ├── create ├── prepare ├── converge ├── idempotence ├── side_effect ├── verify └── destroy --> Scenario: 'default' --> Action: 'lint' --> Executing Yamllint on files found in <path>/nginx/... Lint completed successfully. --> Executing Flake8 on files found in <path>/nginx/molecule/default/tests/... Lint completed successfully. --> Executing Ansible Lint on <path>/nginx/molecule/default/playbook.yml... Lint completed successfully. --> Scenario: 'default' --> Action: 'destroy' PLAY [Destroy] ***************************************************************** TASK [Destroy molecule instance(s)] ******************************************** changed: [localhost] => (item=None) changed: [localhost] TASK [Wait for instance(s) deletion to complete] ******************************* ok: [localhost] => (item=None) ok: [localhost] TASK [Delete docker network(s)] ************************************************ PLAY RECAP ********************************************************************* localhost : ok=2 changed=1 unreachable=0 failed=0 --> Scenario: 'default' --> Action: 'dependency' Skipping, missing the requirements file. --> Scenario: 'default' --> Action: 'syntax' playbook: <path>/nginx/molecule/default/playbook.yml --> Scenario: 'default' --> Action: 'create' PLAY [Create] ****************************************************************** TASK [Log into a Docker registry] ********************************************** skipping: [localhost] => (item=None) TASK [Create Dockerfiles from image names] ************************************* changed: [localhost] => (item=None) changed: [localhost] TASK [Discover local Docker images] ******************************************** ok: [localhost] => (item=None) ok: [localhost] TASK [Build an Ansible compatible image] *************************************** changed: [localhost] => (item=None) changed: [localhost] TASK [Create docker network(s)] ************************************************ TASK [Create molecule instance(s)] ********************************************* changed: [localhost] => (item=None) changed: [localhost] TASK [Wait for instance(s) creation to complete] ******************************* changed: [localhost] => (item=None) changed: [localhost] PLAY RECAP ********************************************************************* localhost : ok=5 changed=4 unreachable=0 failed=0 --> Scenario: 'default' --> Action: 'prepare' Skipping, prepare playbook not configured. --> Scenario: 'default' --> Action: 'converge' PLAY [Converge] **************************************************************** TASK [Gathering Facts] ********************************************************* ok: [instance] TASK [nginx : Install nginx] *************************************************** changed: [instance] TASK [nginx : Start nginx] ***************************************************** changed: [instance] PLAY RECAP ********************************************************************* instance : ok=3 changed=2 unreachable=0 failed=0 --> Scenario: 'default' --> Action: 'idempotence' Idempotence completed successfully. --> Scenario: 'default' --> Action: 'side_effect' Skipping, side effect playbook not configured. --> Scenario: 'default' --> Action: 'verify' --> Executing Testinfra tests found in <path>/nginx/molecule/default/tests/... ============================= test session starts ============================== platform darwin -- Python 2.7.15, pytest-4.3.0, py-1.8.0, pluggy-0.9.0 rootdir: <path>/nginx/molecule/default, inifile: plugins: testinfra-1.16.0 collected 4 items tests/test_default.py .... [100%] ========================== 4 passed in 27.23 seconds =========================== Verifier completed successfully. --> Scenario: 'default' --> Action: 'destroy' PLAY [Destroy] ***************************************************************** TASK [Destroy molecule instance(s)] ******************************************** changed: [localhost] => (item=None) changed: [localhost] TASK [Wait for instance(s) deletion to complete] ******************************* changed: [localhost] => (item=None) changed: [localhost] TASK [Delete docker network(s)] ************************************************ PLAY RECAP ********************************************************************* localhost : ok=2 changed=2 unreachable=0 failed=0 

Notre rÎle simple a été testé sans problÚme.
Il convient de rappeler que s'il y a eu des problÚmes pendant le fonctionnement du molecule test , alors si vous n'avez pas modifié la séquence standard, la molécule supprimera l'instance.


Les commandes suivantes sont utiles pour le débogage:


 > molecule --debug <command> # debug info.      . > molecule converge #      . > molecule login #    . > molecule --help #   . 

RĂŽle existant


L'ajout d'un nouveau script à un rÎle existant s'effectue à partir du répertoire des rÎles avec les commandes suivantes:


 #     > molecule init scenarion --help #    > molecule init scenario -r <role_name> -s <scenario_name> 

Dans le cas oĂč il s'agit du premier script du rĂŽle, l' -s peut ĂȘtre omise car le script default sera créé.


Conclusion


Comme vous pouvez le voir, la Molécule n'est pas trÚs compliquée, et lorsque vous utilisez vos propres modÚles, vous pouvez réduire le déploiement d'un nouveau script pour éditer des variables dans les playbooks pour créer et supprimer des instances. La molécule s'intÚgre parfaitement aux systÚmes CI, ce qui vous permet d'augmenter la vitesse de développement en réduisant le temps nécessaire pour tester manuellement les playbooks.


Merci de votre attention. Si vous avez de l'expérience dans les tests de rÎles ansibles, et que cela n'est pas lié à la molécule - parlez-nous-en dans les commentaires!

Source: https://habr.com/ru/post/fr448136/


All Articles