Ansible - Spotter un outil qui complète Ansible-lint
Publié le : 26 février 2023 | Mis à jour le : 27 juin 2023Table des matières
J’ai découvert récemment spotter, un outil qui permet de contrôler la qualité du
code Ansible
. Vous allez me dire, mais Ansible-Lint le fait déjà ! Oui, mais
spotter
possède quelques fonctions supplémentaires.
Introduction
Pour ceux qui ne connaissent pas ansible-lint
, je rappelle juste que c’est un
outil qui vérifie vos playbooks ansible
à la recherche d’erreurs, mais aussi
recommande des améliorations. Steampunk Spotter, fait la même chose, mais
va plus loin.
Découverte de spotter
Dans les caractéristiques que j’ai retrouvées sur le site de Spotter
, j’ai pu
lire qu’il devrait permettre de :
- structurer vos playbooks pour qu’ils soient lisibles
- éviter les anti-patterns les plus courants dans les playbooks,
- identifier des erreurs difficiles à corriger,
- identifier les changements de nom de modules et de collections,
- identifier les paramètres manquants,
- identifier les modules obsolètes
- identifier les paramètres obsolètes,
- afficher les fqcn complet,
- aide les mise à jour de vos codes
Ansible
vers de nouvelles versions d'Ansible
. - …
Spotter
est plus qu’un simple outil de lint
. En effet, il possède un site qui
recense tous les rapports d’exécution.
Spotter
propose plusieurs plans de souscriptions dont un gratuit permettant de
réaliser 100 scans/mois.
Création du compte
Pour créer le compte, il faut se rendre à cette adresse.
Installation de spotter
Spotter
est un programme écrit en python et donc pour l’installer rien de plus
simple avec pip
:
pip install steampunk-spotter
Pour l’authentification, vous avez le choix :
- D’utiliser le combo user/mot de passe:
- via les paramètres
-u <utilisateur> -p <mot-de-passe>
. - via les variables d’environnement
SPOTTER_USERNAME
etSPOTTER_PASSWORD
.
- via les paramètres
- D’utiliser un token que vous aurez généré sur le portail de spotter dans la section my profil.
- via le paramètre
-t <api-token>
. - via la variable d’environnement
SPOTTER_API_TOKEN
.
- via le paramètre
Notre jeu de test
Je vais utiliser le playbook suivant pour vous montrer en quoi spotter
fournit
d’autres recommandations que celles retournées par ansible-lint
:
---
- hosts: all
gather_facts: false
become: true
vars:
# datasource=github-releases depName=rundeck/rundeck
rundeck_version: v3.4.10
# datasource=github-tags depName=ansible-community/ansible-build-data
ansible_version: 5.5.0
rundeck_os_group: rundeck
rundeck_os_user: rundeck
timezone: Europe/Paris
rundeck_installation_dir: /opt
rundeck_data_dir: /data/rundeck
nfs_path: devbox1:/data
force_install: false
rundeck_version_running: ""
ansible_python_interpreter: /usr/libexec/platform-python
server_address: "rundeck.robert.local"
rundeck_xmx: "1024m"
rundeck_xms: "256m"
rundeck_maxmetaspacesize: "256m"
## Nginx
nginx_version: 1.18
nginx_fqdn: rundeck.robert.local
cert_file: "{{ nginx_fqdn }}+3.pem"
cert_key: "{{ nginx_fqdn }}+3-key.pem"
tasks:
- name: Wait 600 seconds for target connection to become reachable/usable
ansible.builtin.wait_for_connection:
- name: Get ansible_facts
ansible.builtin.setup:
- name: "Check rundeck-latest link stat in {{ rundeck_installation_dir }}"
ansible.builtin.stat:
path: "{{ rundeck_installation_dir }}/rundeck"
register: running_version
tags: version
- name: Register current running version if any
ansible.builtin.set_fact:
rundeck_version_running: >-
{{
running_version.stat.lnk_target
| regex_replace('^.*rundeck-(\d*\.\d*\.\d*-\d*)', '\1')
}}
when:
- running_version.stat.exists | default(false)
- running_version.stat.islnk | default(false)
tags: version
- name: Create group rundeck
ansible.builtin.group:
name: "{{ rundeck_os_group }}"
state: present
- name: Create user rundeck
ansible.builtin.user:
name: "{{ rundeck_os_user }}"
groups: "{{ rundeck_os_group }}"
append: true
- name: Install packages
ansible.builtin.package:
state: present
name:
- glibc-common
- glibc-langpack-en
- glibc-langpack-fr
- java
- tar
- unzip
- epel-release
- python3-libsemanage
- python3-pip
- policycoreutils-python-utils
- python3-libselinux
- name: Install tools for debug
ansible.builtin.package:
name:
- htop
- net-tools
- python39
state: present
- name: Correct python version selected
community.general.alternatives:
name: python3
path: /usr/bin/python3.9
- name: Set as default locale
ansible.builtin.command: localectl set-locale LANG=en_US.UTF-8
- name: Set timezone
community.general.timezone:
name: "{{ timezone }}"
- name: Mount nfs /data
ansible.posix.mount:
src: "{{ nfs_path }}"
path: /data
state: mounted
fstype: nfs
- name: Mount /dev/shm
ansible.posix.mount:
fstype: tmpfs
name: "/dev/shm"
opts: "defaults,nodev,nosuid,noexec"
src: tmpfs
state: mounted
- name: Create rundeck directory
ansible.builtin.file:
path: "{{ item }}"
state: "directory"
owner: "{{ rundeck_os_user }}"
group: "{{ rundeck_os_group }}"
mode: "0755"
with_items:
- "{{ rundeck_installation_dir }}"
- "{{ rundeck_data_dir }}"
- name: Get list of services
ansible.builtin.service_facts:
- name: Stop rundeck service
ansible.builtin.service:
name: rundeck
enabled: true
state: stopped
when: "'rundeck.service' in services and (rundeck_version != rundeck_version_running or force_install)"
- name: Create directory
ansible.builtin.file:
path: "{{ rundeck_installation_dir }}/rundeck-{{ rundeck_version }}"
state: directory
owner: "{{ rundeck_os_user }}"
group: "{{ rundeck_os_group }}"
mode: "0755"
when: (rundeck_version_running | length == 0 or rundeck_version != rundeck_version_running or force_install)
- name: Install rundeck
become_user: rundeck
ansible.builtin.get_url:
url: "https://packagecloud.io/pagerduty/rundeck/packages/java/org.rundeck/rundeck-{{ rundeck_version }}.war/artifacts/rundeck-{{ rundeck_version }}.war/download"
dest: "{{ rundeck_installation_dir }}/rundeck-{{ rundeck_version }}/rundeck.war"
owner: "{{ rundeck_os_user }}"
mode: "0755"
when: (rundeck_version_running | length == 0 or rundeck_version != rundeck_version_running or force_install)
- name: Uncompress war
become_user: "{{ rundeck_os_user }}"
ansible.builtin.command:
cmd: "java -jar rundeck.war --installonly"
chdir: "{{ rundeck_installation_dir }}/rundeck-{{ rundeck_version }}"
environment:
RDECK_BASE: "{{ rundeck_installation_dir }}/rundeck-{{ rundeck_version }}"
when: (rundeck_version_running | length == 0 or rundeck_version != rundeck_version_running or force_install)
- name: Update symlink rundeck
ansible.builtin.file:
path: "{{ rundeck_installation_dir }}/rundeck"
src: "{{ rundeck_installation_dir }}/rundeck-{{ rundeck_version }}"
owner: "{{ rundeck_os_user }}"
group: "{{ rundeck_os_group }}"
state: link
when: (rundeck_version_running | length == 0 or rundeck_version != rundeck_version_running or force_install)
- name: Update configuration
ansible.builtin.template:
src: templates/rundeck-config.properties
dest: "{{ rundeck_installation_dir }}/rundeck/server/config"
owner: "{{ rundeck_os_user }}"
group: "{{ rundeck_os_group }}"
mode: "0644"
when: (rundeck_version_running | length == 0 or rundeck_version != rundeck_version_running or force_install)
- name: Upgrade pip
ansible.builtin.pip:
name:
- pip
- name: Install pip configuration
ansible.builtin.copy:
src: pip.conf
dest: /etc/
owner: root
group: root
mode: "0644"
- name: Install ansible
ansible.builtin.pip:
name:
- ansible
version: "{{ ansible_version }}"
- name: Get list of services
ansible.builtin.service_facts:
- name: Create systemd service configuration
ansible.builtin.template:
src: "rundeck.service"
dest: "/etc/systemd/system"
mode: "0755"
- name: Reload systemd service configuration
ansible.builtin.service:
name: rundeck
enabled: true
state: restarted
daemon_reload: true
- name: Add /usr/local/bin to path
ansible.builtin.copy:
dest: /etc/profile.d/rundeck.sh
content: "PATH=$PATH:/usr/local/bin"
owner: root
group: root
mode: "0644"
# Deploy Nginx
- name: Install nginx
ansible.builtin.dnf:
name: '@nginx:{{ nginx_version }}'
state: present
- name: Copy nginx config
ansible.builtin.copy:
src: nginx.conf
dest: /etc/nginx
mode: "0644"
- name: Template nginx configuration
ansible.builtin.template:
src: rundeck.conf
dest: /etc/nginx/conf.d/rundeck.conf
mode: "0640"
notify: reload_nginx
- name: Copy certificate
ansible.builtin.copy:
src: "certificats/{{ item }}"
dest: "/etc/ssl/{{ item }}"
mode: "0640"
with_items:
- "{{ cert_file }}"
- "{{ cert_key }}"
notify: reload_nginx
- name: Set sebool httpd can network connect to on
ansible.posix.seboolean:
name: httpd_can_network_connect
state: true
persistent: true
- name: Enable & start nginx
ansible.builtin.service:
name: nginx
enabled: true
state: started
handlers:
- name: Reload_nginx
ansible.builtin.service:
name: nginx
state: reloaded
Le résultat avec ansible-lint
(j’ai installé la dernière version 6.13.1):
ansible-lint deploy_rundeck.yml
WARNING Listing 4 violation(s) that are fatal
name[play]: All plays should be named.
deploy_rundeck.yml:2
no-changed-when: Commands should not change things if nothing needs doing.
deploy_rundeck.yml:85 Task/Handler: Set as default locale
yaml[line-length]: Line too long (169 > 160 characters)
deploy_rundeck.yml:132
no-changed-when: Commands should not change things if nothing needs doing.
deploy_rundeck.yml:137 Task/Handler: Uncompress war
Read documentation for instructions on how to ignore specific rule violations.
Rule Violation Summary
count tag profile rule associated tags
1 name[play] basic idiom
1 yaml[line-length] basic formatting, yaml
2 no-changed-when shared command-shell, idempotency
Failed after min profile: 4 failure(s), 0 warning(s) on 1 files.
Le résultat avec spotter :
spotter scan deploy_rundeck.yml
deploy_rundeck.yml:32:7: WARNING: Default value for filter parameter changed between module versions 2.10.17 and 2.11.0 from "*" to []. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:34:7: WARNING: Default value for follow parameter changed between module versions 2.7.18 and 2.8.0 from "no" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:34:7: WARNING: Default value for get_md5 parameter changed between module versions 2.4.6 and 2.9.0 from "yes" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:34:7: WARNING: Default value for get_mime parameter changed between module versions 2.3.3 and 2.4.0, 2.7.18 and 2.8.0 from true to "yes", from "yes" to true. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:34:7: WARNING: Default value for get_checksum parameter changed between module versions 2.7.18 and 2.8.0 from "yes" to true. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:34:7: WARNING: Default value for get_attributes parameter changed between module versions 2.3.3 and 2.4.0, 2.7.18 and 2.8.0 from true to "yes", from "yes" to true. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:54:7: WARNING: Default value for force parameter changed between module versions 2.4.6 and 2.5.0 from "no" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:54:7: WARNING: Default value for remove parameter changed between module versions 2.4.6 and 2.5.0 from "no" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:54:7: WARNING: Default value for system parameter changed between module versions 2.4.6 and 2.5.0 from "no" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:54:7: WARNING: Default value for move_home parameter changed between module versions 2.4.6 and 2.5.0 from "no" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:54:7: WARNING: Default value for non_unique parameter changed between module versions 2.4.6 and 2.5.0 from "no" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:81:7: HINT: Collection community.general version from the requirements.yml 4.6.0 does not match installed collection version 6.3.0. Consider updating your collection.
deploy_rundeck.yml:85:7: WARNING: Task does not enforce a state. Use creates or removes parameters to inform Ansible under what conditions should the command be run. If the executed command is enforcing the desired state already, use the changed_when keyword to inform Ansible when the state changed. The last resort is adding a when clause to the task or converting the current task into a handler.
deploy_rundeck.yml:85:7: WARNING: Default value for warn parameter changed between module versions 2.10.17 and 2.11.0 from true to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:87:7: HINT: Collection community.general version from the requirements.yml 4.6.0 does not match installed collection version 6.3.0. Consider updating your collection.
deploy_rundeck.yml:90:7: HINT: Required collection ansible.posix is missing from requirements.yml or requirements.yml is missing.
deploy_rundeck.yml:96:7: HINT: Required collection ansible.posix is missing from requirements.yml or requirements.yml is missing.
deploy_rundeck.yml:103:7: WARNING: Use of with_items is discouraged. Consider using loop instead.
deploy_rundeck.yml:103:7: WARNING: Default value for follow parameter changed between module versions 2.5.1 and 2.5.2 from false to true. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:121:7: WARNING: Default value for follow parameter changed between module versions 2.5.1 and 2.5.2 from false to true. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:129:7: WARNING: Default value for force parameter changed between module versions 2.7.18 and 2.8.0 from "no" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:129:7: WARNING: Default value for use_proxy parameter changed between module versions 2.7.18 and 2.8.0 from "yes" to true. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:129:7: WARNING: Default value for validate_certs parameter changed between module versions 2.7.18 and 2.8.0 from "yes" to true. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:129:7: WARNING: Default value for force_basic_auth parameter changed between module versions 2.7.18 and 2.8.0 from "no" to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:137:7: WARNING: Default value for warn parameter changed between module versions 2.10.17 and 2.11.0 from true to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:145:7: WARNING: Default value for follow parameter changed between module versions 2.5.1 and 2.5.2 from false to true. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:161:7: WARNING: Default value for editable parameter changed between module versions 2.3.3 and 2.4.0 from true to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:172:7: WARNING: Default value for editable parameter changed between module versions 2.3.3 and 2.4.0 from true to false. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:184:7: ERROR: daemon_reload is not a valid parameter in module ansible.builtin.service.
deploy_rundeck.yml:198:7: WARNING: Default value for lock_timeout parameter changed between module versions 2.8.2 and 2.8.3 from 0 to 30. Consider setting value of the parameter explicitly.
deploy_rundeck.yml:213:7: WARNING: Use of with_items is discouraged. Consider using loop instead.
deploy_rundeck.yml:222:7: HINT: Required collection ansible.posix is missing from requirements.yml or requirements.yml is missing.
------------------------------------------------------------------------
Overall status: ERROR
En effet, on voit bien que spotter fournit beaucoup plus de recommandations qu’ansible-lint. On remarque que la promesse d’aider à gérer les montées de versions d’Ansible est tenu. Donc, je valide son utilisation.
Installation de l’extension Vscode
Une extension est disponible et comme ansible-lint
permet de remonter les
erreurs au moment de certains événements comme la sauvegarde du fichier.
Conclusion
L’utilisation des deux outils est une combinaison gagnante et vous garantit
que vous obtiendrez un code ansible
plus fiable. Compte tenu du nombre limité
de scans par mois pour la version libre, il faudra corriger toutes les erreurs
remontées avec ansible-lint
avant de lancer spotter
. Pour ceux qui
découvrent ce blog, il regorge de billets sur les outils devops et en
particulier
ansible.