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

Overview

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.

reposerver.yml

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
  hosts: bronze.lan.nathancurry.com
  gather_facts: true

  roles:
    - preparestorage

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

- name: Configure local repo server
  hosts: repo.lan.nathancurry.com
  gather_facts: false
  user: root

  roles:
    - chronyclient
    - kickstart
    - reposerver
    - tftpserver

preparestorage

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
  block:
  - 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

chronyclient

This was covered here, and very little has changed.

kickstart & tftpboot

These roles have also changed very little since I covered them [here](http://www.nathancurry.com/blog/22-ansible-pxeboot-vms

library/init-server.yml

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

  roles:
    - sshenableuser

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

  roles:
    - sshdisableroot
    - repoclient

sshenableuser

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 }}"
  with_first_found:
    - "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
  lineinfile:
    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
  lineinfile:
    dest: /etc/sudoers
    state: present
    regexp: '^%sudo'
    line: '%sudo ALL=(ALL) NOPASSWD: ALL'
    validate: 'visudo -cf %s'
  when: (ansible_distribution == "Debian")

repoclient

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
  block:
    - yum_repository:
        name: '{{ item }}'
        state: absent
      with_items:
        - 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")

Conclusion

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