Using Ansible with Terrafoam

Terraform is a great provisioning tool. Ansible is great to set up machines. What happens when we add both to the mix?

What is Ansible?

Ansible is a modern automation tool which makes your life easier by managing your servers for you. You just need to define the configuration in which you are interested and ansible will go ahead and do it for you, be it installing a package or configuring a server application or even restarting a service. Ansible is always ready to manage your servers. Read more about Ansible and its installation.

What is Terrafoam?

Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions. In true sense, Terraform enables infrastructure as code. It works well with providers like Amazon Web Services, Google Cloud, Digital Ocean, Microsoft Azure and a lot more. Since Terraform is an independent tool, it can manage cross-cloud dependencies.

How to setup Terraform?

Terraform and its plugins are distributed as binaries. It is downloadable, in zip format, from https://www.terraform.io/downloads.html. Once downloaded, we have to extract it and make sure that we add the extracted location in $PATH variable. Typically, doing this in ~/.bashrc is the best way to manage $PATH. We recommend extracting it in /opt/terraform and then adding the line below in ~/.bashrc

export PATH=$PATH:/opt/terraform

Important Terraform Components

Terraform consist of several components. Three of the important ones are listed below.

Setting up ownCloud using Terraform and Ansible

We will run a virtual machine on Digital Ocean (they call it a droplet) using Terraform. For this, we need to generate an API token from Digital Ocean's website. So here, our provider is Digital Ocean and resource is the droplet. We will call Ansible locally using local-exec provisioner to set up ownCloud on the Droplet. Let us create a directory where we will keep all the files.

$ mkdir OConDO
$ cd OConCO

Terrafoam loads all the files in the current directory which ends with .tf. We will create two files, credentials.tf and DO.tf. We don't really need two files but it is a good idea to keep credentials in a different file. So, credentials.tf would look like this:

provider "digitalocean" {
    token = "r514d6331b68dcg8fc9c0h83b792447cb43fvedz8fbc4205276g1c8v76s7925b"
}

Next, the DO.tf should look like this:

resource "digitalocean_droplet" "web" {
    image = "fedora-22-x64"
    name = "web-1"
    region = "sgp1"
    size = "512mb"
    ssh_keys = ["a1:b4:4d:4c:8d:8a:a3:de:41:94:b8:a0:f4:6f:8e:41"]

  provisioner "local-exec" {
    command = "sleep 30 && echo -e \"[webserver]\n${digitalocean_droplet.web.ipv4_address} ansible_connection=ssh ansible_ssh_user=root\" > inventory &&  ansible-playbook -i inventory oc-playbook.yml"
  }
}

We have declared the resource to use the Fedora 22 image. We want a 512 mb droplet in Singapore region. We will name it as web-1. An additional parameter to let add my ssh key to the droplet has been added.

  1. sleep for 30 seconds because sometimes it takes time for the droplet to allow ssh immediately.
  2. add the IP address of the droplet with additional parameters to inventory file.
  3. call Ansible with the inventory file.

We have a playbook ready to do the installation. The playbook, named oc-playbook.yml should look like this:

---
- hosts: webserver

  tasks:
  - name: install httpd
    dnf: name=httpd state=installed

  - name: install php and libs
    dnf: name={{ item }} state=installed
    with_items:
      - php-xml
      - php
      - php-zip
      - php-mbstring
      - php-mysqlnd
      - php-gd

  - name: install additional tools
    dnf: name=dnf state=installed

  - name: set selinux permissive
    selinux: policy=targeted state=permissive

  - name: get the owncloud tar
    get_url: url=https://download.owncloud.org/community/owncloud-9.0.1.tar.bz2 dest=/var/www/html

  - name: exract the tar
    unarchive: src=/var/www/html/owncloud-9.0.1.tar.bz2 dest=/var/www/html copy=no owner=apache
    notify:
    - restart apache

  handlers:
    - name: restart apache
      service: name=httpd state=restarted

Now, we have the Terraform artifacts and Ansible playbook ready, let us do a dry-run and see what all will be changed by Terraform.

terraform plan
+ digitalocean_droplet.web
    image:                "" => "fedora-22-x64"
    ipv4_address:         "" => "<computed>"
    ipv4_address_private: "" => "<computed>"
    ipv6_address:         "" => "<computed>"
    ipv6_address_private: "" => "<computed>"
    locked:               "" => "<computed>"
    name:                 "" => "web-1"
    region:               "" => "sgp1"
    size:                 "" => "512mb"
    ssh_keys.#:           "" => "1"
    ssh_keys.0:           "" => "a1:b4:4d:4c:8d:8a:a3:de:41:94:b8:a0:f4:6f:8e:41"
    status:               "" => "<computed>"

Plan: 1 to add, 0 to change, 0 to destroy.

We can verify that Terraform is going to create only one Digital Ocean droplet. There are no changes to the existing droplets and there is nothing to be destroyed. Once we have verified the Terraform output, we can simply call terraform apply and once the execution is finished, we can open the browser and checkout http://<droplet_ip>/owncloud.