{{tag>Brouillon}} # Notes Ansible Voir : * https://docs.ansible.com/ecosystem.html * https://docs.ansible.com/ansible/latest/user_guide/ * http://william.shallum.net/random-notes/random-ansible-tricks * https://www.youtube.com/watch?v=ZNB1at8mJWY * http://www.ageekslab.com/ansible/ansible3/ (boucles imbriquées) * [Booster vos pratiques DEVOPS avec Ansible AWX](https://blog.steamulo.com/booster-vos-pratiques-devops-avec-ansible-awx-9a9c20734a71) * https://github.com/STEAMULO * http://people.redhat.com/mlessard/mtl/presentations/apr2018/AnsibleF5WorkshopVF.pdf * https://legacy-controller-docs.ansible.com/automation-controller/latest/html/ Liste des modules Ansible par catégorie : https://docs.ansible.com/ansible/2.9/modules/modules_by_category.html Glossary * https://docs.ansible.com/ansible/latest/reference_appendices/glossary.html Voir mode pull : * https://blog.octo.com/ansible-pull-killer-feature Voir aussi : * https://www.packer.io Exemples cool : * https://github.com/ansible/ansible-examples/blob/master/language_features/register_logic.yml * https://codepoets.co.uk/2014/ansible-random-things/ A lire * https://docs.ansible.com/ansible/latest/user_guide/playbooks_advanced_syntax.html * https://docs.w3cub.com/ansible~2.9/user_guide/playbooks_advanced_syntax * https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html * https://runebook.dev/fr/docs/ansible/user_guide/playbooks_loops * https://runebook.dev/fr/docs/ansible/plugins/lookup * https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html ## Install et config ### Install avec PIP `https://raw.githubusercontent.com/mrlesmithjr/ansible-samba/master/provision.sh` ~~~bash #!/bin/bash sudo apt-get update sudo apt-get install -y git python-pip python-dev sudo pip install jinja2 sudo pip install ansible sudo ansible-galaxy install -r /vagrant/requirements.yml -f ansible-playbook -i "localhost," -c local /vagrant/playbook.yml ~~~ ### Doc Voir ansible-doc. Exemple : ~~~bash ansible-doc -t keyword -l ~~~ ### Inventaire Voir : * https://blog.stephane-robert.info/post/ansible-inventaire-static-precedence-tips/ * https://blog.stephane-robert.info/post/ansible-inventaire-dynamique-vagrant/ * https://linux.goffinet.org/ansible/comprendre-inventaire-ansible/ * https://blog.octo.com/ansible-inventory-du-statique-au-dynamique/ "inline content" inventory ~~~bash ansible -m ping all -i 'node1,node2,' ~~~ lister toutes les nœuds ~~~bash ansible-inventory --list -y ~~~ ## config ~~~bash cp /etc/ansible/ansible.cfg ~/.ansible.cfg mkdir ~/.ansible cp /etc/ansible/hosts ~/.ansible/hosts.ini sed -i -e 's%/etc/ansible/hosts%$HOME/.ansible/hosts.ini%' ~/.ansible.cfg sed -i -e 's%#\(.*$HOME/\.ansible/hosts.ini\)%\1%' ~/.ansible.cfg sed -i -e 's/^remote_port/#remote_port/' ~/.ansible.cfg echo "localhost ansible_connection=local" >> ~/.ansible/hosts.ini ~~~ Ou `/etc/ansible/ansible.cfg` ~~~ini [defaults] host_key_checking = False timeout = 60 vault_password_file = /var/lib/plop/ansible/vault/vault_pass.txt ansible_managed = Ansible managed file, do not edit directly filter_plugins = /var/lib/plop/ansible/filter_plugins/ lookup_plugins = /var/lib/plop/ansible/lookup_plugins/ library = /var/lib/plop/ansible/library/ remote_tmp = /tmp/.ansible local_tmp = /tmp/.ansible #allow_world_readable_tmpfiles = true [ssh_connection] pipelining = True ssh_args = -o ControlMaster=auto -o ControlPersist=30m -o UserKnownHostsFile=/dev/null ~~~ ~~~bash export ANSIBLE_CONFIG=$HOME/.ansible.cfg ansible -i ~/.ansible/hosts.ini test -m ping ~~~ La connexion via SSH doit être configurée via ~/.ssh/config et via ssh-agent. Si besion : ~~~bash ssh-agent -k eval $(ssh-agent -s) ssh-add ~~~ Exemple de conf par variables ~~~bash export ANSIBLE_ALLOW_EMBEDDED_TEMPLATES=false export ANSIBLE_NOCOWS=true export BECOME_ALLOW_SAME_USER=false export ANSIBLE_PRIVATE_ROLE_VARS=true export ANSIBLE_DISPLAY_ARGS_TO_STDOUT=true export ANSIBLE_DISPLAY_TRACEBACK=always export ANSIBLE_DUPLICATE_YAML_DICT_KEY=error # export ANSIBLE_ENABLE_TASK_DEBUGGER=true export ANSIBLE_HOST_PATTERN_MISMATCH=error export ANSIBLE_INVENTORY_ANY_UNPARSED_IS_FAILED=true export ANSIBLE_INVENTORY_UNPARSED_FAILED=true ~~~ ## Usage Sudo / become ~~~bash ansible-playbook -u user -kKb playbook.yml ~~~ ## Sur les serveurs distants ~~~bash apt-get install python-minimal libpython-stdlib sudo ~~~ ## Traitements parallèles Voir : * [[Ansible - Accélérer Ansible grâce au module Mitogen]] * [[Notes commande xargs]] Exemple 1 `ansible.cfg` ~~~ini [defaults] strategy = free ~~~ Exemple 2 ~~~bash ansible -e serial_number=50 ~~~ ## Connexions ~~~ini [arista] eos ansible_host=192.168.2.10 ansible_connection=network_cli ansible_network_os=eos [juniper] junos ansible_host=192.168.2.20 ansible_connection=netconf ansible_network_os=junos ~~~ ## Autres Lancer une commande ~~~bash ansible all -a "free -m" ~~~ Lancer une commande bash (utilisation Pipe vars etc...) ~~~bash ansible all -m shell -a "ifconfig | grep inet" ~~~ Connaître toutes les variables et les valeurs associées (Nom machine, mémoire, Version noyaux ...) ~~~bash ansible all -m setup ~~~ Lancer une commande simultanément sur plusieurs serveurs par lots de 2 machines **-s** pour **sudo** ~~~bash ansible webservers -m service -a "name=nginx state=restarted" --forks=2 -s ~~~ Mode "noop" / "dry-run" ** --check** \ ou **--check--diff --limit foo.example.com** `always_run: True` sinon `--check` n’exécute pas les instructions du module **shell**, lineinfile A la place de **lineinfile** il existe aussi **replace** ### Dépendance de rôles Quand un rôle dépend d'un autre. \\ Ici **foo** dépend de **bar** `roles/foo/meta/main.yml` ~~~yaml --- allow_duplicates: no dependencies: - role: bar ~~~ ## Exemple Exemple * Découpage "role" un plusieurs morceaux (split role) * "when when" * **Include** dans un **role** * Action si fichier n'existe pas ** Si `/etc/systemd/system/multi-user.target.wants/rpcbind.service` n'existe pas faire : *** `systemctl add-wants multi-user.target rpcbind.service` `/roles/nis_client/tasks/main.yml` ~~~yaml --- - name: Include tasks ansible.builtin.include_tasks: "{{ ansible_os_family | lower }}.yml" ~~~ `/roles/nis_client/tasks/debian.yml` ~~~yaml --- - name: Ubuntu lancer rpcbind avant NIS stat: path='/etc/systemd/system/multi-user.target.wants/rpcbind.service' register: systemdwants - name: DEBUG debug: msg="systemdwants = {{ systemdwants }}" - name: Ubuntu lancer rpcbind avant NIS 2 command: systemctl add-wants multi-user.target rpcbind.service # when: systemdwants.stat.exists == False when: not systemdwants.stat.exists notify: - restart nis ~~~ ### Vérifier si un paquet deb est déjà installé Source : http://chaosmail.github.io/programming/2015/03/04/install-deb-packages-in-ansible/ ~~~yaml --- - name: Check if my_package is installed command: dpkg-query -W my_package register: my_package_check_deb failed_when: my_package_check_deb.rc > 1 changed_when: my_package_check_deb.rc == 1 check_mode: false - name: copie du paquet my_package copy: src=my_package_linux.ubuntu14.04_x86-64.deb dest=/root/my_package_linux.ubuntu14.04_x86-64.deb changed_when: my_package_check_deb.rc == 1 - name: installation des dépendances apt: name=libacl1 state=present changed_when: my_package_check_deb.rc == 1 - name: install du paquet apt: deb=/root/my_package_linux.ubuntu14.04_x86-64.deb changed_when: my_package_check_deb.rc == 1 ~~~ ### Exemple de find shell ~~~yaml - name: /var/log/* readable by user process - find shell: 'find /var/log/ -not \( -perm /o=r -o -user process \) -a -not \( -wholename "/var/log/btmp*" \)' changed_when: False always_run: True register: list_files_var_log_notreadable - name: /var/log/* readable by user process - set file: mode="o+rX" dest={{ item }} #file: mode="0755" dest={{ item }} with_items: - "{{ list_files_var_log_notreadable.stdout.split('\n') }}" when: list_files_var_log_notreadable.stdout != "" ~~~ ### Exemples include role conditionnel Exemple 1 ~~~yaml - hosts: webservers roles: - { role: debian_stock_config, when: ansible_os_family == 'Debian' } ~~~ Exemple 2 ~~~yaml - name: Enable local cache DNS include_role: name: acme.dns.enable_local_cache_dns vars: EVAR_BACKUP_NAME: postinstall host_func_excluded: - FOO # trigramme_appli: "{{ inventory_hostname[5:8] }}" trigramme_appli: "{{ ansible_hostname[5:8] }}" when: not trigramme_appli | lower in host_func_excluded | lower ~~~ ## Notes Ansible ### Lancer l'action même si Check Mode (Dry Run) `--check` always_run is deprecated. Use check_mode = no instead ~~~yaml #always_run: true check_mode: false ~~~ Parfois il est préférable de trouver une solution plus élégante. Par exemple : ~~~yaml - name: mkdir /san/label file: dest='/san/{{ item }}' state=directory with_items: #- '{{ list_label_ext4devs.stdout_lines }}' #- '{{ list_label_xfsdevs.stdout_lines }}' - '{{ list_label_ext4devs.stdout_lines | default() }}' - '{{ list_label_xfsdevs.stdout_lines | default() }}' ~~~ Ici nous utilisons `default()` pour éviter une erreur à cause d'un champ vide ~~~ fatal: [plop1]: FAILED! => {"failed": true, "msg": "'dict object' has no attribute 'stdout_lines'"} ~~~ ### Ignorer si mode check (ne pas tester) `when: not ansible_check_mode` ~~~bash - name: activation service sysstat 1 lineinfile: dest=/etc/default/sysstat line='ENABLED="false"' state=absent when: not ansible_check_mode ~~~ ### Exemple module command ne lancer qu'une seule fois une commande. ~~~yaml - name: newer autolock screen - do conf command: dbus-launch gsettings set org.gnome.desktop.lockdown disable-lock-screen true become: '{{ autologin_user }}' args: creates: /root/.ansible-jalon-disable-lock-screen - name: newer autolock screen - jalon exist ? stat: path=/root/.ansible-jalon-disable-lock-screen register: p - name: newer autolock screen - jalon touch file: path=/root/.ansible-jalon-disable-lock-screen state=touch # when: p.stat.exists == False when: not p.stat.exists ~~~ ## Gather_fact partiel Grâce à `gather_subset` `play.yml` ~~~yaml - name: Test hosts: all gather_subset: os_family ~~~ ## Copie de fichiers Une alternative à M(copy) ~~~yaml - name: Download file from a file path # ansible.builtin.copy: ansible.builtin.get_url: url: file:///tmp/a_file.txt dest: /tmp/afilecopy.txt ~~~ ## Pb ### becoming-an-unprivileged-user Err Failed to set permissions on the temporary...Not owner\nchown Lors de l’exécution d’un playbook Ansible avec un sudo (become) faisant appel à un utilisateur non privilégié (ici « oracle ») ~~~bash ansible -m ping -u user01 -i srv1, all --become-user=oracle -b ~~~ Nous avons l’erreur suivante : ~~~ srv1 | FAILED! => { "msg": "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 1, err: chown: /var/tmp/ansible-tmp-1685976784.0795348-3077033-272077328342364/: Not owner\nchown: /var/tmp/ansible-tmp-1685976784.0795348-3077033-272077328342364/AnsiballZ_ping.py: Not owner\n}). For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user" } ~~~ Apparemment cela concernerait que AIX. Solution La solution de contournement la plus simple à mettre en place est de définir à True la variable `ansible_shell_allow_world_readable_temp` `play1.yml` ~~~yaml #!/usr/bin/ansible-playbook # # ./play1.yml -u user01 -i srv1, --- - name: test sudo oracle hosts: all gather_facts: false become: true become_user: oracle vars: ansible_shell_allow_world_readable_temp: true tasks: - name: command id command: id changed_when: false register: cmd_id - name: echo id debug: var: cmd_id ~~~ ### Remote copy does not support recursive copy of directory Le module **copy** ne supporte pas les copies de répertoire (mode récursif). \\ Le module **synchronize** est plus approprié. Dans notre exemple nous voulons copier srv1:/mnt/plop/ sur srv1:/tmp/ Note : peut-être que cela marche avec 'directory_mode' ~~~yaml - name: push omniplanar installer copy: src: /mnt/plop/ dest: /tmp remote_src: True #directory_mode: True ~~~ Solution ~~~yaml - name: push plop synchronize: src: /mnt/plop/plop.run dest: /usr/local/bin/ rsync_opts: - "--chmod=F755" - "--chown=root:staff" #delegate_to: "{{ inventory_hostname }}" use_ssh_args: true ~~~ ### Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user Erreur ~~~ fatal: [aws-zbx1]: FAILED! => {"msg": "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 1, err: chown: changing ownership of '/var/tmp/ansible-tmp-1559124598.47-172527571991348/': Operation not permitted\nchown: changing ownership of '/var/tmp/ansible-tmp-1559124598.47-172527571991348/AnsiballZ_postgresql_db.py': Operation not permitted\n}). For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user" ~~~ Solution `~/.ansible.cfg` ~~~ini [defaults] allow_world_readable_tmpfiles = true ~~~ ou ~~~yaml vars: ansible_shell_allow_world_readable_temp: true ~~~ Voir https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user ### sudo: no tty present and no askpass program specified Solution de contournement (workaround) Source: https://github.com/ansible/ansible/issues/15297 ~~~yaml lineinfile: path: /etc/sudoers state: present insertafter: EOF line: '{{ ansible_user }} ALL=NOPASSWD:/usr/bin/rsync' ~~~ Solution 2 Source : https://github.com/ansible/ansible/issues/20769 Applique la perte de l'élévation de privilèges Ajouter `rsync_path: /usr/bin/rsync` ~~~yaml tasks: - name: Synchronization of src on the control machine to dest on the remote hosts synchronize: src: /etc/hostname dest: /home/user rsync_path: /usr/bin/rsync ~~~ ### Pb No module named 'ansible' ~~~ $ ansible --version Traceback (most recent call last): File "/usr/bin/ansible", line 34, in from ansible import context ModuleNotFoundError: No module named 'ansible' ~~~ #### Solution Test ~~~bash env PYTHONPATH=/usr/lib/python3/dist-packages ansible --version ~~~ Solution si test OK `~/.bashrc` ~~~bash # Fix bug Ansible : No module named 'ansible' export PYTHONPATH=$PYTHONPATH:/usr/lib/python3/dist-packages ~~~ ### Err template error while templating string: Could not load \"search\": 'search'. ~~~ TASK [dns_update_resolv_conf : Remove immutable attribute] ************************************************************************************************** fatal: [localhost]: FAILED! => {"msg": "The conditional check 'stat_resolv_conf.stat.attr_flags | search(\"i\")' failed. The error was: template error while templating string: Could not load \"search\": 'search'. String: {% if stat_resolv_conf.stat.attr_flags | search(\"i\") %} True {% else %} False {% endif %}. Could not load \"search\": 'search'\n\nThe error appears to be in '/home/jean/code/dns_update_resolv_conf/roles/dns_update_resolv_conf/tasks/main.yml': line 147, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Remove immutable attribute\n ^ here\n"} ~~~ #### Solution Change ~~~yaml when: - result | failed ~~~ By ~~~yaml when: - result is failed ~~~ Example : ~~~yaml - name: Remove immutable attribute become: true ansible.builtin.file: path: "{{ resolv_filepath }}" attributes: "-i" # when: stat_resolv_conf.stat.attr_flags | search("i") when: stat_resolv_conf.stat.attr_flags is search("i") ~~~ ### Pb passer un boolean ou des listes en extravars à Ansible #### Solution Passer par du JSON ~~~ --extra-vars '{"abc": false}' --extra-vars '{"abc": ["elm",] }' ~~~ ## Test Voir : * [Monkeyble: Framework de test bout en bout pour Ansible](https://linuxfr.org/news/presentation-de-monkeyble-framework-de-test-bout-en-bout-pour-ansible) * ansible-test * Molecule * bats * [Test Kitchen](https://blog.stephane-robert.info/post/test-role-ansible-kitchenci-serverspec/) * https://docs.openstack.org/openstack-ansible/latest/contributors/testing.html ~~~bash ansible-test sanity --list-tests ansible-test sanity --docker ~~~ ### Molecule [Introducing Ansible Molecule with Ansible Automation Platform]([https://developers.redhat.com/articles/2023/09/13/introducing-ansible-molecule-ansible-automation-platform) ## Debug ~~~ env ANSIBLE_NOCOLOR=1 ansible-playbook -vvvvv ~~~ Voir le module debug ~~~ env ANSIBLE_DEBUG=1 ansible-playbook ~~~ ### Ansible-lint Voir : * https://ansible.readthedocs.io/projects/lint/configuring/#specifying-configuration-files * [Ansible-lint un vérificateur de syntaxe yaml playbook / rôle](https://github.com/willthames/ansible-lint) `.ansible-lint` ~~~yaml --- profile: null exclude_paths: - test/playbook.yml ~~~ ~~~yaml --- # Offline mode disables installation of requirements.yml and schema refreshing offline: true profile: production exclude_paths: - .git/ - .github/ - .gitlab/ - .cache/ warn_list: - var_naming - idiom skip_list: - var-naming[no-role-prefix] ~~~ `.ansible-lint-ignore` ~~~python roles/agent/defaults/main.yml var-naming[no-role-prefix] ~~~ Exeption : Utiliser **skip_ansible_lint** Exemple : ~~~yaml - name: Kustomize get image become: true become_user: "{{ user_k8s }}" ansible.builtin.shell: chdir: "{{ myhome }}/awx-operator" cmd: "{{ myhome }}/awx-operator/bin/kustomize build config/default" changed_when: false register: reg_image tags: skip_ansible_lint ~~~ ### Syntax Voir : * `ansible-playbook --syntax-check` * Ansible-lint ### Callback plugin https://beingasysadmin.wordpress.com/2015/06/03/ping-your-ansible-from-slack/ ## Autres ~~~python ansible_python_interpreter=/home/user/network-automation/venv/bin/python ~~~