Ansible-Cleanup: A CLI tool to find and remove unused playbooks, tasks, and variables

Ansible-cleanup provides a command line tool to find and remove unused playbooks, tasks, group variables, and host variables. It maintains a clean codebase by recursively scanning your Ansible repository and listing files that are safe to delete.

Features

  • Identify unused playbooks and tasks: Scans the repository to find all unused playbooks and tasks. It analyzes the codebase and determines which playbooks and tasks are no longer referenced or used.
  • Find unused YAML files in group_vars and host_vars: Parses the “hosts” file, load all hosts and groups into a data structure. It then scans the group_vars and host_vars directories, identifying any YAML files that correspond to hosts or groups that no longer exist. This ensures that your variable files remain relevant and up-to-date.

Installation

Here is how to install ansible-cleanup using pip:

pip install --user git+https://github.com/jamescherti/ansible-cleanup

The pip command above will install the executable files in ~/.local/bin/.

Command Line Interface

The ansible-cleanup executable routes execution to specific cleanup modules using subcommands.

ansible-cleanup imports

This subcommand acts as a static code analyzer for your Ansible execution paths. It takes a root playbook (or multiple playbooks) as an argument and recursively traces every import_playbook, include_tasks, import_role, and related Ansible includes. It then compares the files it successfully resolved against all the YAML files in your repository to find the orphans.

As infrastructure evolves, old task files and sub-playbooks are often disconnected from the main execution tree but are left behind in the repository. Manually tracing YAML includes across dozens of files is tedious and prone to human error. This command automates the discovery of dead code, ensuring your repository only contains files that are actually executed.

Usage:

Pass your primary entry-point playbook (e.g., site.yml or main.yml) as an argument. The script will output the absolute paths of any .yml or .yaml files that are not referenced anywhere in the execution tree.

$ ansible-cleanup imports site.yaml
/path/to/repo/playbooks/old_deployment_tasks.yml
/path/to/repo/playbooks/deprecated_setup.yaml

ansible-cleanup vars

This subcommand manages your variable definitions. It reads your local hosts inventory file and builds a comprehensive list of all active hosts and groups. It then cross-references this active list against the files located in your host_vars and group_vars directories to find files named after hosts or groups that are not defined in the inventory.

When servers are decommissioned or host groups are renamed, engineers frequently remove them from the hosts file but forget to delete the corresponding variable files in host_vars/ or group_vars/. Over time, this leads to significant repository bloat and confusion over which variables are actually applied. This tool securely flags those forgotten files for deletion.

Execute the command in the directory containing your hosts file, host_vars directory, and group_vars directory. It requires no arguments.

Usage:

$ ansible-cleanup vars
/path/to/repo/host_vars/decommissioned-db-server-01.yml
/path/to/repo/group_vars/legacy-web-nodes.yaml

License

Copyright (c) 2009-2026 James Cherti

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

Links

Ansible-role-flatpak, an Ansible Role that Installs and Configures Flatpak

License

The ansible-role-flatpak Ansible role installs and configures Flatpak, adds Flathub as a remote repository, and optionally manages Flatpak packages and updates. This role supports specific Linux distributions: Debian-based, Gentoo, and Arch Linux.

Requirements

  • Supported operating systems: Debian/Ubuntu (and their derivatives), Gentoo, or Arch Linux.
  • Ansible collections:
    • community.general

Role Variables

The following variables can be set to customize the role’s behavior:

Variable Description Default
flatpak_packages List of Flatpak packages to install. []
flatpak_update_script Whether to enable automatic daily updates and cleanup of Flatpak packages. false
flatpak_update_script_cmd_prefix Optional prefix command to run before the Flatpak update command (e.g., nice, ionice).
flatpak_update_script_cmd_suffix Optional suffix to append to the Flatpak update command. ‘>/dev/null’
flatpak_update_script_remove_unused Delete unused Flatpak packages after a successful update true
flatpak_update_script_script_path Path to the update script. ‘/etc/cron.daily/flatpak-update’
flatpak_install_desktop_portal Install the desktop portal. Values: ” (no desktop portal), “gtk”, or “gnome”. Can be a string or a list of values, such as [“gtk”, “gnome”] [‘gtk’]
flatpak_proxy Proxy settings for Flatpak (optional). Leave empty if not using a proxy.

Author and license

The ansible-role-flatpak role has been written by James Cherti and is distributed under terms of the MIT license.

Copyright (C) 2025-2026 James Cherti

Distributed under terms of the MIT license.

Links

ansible-role-auto-upgrade – An Ansible role that automates upgrading Linux operating systems

The ansible-role-auto-upgrade Ansible role automates regular upgrades of supported operating systems:

  • Debian-based systems (e.g., Ubuntu, Debian, Linux Mint). This role provides a simpler alternative to unattended-upgrades for applying system updates.

(In future versions, Arch Linux and Gentoo will also be supported.)

License

Copyright (c) 2025-2026 James Cherti.

Distributed under terms of the MIT license.

Do you like ansible-role-auto-upgrade?

Please star ansible-role-auto-upgrade on GitHub.

Links

ansible-role-reniced – An Ansible role that configures reniced on Debian and Ubuntu based operating systems

The ansible-role-reniced Ansible role configures reniced on Debian and Ubuntu based operating systems.

Customizations

When reniced_conf is defined, it is used as the configuration content.

Include the role using:

- name: Import role reniced
  when: ansible_facts.os_family == "Debian"
  ansible.builtin.import_role:
    name: reniced

Variables:

reniced_conf: |
  # high prio network services
  0 ^apache
  0 ^nfsd
  0 ^ntpd
  0 ^openvpn
  0 ^portmap
  0 ^ppp
  0 ^rpc.
  0 ^sshd

  # medium prio network services
  5 ^inn$
  5 ^mysqld

  # low prio network services
  15i ^amavisd-new
  15i ^clamd
  15 ^controlchan
  15 ^exim4
  15 ^freshclam
  15 ^innwatch
  12 ^mailman
  15 ^rc.news
  15i ^spamd

  # long running user processes (screen)
  3 ^irssi

  # test OOM settings
  o1 bash

Author and license

Copyright (C) 2024-2026 James Cherti.

Distributed under terms of the MIT license.

Links

ansible-role-apt – An Ansible role that manages the APT configuration and updates the /etc/apt/sources.list for Debian and Ubuntu systems

License

The ansible-role-apt Ansible role manages the APT configuration and updates the /etc/apt/sources.list for Debian and Ubuntu systems.

Role variables

Important variables:

Variable Description Default
apt_debian_community Enables community repositories (Debian contrib and main, or Ubuntu universe) true
apt_debian_nonfree Enables non-free repositories (Debian non-free, non-free-firmware, or Ubuntu multiverse) true
apt_debian_backports Enables the backports repository on Debian (no effect on Ubuntu systems) false
apt_deb_src Enables source package repositories (deb-src entries) false

Other variables:

Variable Description Default
apt_mirror_url_debian Debian mirror URL "http://deb.debian.org/debian"
apt_mirror_url_debian_security Debian security mirror URL "http://deb.debian.org/debian-security"
apt_mirror_url_ubuntu Ubuntu mirror URL "http://archive.ubuntu.com/ubuntu"

Author and license

The ansible-role-apt role has been written by James Cherti and is distributed under terms of the MIT license.

Copyright (C) 2000-2026 James Cherti

Distributed under terms of the MIT license.

Links

Emacs flymake-ansible-lint.el – A Flymake backend for ansible-lint

Build Status MELPA MELPA Stable License

The flymake-ansible-lint package provides a Flymake backend for ansible-lint, enabling real-time syntax and style checking for Ansible playbooks and roles within Emacs.

(This package can also work with Flycheck: simply use the flymake-flycheck package, which allows any Emacs Flymake backend to function as a Flycheck checker.)

Requirements

Installation

To install flymake-ansible-lint from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code to your Emacs init file to install flymake-ansible-lint from MELPA:

(use-package flymake-ansible-lint
  :commands flymake-ansible-lint-setup
  :hook (((yaml-ts-mode yaml-mode) . flymake-ansible-lint-setup)
         ((yaml-ts-mode yaml-mode) . flymake-mode)))

Customizations

You can configure ansible-lint parameters using the flymake-ansible-lint-args variable:

(setq flymake-ansible-lint-args '("--offline"
                                  "-x"
                                  "run-once[play],no-free-form"))

You can also enable automatic project directory detection to pass the --project-dir argument to the linter automatically. This feature detects the project or version control root and uses it as the project directory:

(setq flymake-ansible-lint-auto-project-dir t)

This ensures that Ansible caches its data inside a single .ansible directory at the project root, rather than cluttering your repository by creating an .ansible folder in every subdirectory where a file is linted, keeping your project tree clean.

Frequently asked questions

Why are some ansible-lint error messages truncated?

This issue is a known bug in ansible-lint, not in flymake-ansible-lint.

It is ansible-lint that truncates some error messages:

$ ansible-lint -p test.yaml
test.yaml:5: yaml[truthy]: Truthy value should be one of

Location of the temporary files created by the flymake-ansible-lint package

By default, the flymake-ansible-lint package creates temporary files in the same directory as the Ansible YAML file currently being edited.

For example, when editing: /home/user/test/myfile.yaml, the package may generate temporary files such as: /home/user/test/flymake_1_myfile.yaml /home/user/test/flymake_2_myfile.yaml

These temporary files are automatically removed once flymake-ansible-lint completes its analysis.

(This behavior is controlled by the variable flymake-ansible-lint-tmp-files-enabled. Keeping flymake-ansible-lint-tmp-files-enabled enabled is important because it allows Flymake to lint the most recent in-memory state of the buffer, including unsaved modifications. Without these temporary files, Flymake would have to rely on the last saved version of the file, which might not reflect the current edits. This ensures that linting diagnostics remain accurate, up to date, and synchronized with the actual buffer contents, providing immediate feedback while editing.)

License

The flymake-ansible-lint Emacs package has been written by James Cherti and is distributed under terms of the GNU General Public License version 3, or, at your choice, any later version. This package uses flymake-quickdef, by Karl Otness.

Copyright (C) 2024-2026 James Cherti

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • compile-angel.el: Speed up Emacs! This package guarantees that all .el files are both byte-compiled and native-compiled, which significantly speeds up Emacs.
  • outline-indent.el: An Emacs package that provides a minor mode that enables code folding and outlining based on indentation levels for various indentation-based text files, such as YAML, Python, and other indented text files.
  • easysession.el: Easysession is lightweight Emacs session manager that can persist and restore file editing buffers, indirect buffers/clones, Dired buffers, the tab-bar, and the Emacs frames (with or without the Emacs frames size, width, and height).
  • vim-tab-bar.el: Make the Emacs tab-bar Look Like Vim’s Tab Bar.
  • elispcomp: A command line tool that allows compiling Elisp code directly from the terminal or from a shell script. It facilitates the generation of optimized .elc (byte-compiled) and .eln (native-compiled) files.
  • tomorrow-night-deepblue-theme.el: The Tomorrow Night Deepblue Emacs theme is a beautiful deep blue variant of the Tomorrow Night theme, which is renowned for its elegant color palette that is pleasing to the eyes. It features a deep blue background color that creates a calming atmosphere. The theme is also a great choice for those who miss the blue themes that were trendy a few years ago.
  • Ultyas: A command-line tool designed to simplify the process of converting code snippets from UltiSnips to YASnippet format.
  • flymake-bashate.el: A package that provides a Flymake backend for the bashate Bash script style checker.
  • inhibit-mouse.el: A package that disables mouse input in Emacs, offering a simpler and faster alternative to the disable-mouse package.
  • quick-sdcv.el: This package enables Emacs to function as an offline dictionary by using the sdcv command-line tool directly within Emacs.
  • enhanced-evil-paredit.el: An Emacs package that prevents parenthesis imbalance when using evil-mode with paredit. It intercepts evil-mode commands such as delete, change, and paste, blocking their execution if they would break the parenthetical structure.
  • stripspace.el: Ensure Emacs Automatically removes trailing whitespace before saving a buffer, with an option to preserve the cursor column.
  • persist-text-scale.el: Ensure that all adjustments made with text-scale-increase and text-scale-decrease are persisted and restored across sessions.
  • pathaction.el: Execute the pathaction command-line tool from Emacs. The pathaction command-line tool enables the execution of specific commands on targeted files or directories. Its key advantage lies in its flexibility, allowing users to handle various types of files simply by passing the file or directory as an argument to the pathaction tool. The tool uses a .pathaction.yaml rule-set file to determine which command to execute. Additionally, Jinja2 templating can be employed in the rule-set file to further customize the commands.
  • kirigami.el: The kirigami Emacs package offers a unified interface for opening and closing folds across a diverse set of major and minor modes in Emacs, including outline-mode, outline-minor-mode, outline-indent-minor-mode, org-mode, markdown-mode, vdiff-mode, vdiff-3way-mode, hs-minor-mode, hide-ifdef-mode, origami-mode, yafolding-mode, folding-mode, and treesit-fold-mode. With Kirigami, folding key bindings only need to be configured once. After that, the same keys work consistently across all supported major and minor modes, providing a unified and predictable folding experience.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

Ansible: ansible-role-tuned, an Ansible role which configures tuned

License

The ansible-role-tuned Ansible playbook manages the installation, configuration, and activation of the tuned service.

Tuned is a dynamic adaptive system tuning tool used in Linux environments to optimize performance by adjusting various system settings dynamically. It provides pre-defined profiles that target specific use cases, such as high throughput, low latency, and energy saving, and automatically applies these configurations based on system activity.

For high traffic servers, using Tuned is beneficial as it can enhance network throughput and responsiveness by adjusting parameters like CPU frequency scaling, I/O scheduling, and network stack settings. This optimization results in improved server performance, reduced latency, and better handling of high loads, ultimately leading to a more efficient and reliable infrastructure for handling significant network traffic.

Features

  • Install tuned and configure it using the Ansible variables: tuned_daemon, tuned_dynamic_tuning, tuned_sleep_interval, tuned_update_interval, and tuned_recommend_command.
  • Activate the specified tuned profile using the tuned_profile variable. (When the tuned_profile is not set, the role installs only tuned.)
  • Supports Debian/Ubuntu and RedHat family based operating systems.

Usage

Example Playbook

Here is an example of how to use ansible-role-tuned after installing it in the roles/tuned directory:

- hosts: SERVER
  roles:
    - {role: tuned,
       tuned_profile: "throughput-performance"}

Author and license

Copyright (C) 2020-2026 James Cherti.

Distributed under terms of the MIT license.

Links

Ansible: Installing and configuring Gitolite using Ansible for secure Git repository management

License

The ansible-role-gitolite Ansible role automates the installation and configuration of Gitolite, a Git repository management system. It facilitates the setup of Gitolite on remote servers, including user access control and repository creation, ensuring a consistent and reproducible deployment.

Requirements

  • Operating system: Debian-based (e.g., Ubuntu, Mint), RedHat-based (e.g., CentOS, Fedora), or Arch Linux

Author and License

Copyright (C) 2024-2026 James Cherti.

Distributed under terms of the MIT license.

Links

Ansible: Reintegrating /etc/rc.local in Linux systems that use Systemd as their init system

For years, /etc/rc.local has been a staple in Linux administration, providing a straightforward means to execute scripts or commands automatically upon system startup. However, with the transition to newer init systems like systemd, the /etc/rc.local script is no longer executed at boot time.

Ansible tasks that restore the /etc/rc.local script

The following Ansible tasks will create and configure /etc/rc.local and also ensure its execution by Systemd at boot time.

---
# Description: Reintegrate /etc/rc.local in Linux systems that use Systemd 
#              as their init system.
# Author: James Cherti
# License: MIT
# URL: https://www.jamescherti.com/ansible-config-etc-rc-local-linux-systemd/

- name: Check if /etc/rc.local exists
  stat:
    path: "/etc/rc.local"
  register: etc_rc_local_file

- name: Create the file /etc/rc.local should it not already exist
  copy:
    dest: /etc/rc.local
    owner: root
    group: root
    mode: 0750
    content: |
      #!/usr/bin/env bash
  when: not etc_rc_local_file.stat.exists

- name: Create the systemd service rc-local.service
  register: rc_local
  copy:
    dest: /etc/systemd/system/rc-local.service
    owner: root
    group: root
    mode: 0644
    content: |
      [Unit]
      Description=/etc/rc.local compatibility

      [Service]
      Type=oneshot
      ExecStart=/etc/rc.local
      TimeoutSec=0
      RemainAfterExit=yes
      SysVStartPriority=99

      [Install]
      WantedBy=multi-user.target

- name: Reload systemd daemon
  systemd:
    daemon_reload: yes
  when: rc_local.changed|bool

- name: Enable rc-local.service
  systemd:
    name: rc-local
    enabled: true
Code language: YAML (yaml)

Vim: Open documentation in a new tab for the word under the cursor (Vim help, Python, man pages, Markdown, Ansible…)

The following Vim script (VimL) function can be used to make Vim open the documentation of the word under the cursor in a new tab for various languages and tools such as Vim help (:help), Python (Pydoc), Markdown (sdcv dictionary), man pages (Vim’s built-in ‘:Man’), and Ansible (ansible-doc).

The VimL function is also extensible, meaning that you can adapt it to work with any other documentation tool. By default, the key mapping upper-case “K” can be used to open the documentation for the word under the cursor in a new tab.

" Language: Vim script
" Author: James Cherti
" License: MIT
" Description: Vim: open help/documentation in a new tab 
"              (Vim script, Python, Markdown, man pages, Ansible...).
"              Press upper-case K to open help for the word under the cursor.
" URL: https://www.jamescherti.com/vim-open-help-documentation-in-a-new-tab/

function! TabHelp(word) abort
  let l:cmd = ''

  let l:tabhelpprg = get(b:, 'tabhelpprg', '')
  if l:tabhelpprg ==# ''
    normal! K
    return
  endif

  if l:tabhelpprg[0] ==# ':'
    if stridx(l:tabhelpprg, '%s') ==# -1
      execute l:tabhelpprg
    else
      execute printf(l:tabhelpprg, fnameescape(a:word))
    endif
    return
  else
    let l:cmd = 'silent read! '
    if stridx(l:tabhelpprg, '%s') ==# -1
      let l:cmd .= l:tabhelpprg
    else
      let l:cmd .= printf(l:tabhelpprg, shellescape(a:word))
    endif
  endif

  execute 'silent tabnew help:' . fnameescape(a:word)

  setlocal modifiable
  silent normal! ggdG
  silent normal! 1Gdd
  if l:cmd !=# ''
    execute l:cmd
  endif
  silent normal! gg0
  setlocal nomodifiable
  setlocal noswapfile
  setlocal nowrap
  setlocal nonumber
  setlocal nomodified
  setlocal buftype=nofile
  setlocal bufhidden=delete
  if exists('&relativenumber')
    setlocal norelativenumber
  endif
  if exists('&signcolumn')
    setlocal signcolumn=no
  endif
  setlocal nofoldenable
  setlocal foldcolumn=0
endfunction

augroup TabHelp
  autocmd!
  autocmd FileType vim let b:tabhelpprg = ':tab help %s'
  autocmd FileType sh,zsh,csh if ! exists(':Man') | runtime ftplugin/man.vim | endif | let b:tabhelpprg = ':tab Man %s'
  autocmd FileType yaml.ansible if executable('ansible-doc') | let b:tabhelpprg = 'ansible-doc %s' | endif
  autocmd FileType markdown if executable('sdcv') | let b:tabhelpprg = 'sdcv %s' | endif
  autocmd FileType vim,sh,zsh,csh,yaml.ansible,markdown nnoremap <silent> <buffer> K :call TabHelp(expand('<cword>'))<CR>
augroup ENDCode language: Vim Script (vim)