Introduction

I’d been wanting to check out Ansible for a while. When I learn a new technology I prefer to have a real use for it. Up to this point I hadn’t found one for Ansible, until I decided to switch my daily driver from Ubuntu to Debian. I realized that I could probably codify all of the software installs and configuration using Ansible, so that the next time I rebuild my workstation it would be automated. I’d like to share what I’ve come up with.

Setup

After installing Debian on my workstation, I updated the apt cache and installed the required dependency - which was unecessary as it was already in the Debian build I used:

sudo apt update
sudo apt install software-properties-common

Then I added the official Ansible repo:

sudo add-apt-repository --update ppa:ansible/ansible

And installed Ansible:

sudo apt install ansible

Making a Playbook

I started with installing some basic command line utils found in the default apt repos by making a playbook file called software.yml:

---
- hosts: localhost
  connection: local
  become: true
  tasks:

  - name: Install apt packages
    ansible.builtin.apt:
      state: present
      update_cache: true
      name:
      - htop
      - tree
      - neofetch

To apply this playbook, I ran sudo ansible-playbook software.yml. After the success message, I was able to verify it worked by running one of the utilities, like neofetch.

This was great, but I realized some of the software I needed (vscode, firefox, github cli) would require adding their official repos. It took a lot of searching and cross referencing Ansible documentation with installation documentation from the respective software sites. Eventually, I came up with this:

 - name: Add Mozilla gpg key
    ansible.builtin.apt_key:
      url: https://packages.mozilla.org/apt/repo-signing-key.gpg
      state: present
  - name: Add Mozilla repository
    apt_repository:
      repo: deb [arch=amd64] https://packages.mozilla.org/apt mozilla main

  - name: Add VSCode gpg key
    ansible.builtin.apt_key:
      url: https://packages.microsoft.com/keys/microsoft.asc
      state: present
  - name: Add VSCode repository
    apt_repository:
      repo: deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main

  - name: Add Github gpg key
    ansible.builtin.apt_key:
      url: https://cli.github.com/packages/githubcli-archive-keyring.gpg
      state: present
  - name: Add Github repository
    apt_repository:
      repo: deb [arch=amd64] https://cli.github.com/packages stable main

Now I could add the corresponding packages to the apt install section:

  - name: Install apt packages
    ansible.builtin.apt:
      state: present
      update_cache: true
      name:
      - htop
      - tree
      - neofetch
      - code
      - firefox
      - gh

Awesome! Except there was one app I use a lot, Obsidian, that didn’t have an official apt repo and instead published releases to GitHub. I found that I could install the latest release using the following:

 - name: Install Obsidian
    ansible.builtin.apt:
      deb: "https://github.com/obsidianmd/obsidian-releases/releases/download/v1.5.12/obsidian_1.5.12_amd64.deb"

This worked, but I realized this would quickly not be the latest version and wouldn’t have any way to update it. So, I went down a rabbit hole of trying to program Ansible to pull the latest release info from GitHub and then install it. In the end I came up with this:

  - name: Get Obsidian Releases
    ansible.builtin.uri:
      url: https://api.github.com/repos/obsidianmd/obsidian-releases/releases/latest
      return_content: true
    register: json_response

  - name: Install Obsidian
    ansible.builtin.apt:
      deb: "{{ item.browser_download_url }}"
    loop_control:
      label: "{{ item.browser_download_url }}"
    loop: "{{ json_response.json.assets }}"
    when: item.browser_download_url is search("amd64.deb")
    register: download_url

And it worked! It essentially curl’s the GitHub API for the latest release of the Obsidian official repo, parses the JSON to pick the url of the .deb package from a list of other package types, then downloads and installs the file from that url.

Shell Configuration

At this point I had a lot of the software I wanted, but there were a number of shell configurations that I wanted to change like dark mode, screen timeout, and enabling titlebar buttons . My playbook was getting pretty big, so I made a new one called settings.yml.

I found some of the settings I wanted to change by looking for them specifically. They all involved dconf key modification, so it was a big help when I found the following command:

dconf watch /

This puts the terminal in a monitoring mode, displaying the key and value as you change settings in graphical interfaces. So much better than digging through documentation or Stack Overflow!

With that, I found the keys and values to change and came up with this for my settings:

---
- hosts: localhost
  connection: local
  tasks:

  - name: Screen timeout 30min
    dconf:
      key: /org/gnome/desktop/session/idle-delay
      value: "uint32 1800"

  - name: Prefer Dark
    dconf:
      key: /org/gnome/desktop/interface/color-scheme
      value: "'prefer-dark'"

  - name: Window Theme
    dconf:
      key: /org/gnome/desktop/interface/gtk-theme
      value: "'Adwaita-dark'"
      
  - name: Titlebar buttons
    dconf:
      key: /org/gnome/desktop/wm/preferences/button-layout
      value: "'appmenu:minimize,maximize,close'"

One ansible-playbook settings.yml later and I could see the changes like dark mode and titlebar buttons happen right in front of me. Cool!

Conclusion

It was nice to get my feet wet with Ansible. That said, I wonder how much I’d use it in a professional setting. I think it would depend how much of the infrastructure is self hosted. It seems like it would at least be useful for the provisioning of developer workstations.

I’ve left out some of the code for brevity. You can find the complete files at this github repo.

Cheers!
Rick

 

 


Resources