The Complete Magazine on Open Source

Developing a virtual machine for Erlang/OTP using Ansible

2.83K 0

Virtual machine for erlang/otp

This seventh article in the DevOps series is a tutorial on how to create a test virtual machine (VM) to compile, build, and test Erlang/OTP from its source code. You can then adapt the method to create different VMs for various Erlang releases.

Erlang is a programming language designed by Ericsson primarily for soft real-time systems. The Open Telecom Platform (OTP) consists of libraries, applications and tools to be used with Erlang to implement services that require high availability. In this article, we will create a test virtual machine (VM) to compile, build, and test Erlang/OTP from its source code. This allows you to create VMs with different Erlang release versions for testing.

The Erlang programming language was developed by Joe Armstrong, Robert Virding and Mike Williams in 1986 and released as free and open source software in 1998. It was initially designed to work with telecom switches, but is widely used today in large scale, distributed systems. Erlang is a concurrent and functional programming language, and is released under the Apache License 2.0.

Setting it up

A CentOS 6.8 virtual machine (VM) running on KVM is used for the installation. Internet access should be available from the guest machine. The VM should have at least 2GB of RAM allotted to build the Erlang/OTP documentation. The Ansible version used on the host (Parabola GNU/Linux-libre x86_64) is 2.3.0.0. The ansible/ folder contains the following files:

ansible/inventory/kvm/inventory

ansible/playbooks/configuration/erlang.yml

The IP address of the guest CentOS 6.8 VM is added to the inventory file as shown below:

erlang ansible_host=192.168.122.150 ansible_connection=ssh ansible_user=bravo ansible_password=password

An entry for the erlang host is also added to the /etc/hosts file as indicated below:

192.168.122.150 erlang

A ‘bravo’ user account is created on the test VM, and is added to the ‘wheel’ group. The /etc/sudoers file also has the following line uncommented, so that the ‘bravo’ user will be able to execute sudo commands:

## Allows people in group wheel to run all commands

%wheel ALL=(ALL) ALL

We can obtain the Erlang/OTP sources from a stable tarball, or clone the Git repository. The steps involved in both these cases are discussed below.

Building from the source tarball

The Erlang/OTP stable releases are available at http://www.erlang.org/downloads. The build process is divided into many steps, and we shall go through each one of them. The version of Erlang/OTP can be passed as an argument to the playbook. Its default value is the release 19.0, and is defined in the variable section of the playbook as shown below:

vars:

ERL_VERSION: “otp_src_{{ version | default(‘19.0’) }}”

ERL_DIR: “{{ ansible_env.HOME }}/installs/erlang”

ERL_TOP: “{{ ERL_DIR }}/{{ ERL_VERSION }}”

TEST_SERVER_DIR: “{{ ERL_TOP }}/release/tests/test_server”

The ERL_DIR variable represents the directory where the tarball will be downloaded, and the ERL_TOP variable refers to the top-level directory location containing the source code. The path to the test directory from where the tests will be invoked is given by the TEST_SERVER_DIR variable.

Erlang/OTP has mandatory and optional package dependencies. Let’s first update the software package repository, and then install the required dependencies as indicated below:

tasks:

- name: Update the software package repository

become: true

yum:

name: ‘*’

update_cache: yes

- name: Install dependencies

become: true

package:

name: “{{ item }}”

state: latest

with_items:

- wget

- make

- gcc

- perl

- m4

- ncurses-devel

- sed

- libxslt

- fop

The Erlang/OTP sources are written using the ‘C’ programming language. The GNU C Compiler (GCC) and GNU Make are used to compile the source code. The ‘libxslt’ and ‘fop’ packages are required to generate the documentation. The build directory is then created, the source tarball is downloaded and it is extracted to the directory mentioned in ERL_DIR.

- name: Create destination directory

file: path=”{{ ERL_DIR }}” state=directory

- name: Download and extract Erlang source tarball

unarchive:

src: “http://erlang.org/download/{{ ERL_VERSION }}.tar.gz”

dest: “{{ ERL_DIR }}”

remote_src: yes

The ‘configure’ script is available in the sources, and it is used to generate the Makefile based on the installed software. The ‘make’ command will build the binaries from the source code.

- name: Build the project

command: “{{ item }} chdir={{ ERL_TOP }}”

with_items:

- ./configure

- make

environment:

ERL_TOP: “{{ ERL_TOP }}”

After the ‘make’ command finishes, the ‘bin’ folder in the top-level sources directory will contain the Erlang ‘erl’ interpreter. The Makefile also has targets to run tests to verify the built binaries. We are remotely invoking the test execution from Ansible and hence -noshell -noinput are passed as arguments to the Erlang interpreter, as shown in the .yaml file.

- name: Prepare tests

command: “{{ item }} chdir={{ ERL_TOP }}”

with_items:

- make release_tests

environment:

ERL_TOP: “{{ ERL_TOP }}”

- name: Execute tests

shell: “cd {{ TEST_SERVER_DIR }} && {{ ERL_TOP }}/bin/erl -noshell -noinput -s ts install -s ts smoke_test batch -s init stop”

You need to verify that the tests have passed successfully by checking the $ERL_TOP/release/tests/test_server/index.html page in a browser. A screenshot of the test results is shown in Figure 1.

The built executables and libraries can then be installed on the system using the make install command. By default, the install directory is /usr/local.

- name: Install

command: “{{ item }} chdir={{ ERL_TOP }}”

with_items:

- make install

become: true

environment:

ERL_TOP: “{{ ERL_TOP }}”

The documentation can also be generated and installed as shown below:

- name: Make docs

shell: “cd {{ ERL_TOP }} && make docs”

environment:

ERL_TOP: “{{ ERL_TOP }}”

FOP_HOME: “{{ ERL_TOP }}/fop”

FOP_OPTS: “-Xmx2048m”

- name: Install docs

become: true

shell: “cd {{ ERL_TOP }} && make install-docs”

environment:

ERL_TOP: “{{ ERL_TOP }}”

The total available RAM (2GB) is specified in the FOP_OPTS environment variable. The complete playbook to download, compile, execute the tests, and also generate the documentation is given below:

---

- name: Setup Erlang build

hosts: erlang

gather_facts: true

tags: [release]

vars:

ERL_VERSION: “otp_src_{{ version | default(‘19.0’) }}”

ERL_DIR: “{{ ansible_env.HOME }}/installs/erlang”

ERL_TOP: “{{ ERL_DIR }}/{{ ERL_VERSION }}”

TEST_SERVER_DIR: “{{ ERL_TOP }}/release/tests/test_server”

tasks:

- name: Update the software package repository

become: true

yum:

name: ‘*’

update_cache: yes

- name: Install dependencies

become: true

package:

name: “{{ item }}”

state: latest

with_items:

- wget

- make

- gcc

- perl

- m4

- ncurses-devel

- sed

- libxslt

- fop

- name: Create destination directory

file: path=”{{ ERL_DIR }}” state=directory

- name: Download and extract Erlang source tarball

unarchive:

src: “http://erlang.org/download/{{ ERL_VERSION }}.tar.gz”

dest: “{{ ERL_DIR }}”

remote_src: yes

- name: Build the project

command: “{{ item }} chdir={{ ERL_TOP }}”

with_items:

- ./configure

- make

environment:

ERL_TOP: “{{ ERL_TOP }}”

- name: Prepare tests

command: “{{ item }} chdir={{ ERL_TOP }}”

with_items:

- make release_tests

environment:

ERL_TOP: “{{ ERL_TOP }}”

- name: Execute tests

shell: “cd {{ TEST_SERVER_DIR }} && {{ ERL_TOP }}/bin/erl -noshell -noinput -s ts install -s ts smoke_test batch -s init stop”

- name: Install

command: “{{ item }} chdir={{ ERL_TOP }}”

with_items:

- make install

become: true

environment:

ERL_TOP: “{{ ERL_TOP }}”

- name: Make docs

shell: “cd {{ ERL_TOP }} && make docs”

environment:

ERL_TOP: “{{ ERL_TOP }}”

FOP_HOME: “{{ ERL_TOP }}/fop”

FOP_OPTS: “-Xmx2048m”

- name: Install docs

become: true

shell: “cd {{ ERL_TOP }} && make install-docs”

environment:

ERL_TOP: “{{ ERL_TOP }}”

The playbook can be invoked as follows:

$ ansible-playbook -i inventory/kvm/inventory playbooks/configuration/erlang.yml -e “version=19.0” --tags “release” -K

Building from the Git repository

We can build the Erlang/OTP sources from the Git repository too. The complete playbook is given below for reference:

- name: Setup Erlang Git build

hosts: erlang

gather_facts: true

tags: [git]

vars:

GIT_VERSION: “otp”

ERL_DIR: “{{ ansible_env.HOME }}/installs/erlang”

ERL_TOP: “{{ ERL_DIR }}/{{ GIT_VERSION }}”

TEST_SERVER_DIR: “{{ ERL_TOP }}/release/tests/test_server”

tasks:

- name: Update the software package repository

become: true

yum:

name: ‘*’

update_cache: yes

- name: Install dependencies

become: true

package:

name: “{{ item }}”

state: latest

with_items:

- wget

- make

- gcc

- perl

- m4

- ncurses-devel

- sed

- libxslt

- fop

- git

- autoconf

- name: Create destination directory

file: path=”{{ ERL_DIR }}” state=directory

- name: Clone the repository

git:

repo: “https://github.com/erlang/otp.git”

dest: “{{ ERL_DIR }}/otp”

- name: Build the project

command: “{{ item }} chdir={{ ERL_TOP }}”

with_items:

- ./otp_build autoconf

- ./configure

- make

environment:

ERL_TOP: “{{ ERL_TOP }}”

The ‘git’ and ‘autoconf’ software packages are required for downloading and building the sources from the Git repository. The Ansible Git module is used to clone the remote repository. The source directory provides an otp_build script to create the configure script. You can invoke the above playbook as follows:

$ ansible-playbook -i inventory/kvm/inventory playbooks/configuration/erlang.yml --tags “git” -K