<-

Dotfiles and configuration management using Ansible

Got a new mac? Don't want to spend the whole weekend installing and configuring your favourite apps? Automate that process! That what I did in my osx-automation project.

What is Infrastructure as Code?

Infrastructure as Code is the process of managing and provisioning computer data centers throught machine-readable definition files, rather than manual configuration.

In simplier words, your system configuration is stored in plain text files. Plain text files than can be stored in any version control system. Thanks to VCS you have change history, you can always rollback to previous version, you can always see what was changed last.

The point is that it gives you automated, reproducible, testable and self documented enviroment setup.

So how is it related to your personal laptop? Put all your configuration in text files, and store those files in GitHub. That's what people do with dotfiles.

What are dotfiles?

Dotfiles are plain text configuration files for command line tools, editors, shells, and so on.

Example: .profile.clj, .tmux.conf, .vimrc, .zshrc...

They are called 'dotfiles' because most of the time the name begins with . symbol.

However, there are some open questions:

  1. How to install and update configuration files?
  2. How to save what apps are installed on my machine?
  3. How to generate configurations on the fly with env variables for example?

The answer to those questions is to use software provisioning tool Ansible or similar.

What is Ansible?

Ansible is open-source software provisioning, configuration management, and application deployment tool. Includes its own declarative language to describe system configuration(YAML based). Written in Python.

How to use it?

There is concept of Role in Ansible. Each role may consist of set of variables, tasks and templates.

Variables are just data in yml files. Tasks can be shell commands, plugin commands and so on. Templates are templates based on Jinja2 engine.

So basically in Ansible, you can create roles, which can consist of variables, tasks and templates.

So in my case, I have the next roles: brew, zsh, vim, tmux, docker, git.

Each role has some tasks to perform, that can install something, create folders, generate config files.

Here is a tree view for my automation project:

.
├── Makefile
├── README.md
├── hosts
├── init.sh
├── playbook.retry
├── playbook.yml
├── roles
│   ├── brew
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── vars
│   │       └── main.yml
│   ├── clojure
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   ├── docker
│   │   └── tasks
│   │       └── main.yml
│   ├── git
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   ├── golang
│   │   └── tasks
│   │       └── main.yml
│   ├── iterm2
│   │   ├── tasks
│   │   │   └── main.yml
│   │   ├── templates
│   │   │   └── com.googlecode.iterm2.plist.j2
│   │   └── vars
│   │       └── main.yml
│   ├── jvm
│   │   └── tasks
│   │       └── main.yml
│   ├── node
│   │   └── tasks
│   │       └── main.yml
│   ├── python
│   │   └── tasks
│   │       └── main.yml
│   ├── ssh
│   │   └── tasks
│   │       └── main.yml
│   ├── tmux
│   │   ├── tasks
│   │   │   └── main.yml
│   │   ├── templates
│   │   └── vars
│   │       └── main.yml
│   ├── vim
│   │   ├── tasks
│   │   │   └── main.yml
│   │   ├── templates
│   │   │   ├── autocommand.vim
│   │   │   ├── ftplugin
│   │   │   │   ├── clojure.vim
│   │   │   │   ├── go.vim
│   │   │   │   ├── javascript.vim
│   │   │   │   ├── python.vim
│   │   │   │   ├── scala.vim
│   │   │   │   └── yaml.vim
│   │   │   ├── init.vim
│   │   │   ├── mappings.vim
│   │   │   ├── options.vim
│   │   │   ├── plugin
│   │   │   │   ├── ale.vim
│   │   │   │   ├── deoplete.vim
│   │   │   │   ├── fzf.vim
│   │   │   │   ├── gitgutter.vim
│   │   │   │   └── nerdtree.vim
│   │   │   └── plugins.vim
│   │   └── vars
│   │       └── main.yml
│   └── zsh
│       ├── tasks
│       │   └── main.yml
│       ├── templates
│       └── vars
│           └── main.yml
└── vars
    ├── global_env.yml
    └── variables.yml

Example, Homebrew Role

Let's see in more details brew role brew/tasks/main.yml

---
- name: Ensure homebrew is updated
  homebrew:
    state: latest
    update_homebrew: true

- name: Tap homebrew homebrew/cask
  homebrew_tap:
    name: "{{ item }}"
    state: present
  with_items: "{{ taps }}"

- name: Install homebrew applications
  homebrew:
    name: "{{ apps }}"
    state: latest

- name: Install homebrew cask applications
  homebrew_cask:
    name: "{{ item }}"
    state: present
  with_items: "{{ cask_apps }}"

And here are variables, with lists of apps, tools, etc

---
homebrew_url: https://raw.githubusercontent.com/Homebrew/install/master/install

taps:
  - caskroom/fonts
  - homebrew/cask
  - jesseduffield/lazygit
  - wagoodman/dive
  - wata727/tflint

apps:
  - adobe-acrobat-reader
  - ansible
  - ansible-lint
  - aria2
  - autoenv
  - caddy
  - dive
  - fzf
  - htop
  - imagemagick
  - jq
  - nmap
  - packer
  - sshfs
  - terraform
  - terraform-inventory
  - tflint
  - tldr
  - tmux
  - tor
  - tree
  - watchman
  - wget
  - yamllint

cask_apps:
  - figma
  - flux
  - font-fira-code
  - google-backup-and-sync
  - google-chrome
  - google-cloud-sdk
  - insomniax
  - kdiff3
  - osxfuse
  - pgadmin4
  - spectacle
  - spotify
  - teamviewer
  - telegram
  - torbrowser
  - transmission
  - tunnelblick
  - vagrant
  - veracrypt
  - visual-studio-code
  - vlc
  - wireshark
  - xmind

This role installs all specified applications via brew.

Secret variables

Sometime you would like also to have some secret information in your configuration files. Ansible has a special feature for that. It is called ansible-vault. You can encrypt your variables files and store in public repo.

The moment when you would like to run ansible on your computer, you will need to type the secret password and it will decrypt files for that run.

Conslusion

Using Ansible you can fully automate your laptop setup. Each time you got a new mac it is a matter of minutes to install all needed software and configuration and be ready to work. No waste of time, trying to remember your configuration or trying to manually copy config files.

Load your automation setup. Run it. And you are ready to go.

Links