Tutorial: Hello Ansible on iMinds Virtual Wall

In this tutorial, you will learn how you can use the open source configuration managment tool “Ansible” to ease the development, scaling and reproducability of your next experiment.

1. Design the experiment

In this exercise we will convert the install script below into an Ansible playbook.

This install script does the following:

  • Install apache2 and iperf

On the server:

  • Configure the default site on Apache

  • Copy some files to /var/www

  • Start the apache service

On the client:

  • Start a wget client script

  • Start an iperf client script

 1#!/bin/bash
 2#----------------------------------------------------------------------
 3# Copyright (c) 2012 Raytheon BBN Technologies
 4#
 5# Permission is hereby granted, free of charge, to any person obtaining
 6# a copy of this software and/or hardware specification (the "Work") to
 7# deal in the Work without restriction, including without limitation the
 8# rights to use, copy, modify, merge, publish, distribute, sublicense,
 9# and/or sell copies of the Work, and to permit persons to whom the Work
10# is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be
13# included in all copies or substantial portions of the Work.
14#
15# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
22# IN THE WORK.
23#----------------------------------------------------------------------
24
25# Usual directory for downloading software in ProtoGENI hosts is `/local`
26cd /local
27#Get the hostname to see if we are at the server or the client
28hn=`echo $HOSTNAME | cut -d'.' -f 1`
29
30##### Check if file is there #####
31if [ ! -f "./installed.txt" ]
32then
33       #### Create the file ####
34        sh -i -c `sudo touch "./installed.txt"`
35
36       #### Run  one-time commands ####
37
38       #Install necessary packages
39        sudo apt-get update
40        sudo apt-get -y install apache2 iperf & EPID=$!
41        wait $EPID
42
43       # Install custom software
44       ## Customize apache installation
45
46
47       ## Reboot the host if needed
48fi
49##### Run Boot-time commands
50# Start services
51# If this is the server then start the iperf and configure and start the http server
52if [ $hn == "server" ]
53then
54
55   # Enable web server stats
56   sudo /usr/sbin/a2enmod status
57   sudo rm /etc/apache2/mods-enabled/status.conf
58
59   echo "<Location /server-status>" | sudo tee -a /etc/apache2/sites-available/default > /dev/null
60   echo "   SetHandler server-status" |sudo tee -a /etc/apache2/sites-available/default > /dev/null
61   echo "   Allow from all" | sudo tee -a /etc/apache2/sites-available/default > /dev/null
62   echo "</Location>" | sudo tee -a /etc/apache2/sites-available/default > /dev/null
63   echo "ExtendedStatus On" | sudo tee -a /etc/apache2/conf.d/extendedstatus > /dev/null
64
65   # Copy the website under /var/www/
66   sudo cp -R ./website/* /var/www/
67   sudo rm -rf /var/www/html
68   sudo ln -s /var/www/ /var/www/html
69
70   # Start the webserver
71   sudo /usr/sbin/apache2ctl restart
72   sudo service apache2 restart
73
74   # Start the iperf server
75   sudo mkdir -p /var/www/iperflogs
76   iperf_server_log="/var/www/iperflogs/iperf-server.log"
77   sudo bash -c "iperf -s -i 10 &> $iperf_server_log"
78else
79  # If this is the client start the script for transfers
80  # Wait 60 seconds just to give some time to the server to come up
81  sleep 60
82  ./scripts/client-wget.sh&
83  ./scripts/client-iperf.sh&
84fi
85# Start my service -- assume it was installed at /usr/local/bin

2. Establish the Environment

  1. To run this exercise, you will need an account and two pieces of software.

  1. Have a Fed4FIRE or GENI account

  2. jFed Experimenter GUI BETA: use the Quickstart Experimenter GUI BETA-button on <http://jfed.iminds.be/>

  3. Have Ansible installed:

    1. On Linux and Mac: find the instructions for your package manager here

    2. On Windows: Ansible has no support for Windows on the control machine. You can swap in a Linux VM to overcome this issue (Use ansible_controller.rspec for a readily configured machine).

  1. Download the webpages and scripts needed for the exercise.

Use wget to download the tarball of files onto your local machine and use tar to uncompress it:

wget http://doc.ilabt.iminds.be/jfed-documentation/_downloads/helloansible-install.tar.gz
tar zxvf helloansible-install.tar.gz

Note

Windows users should download and unpack this on their Ansible controller testbed-node.

3. Obtain resources

Reserve helloansible.rspec in jFed in an experiment named ansblXX where XX is your initials.

4. Configure and Initialize

jFed can export the login information of your nodes into several formats for configuration management systems. An Ansible inventory is one of the supported formats. This is a flat file format which tells Ansible the name and login information for your nodes.

To export these files:

  • Go to the “RSpec Viewer” tab on the top of your screen

  • Choose “Save Experiment” -> “Export Configuration Management Settings”

  • Save the ZIP-file in a convenient place

  • Unpack the ZIP-file in your working directory

Note

Windows users should copy and unpack their zip-file onto their ansible controller. You can use WinSCP to copy the resources to your testbed node.

../_images/export-configuration-management-settings.png

The exported ZIP-file contains several files:

  • id_rsa

  • id_rsa.pub

  • ssh-config

  • ansible-hosts

  • ansible.cfg

  • fabfile.py

  • README.txt

The README.txt-file contains an comprehensive introduction for each of these files. In this tutorial, we will be using the files mentioned in bold.

An example of the content of these files can be found below:

ansible-hosts:

# Sample commands:
# ansible nodes -m ping
# ansible nodes -m shell -a "uptime"

[nodes]
client        ansible_ssh_host=n091-vm26-10.wall2.ilabt.iminds.be     ansible_ssh_port=22     ansible_ssh_user=twalcari
server        ansible_ssh_host=n091-vm26-11.wall2.ilabt.iminds.be     ansible_ssh_port=22     ansible_ssh_user=twalcari

ansible.cfg:

[defaults]
private_key_file = ./id_rsa
host_key_checking = false
inventory = ansible-hosts

Warning

Before continuing, you need to properly secure the private key id_rsa. Otherwise, all commands will fail. To do this, execute:

$ chmod 600 id_rsa

Check to see if your nodes are up and ready. This command uses the ping module to ping all the servers from the nodes-group (in which jFed stores all servers by default) listed in the inventory file:

$ ansible nodes -m ping

Example output showing all of the nodes responding to ping:

$ ansible -i ansible-hosts nodes -m ping
client | success >> {
    "changed": false,
    "ping": "pong"
}

server | success >> {
    "changed": false,
    "ping": "pong"
}

Try using the ping module in Ansible to only ping server or client by replacing all in the above with server or client.

5. Using Ansible Ad Hoc

The following are some example Ansible Ad Hoc commands. You can run these commands one at a time from the machine where you have Ansible installed. -s tells Ansible to use sudo when executing the command. All modules are described in the Ansible Documentation.

apt module is used to install packages using the apt package manager:

ansible [nodes/server/client] -s -m apt -a "name=apache2 update_cache=yes"

command module is used to execute an arbitrary command on the remote node:

ansible [nodes/server/client]  -s -m command -a "/usr/sbin/a2enmod status"

file module is used to set attributes of files:

ansible [nodes/server/client] -s -m file -a "path=/var/www/html state=absent"

synchronize module is an implementation of rsync and is used to efficiently synchronize files between your local machine and a remote node:

ansible [nodes/server/client] -s  -m synchronize \
    -a "src=website/index.html dest=/var/www"

lineinfile module is used to see if an arbitrary line exists in a file:

ansible [nodes/server/client] -s  -m lineinfile \
   -a "line='ExtendedStatus On' dest=/etc/apache2/conf.d/extendedstatus create=yes state=present"

service module is used to start/stop/restart/etc services:

ansible [nodes/server/client] -s  -m service -a "name=apache2 state=restarted"

Use it!

Using the above Ad Hoc Ansible commands configure the client node by doing the following:

  • on both client and server, install apache2 and iperf

  • copy the scripts directory into /local on the client node with permissions 755.

Verify that the above items have been done, by logging into the client node and running:

$ apache2 -v
$ iperf -v
$ ls /local/scripts

6. Using Ansible Playbooks

Ansible commands can be collected into files called Playbooks. Playbooks are in a configuration file format called YAML which is very straightforward. In particular, Ansible Ad Hoc commands easily map to commands used in an Ansible Playbook.

Use the name construct to leave a comment describing the Ansible command you are running.

The Playbook to configure the client node as in the install script is as follows:

---
- name: Configure client
  hosts: client
  sudo: True
  tasks:
   - name: install apache2
     apt: name=apache2 update_cache=yes
   - name: install iperf
     apt: name=iperf update_cache=yes
   - name: copy scripts into /local
     synchronize: src=scripts dest=/local
   - name: set permission of /local to 755
     file: 
       path: /local 
       mode: 0755
   - name: start client wget
     command: /local/scripts/client-wget.sh 
     async: 86400
     poll: 0
   - name: start client iperf
     command: /local/scripts/client-iperf.sh
     async: 86400
     poll: 0

Do these commands look like the Ad Hoc commands you came up with in the previous step?

Put the above content in a file called hello-client.yml.

Run the playbook with the following command on the local machine:

ansible-playbook -i ansible-hosts hello-client.yml

Use it!

Using the above Ansible modules, configure the server node by reproducing the steps in the HelloGENI install script for the server node. As you find a command that works, use it to construct a hello-server.yml playbook. (See the solution or hello-server.yml)

Here is a template you can fill in to create the hello-server.yml-file:

 1- name: Configure server
 2  hosts: server
 3  sudo: True
 4  vars: 
 5    iperf_server_log: /var/www/iperflogs/iperf-server.log
 6  tasks:
 7   - name: install apache2
 8     apt: name=apache2 update_cache=yes
 9   - name: install iperf
10     apt: name=iperf update_cache=yes
11   - name: /usr/sbin/a2enmod status
12     # INSERT COMMAND HERE
13   - name: check /etc/apache2/mods-enabled/status.conf file is absent
14     # INSERT COMMAND HERE
15   - name: copy website/index.html into /var/www
16     # INSERT COMMAND HERE
17   - name: copy the website/graphics directory into /var/www
18     # INSERT COMMAND HERE
19   - name: rm -rf /var/www/html
20     # INSERT COMMAND HERE
21   - name: Make simlink to webfiles
22     # INSERT COMMAND HERE
23   - name: Make sure /etc/apache2/conf.d/extendedstatus file contains "ExtendedStatus On"
24     # INSERT COMMAND HERE
25   - name: Make sure /etc/apache2/sites-available/000-default.conf contains Location information
26     # INSERT COMMAND HERE
27   - name: restart apache2 service
28     # INSERT COMMAND HERE
29   - name: create directory for iperf logs in /var/www/iperflogs with permissions of 755
30     # INSERT COMMAND HERE
31   - name: start server
32     command: /usr/bin/sudo /bin/bash -c "iperf -s -i 10 &> {{ iperf_server_log }}" 
33     async: 86400
34     poll: 0
  • Run both the client and server playbooks on your nodes.

  • Browse to the server node

7. Advanced Ansible

  • You may have noticed that the server playbook and the client playbook contained duplicate commands. This is because both nodes need to have apache installed so that they can act as webservers. As you might have guessed, there is a way to modularize this configuration. In Ansible this is done with “roles”.

  • Explore some of the intermediate features of Ansible such as roles, variables, and handlers.

8. Teardown Experiment

  • Reload the OS of your client and server, and test your playbooks from scratch in the new experiment. Do you get the same behavior?

  • When you are done, delete the resources in your experiment.

9. Archive Experiment

If this was a real experiment, you would commit your Ansible playbook to a version control system like git as you go.

Acknowledgements

This tutorial is an adaptation of the GENI-tutorial “Converting the Hello GENI Install Script to Ansible”