[Published in Open Source For You (OSFY) magazine, September 2017 edition.]
Introduction
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.
Setup
A CentOS 6.8 Virtual Machine (VM) running on KVM will be used for the installation. Internet access should be available from the guest machine. The VM should have at least 2 GB of RAM alloted 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 show 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, 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 (2 GB) 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
Build from Git repository
We can build the Erlang/OTP sources from the Git repository. 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
You are encouraged to read the complete installation documentation at: https://github.com/erlang/otp/blob/master/HOWTO/INSTALL.md.