Organizing My Ansible Project Into Roles

Table of Contents

Thus far, I’ve been writing ad hoc playbooks and learning how all the pieces go together. It’s been largely disorganized, and I’ve made some structural mistakes in the process.

I wanted to take a moment to correct these mistakes, in the hopes of making further progress more efficient.

Take a look at the relevant git commit here


I’m not going to go into every role in depth, but will pick one or two items I restructured.

I moved ad hoc playbooks into library, and playbooks that call a set of roles into the root directory.


Here’s the repository server main playbook. The first role is for the vm host, because it needs to prepare a bind mount for the later steps.

- name: Prepare storage
  gather_facts: true

    - preparestorage

# Allow container to reboot if necessary.
  - name: sleep
      seconds: 15

- name: Configure local repo server
  gather_facts: false
  user: root

    - chronyclient
    - kickstart
    - reposerver
    - tftpserver


This mounts the storage on the VM host and makes it available to the guest, and then restarts the guest if any changes have been made.

I enclose it in a block that only runs if the UUID has been defined as a host variable.

- name:  Make sure mount directory exists
  - file:
      state: 'directory'
      path: /mnt/external
      owner: root
      group: root
      mode: 0755

  - mount:
      path: /mnt/external
      src: 'UUID={{ storage_uuid }}'
      fstype: ext4
      opts: relatime
      state: mounted

  - command: "pct set {{ storage_guest_vmid }} -mp0 /mnt/external,mp=/data"
    notify: restart container

  # Load vars for handler
  - include_vars: "~/0/vault/proxmox.yml"
    no_log: true

  when: storage_uuid is defined


This was covered here, and very little has changed.

kickstart & tftpboot

These roles have also changed very little since I covered them [here](


This is an ad hoc playbook that configures servers for SSH access and sets up local repository access.

- name: enable SSH user
  hosts: all
  user: root

    - sshenableuser

- name: disable SSH root
  hosts: all
  become: true

    - sshdisableroot
    - repoclient


The SSH role is covered in depth here, however I did smarten up the script a bit.

I streamlined the main playbook by testing against the ansible_distribution variable. Excerpts:

- name: Import variables specific to distribution
  include_vars: "{{ item }}"
    - "vars/{{ ansible_distribution }}-{{ ansible_distribution_version }}.yml"
    - "vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml"
    - "vars/{{ ansible_distribution }}.yml"
    - "vars/default.yml"
- name: Allow 'wheel' group to have passwordless sudo
    dest: /etc/sudoers
    state: present
    regexp: '{{ sudo_regex }}'
    line: '{{ sudo_line }}'
    validate: 'visudo -cf %s'
  when: (ansible_distribution == "CentOS")

- name: Allow 'sudo' group to have passwordless sudo
    dest: /etc/sudoers
    state: present
    regexp: '^%sudo'
    line: '%sudo ALL=(ALL) NOPASSWD: ALL'
    validate: 'visudo -cf %s'
  when: (ansible_distribution == "Debian")


Similarly, I used distro variables so only Centos hosts are set up on the local repository. I also used the yum_repository module over the solution I had previously found online:

- name: Set up local repositories
    - yum_repository:
        name: '{{ item }}'
        state: absent
        - base
        - extras
        - updates
        - epel

    - copy:
        src: 'local.repo'
        dest: '/etc/yum.repos.d/local.repo'
        owner: 'root'
        group: 'root'
        mode: '0644'
  when: (ansible_distribution == "CentOS")


The working layout has been a mess up to this point, and I’m very happy with the progress that this simple change represents.

Future work should be much easier to implement now that I have the makings of a real structure.

If you’re interested in the git project, you can see the relevant commit here