Posted by virantha on Thu 10 March 2016

An Example Provisioning of HACKT on a Centos 7 VM using Vagrant and Ansible

I recently needed to get an open-source circuit toolkit (HACKT)compiled and deployed on my local system. I already knew the C++ source compiled and installed fine on Linux, and didn't want to jump through the hoops to get it running on my Mac 10.11 (El Capitan) system, so I decided to bring up a reproducible build on a VM. I'd used Ansible in the past but had forgotten some of the syntax, so I decided to write a simple playbook that would get this done, as well as document some of the build details required for HACKT. Some of the details on using Ansible locally on a Vagrant VM weren't also immediately obvious to me, so this is also an attempt to collate that information for future reference.

1   Install Vagrant and Ansible

Vagrant is a nice way to bring up a virtual machine (running through VirtualBox, for example) from predefined 'boxes' very easily. Ansible is a separate provisioning system that lets you easily, and in a reproducible and documented fashion, customize these virtual machines, and only requires SSH running on the target system. Vagrant also ships with some nice bindings to Ansible, allowing for really easy provisioning of the deployed boxes. Even more, you don't even need Ansible installed on your local machine as Vagrant will install it automatically in your virtual machine and execute the provisioning inside it, which is a really lightweight way to do it.

I won't go into the details of installing these tools, but they were very straight-forward to get up and running.

2   Get the vanilla virtual machine up

First, just go to a directory where you will be keeping all the files needed to build your server. Then, within that directory, do the following:

vagrant init
vagrant box add centos/7

The first writes a template Vagrantfile to your current directory, that will contain the configuration information for customizing your new VM. The second command downloads a pre-built CentOS 7 system from the Vagrant community and stores it in your $HOME/.vagrant.d/boxes

Next, we want to configure and provision our VM that will be brought up from this downloaded image. So, edit your Vagrantfile, remove all the crud, and insert the following lines:

Vagrant.configure(2) do |config|
    config.vm.box = "centos/7"
end

Now, run the following command to start your VM:

vagrant up

This will bring up your new CentOS VM, as well as rsync your current directory to the VM under /home/vagrant/sync.

You can ssh into the VM by doing:

vagrant ssh

3   Getting Ansible Provisioning working

To enable Ansible provisioning inside your , add the following lines to your Vagrantfile:

Vagrant.configure(2) do |config|
      config.vm.box = "centos/7"

      config.vm.provision "ansible_local" do |ansible|
          ansible.provisioning_path = "/home/vagrant/sync"
          ansible.playbook = "playbook.yml"
      end
end

The playbook.yml is where we'll write the Ansible instructions (in YAML format) that will provision this VM. This file should stay in your current directory, but when Vagrant brings up the VM, it will rsync this file to your /home/vagrant/sync directory inside your VM, so that's why we need the provisioning_path option specified.

Also note that the configuration to Vagrant is specifying ansible_local, which means Vagrant will install and run Ansible inside the VM.

Next, we'll build up the playbook.yml file step by step.

3.1   Connection setting

At the top of the file is the connection setings:

---
- hosts: all
  connection: local

This is all that is needed to run the provisioning locally on the VM.

3.2   Setup some variables

vars:
    src_dir: /home/vagrant/src
    hackt_dir: "{{ src_dir }}/hackt"

3.3   Start the tasks section and update packages

tasks:
  - name: Update yum
    yum: name=* state=latest
    sudo: true

  - name: Install packages
    yum: name="{{ item }}" state=present
    sudo: true
    with_items:
          - "@Development tools"
          - guile
          - libtool-ltdl-devel
          - wget
          - texinfo

The nice thing about using Ansible is that the actions are idempotent, so you can reprovision any number of times and it will keep a consistent state, as well as only running commands that will end up modifying the current state.

The other tricky thing here is the quotes when installing packages, especially the syntax for the "Development tools" group.

3.4   Downgrading Bison version

HACKT, as of this writing, seems to have issues with Bison 2.7 on CentOS7. The work-around for now is to downgrade to version 2.3. First, we yum remove bison, download version 2.3, build, and then install it.

- name: Remove newest bison
  yum: name=bison state=removed
  sudo: true

- name: Create src directory
  file: path={{ src_dir }} state=directory

- name: Download old bison for hackt
  get_url: url=http://ftp.gnu.org/gnu/bison/bison-2.3.tar.gz dest={{ src_dir }}

- name: Unzip bison
  unarchive: src={{ src_dir }}/bison-2.3.tar.gz dest={{ src_dir }}

- name: Build and install new bison
  shell: "{{ item }}"
  args:
      chdir: "{{ src_dir }}/bison-2.3"
  with_items:
      - ./configure
      - make
      - sudo make install

3.5   Building HACKT

Next, we clone the HACKT repository and checkout a specific snapshot, bootstrap, configure, and make.

The bootstrap step has a creates arg in it that doesn't rerun it if the configure script is already there.

The compiler CXXFLAGS does require warnings not to turn into errors because of some unused-typedef warnings in the current gcc.

- name: Get HACKT
  git: repo=https://github.com/fangism/hackt.git
       dest={{ src_dir }}/hackt
       version=tags/SNAPSHOT-RELEASE-20141024

- name: Bootstrap HACKT
  shell: ./bootstrap
  args:
      chdir: "{{ hackt_dir }}"
      creates: "{{ hackt_dir }}/configure"

- name: Build HACKT
  shell: "{{ item }}"
  args:
      chdir: "{{ hackt_dir }}"
      creates: /usr/local/bin/hackt
  with_items:
      - env CXXFLAGS='-Wno-error' ./configure
      - make
      - sudo make install

4   Final steps and other tips

And that's basically it, for a very simple provisioning system. Ansible has some really cool features that we haven't touched on here, and it's probably a good idea to breakdown the playbook into a more hierarchical structure. But for now, here's the complete playbook:

---
- hosts: all
  connection: local

  vars:
      src_dir: /home/vagrant/src
      hackt_dir: "{{ src_dir }}/hackt"

  tasks:
    - name: Update yum
      yum: name=* state=latest
      sudo: true

    - name: Install packages
      yum: name="{{ item }}" state=present
      sudo: true
      with_items:
            - "@Development tools"
            - guile
            - libtool-ltdl-devel
            - wget
            - texinfo

    - name: Remove newest bison
      yum: name=bison state=removed
      sudo: true

    - name: Create src directory
      file: path={{ src_dir }} state=directory

    - name: Download old bison for hackt
      get_url: url=http://ftp.gnu.org/gnu/bison/bison-2.3.tar.gz dest={{ src_dir }}

    - name: Unzip bison
      unarchive: src={{ src_dir }}/bison-2.3.tar.gz dest={{ src_dir }}

    - name: Build and install new bison
      shell: "{{ item }}"
      args:
          chdir: "{{ src_dir }}/bison-2.3"
      with_items:
          - ./configure
          - make
          - sudo make install

    - name: Get HACKT
      git: repo=https://github.com/fangism/hackt.git
           dest={{ src_dir }}/hackt
           version=tags/SNAPSHOT-RELEASE-20141024

    - name: Bootstrap HACKT
      shell: ./bootstrap
      args:
          chdir: "{{ hackt_dir }}"
          creates: "{{ hackt_dir }}/configure"

    - name: Build HACKT
      shell: "{{ item }}"
      args:
          chdir: "{{ hackt_dir }}"
      with_items:
          - env CXXFLAGS='-Wno-error' ./configure
          - make
          - sudo make install

Some further useful commands and tips are below.

4.1   Utility commands

  • vagrant suspend - Shuts down but saves state on the disk
  • vagrant resume - Resumes the suspended VM
  • vagrant halt - Shutdown
  • vagrant destroy - Destroy all the customizations and disk
  • vagrant reload --provision - Restart a running VM after making changes to Vagrantfile
  • vagrant provision - Rerun the provisioning on a running VM

4.2   Sharing files

I wasn't able to get the NFS shares working, but just stuck to the simple rsync option where a directory on the host can be copied to your VM on bootup/reload. Just add the following line to your Vagrantfile:

config.vm.synced_folder "share", "/share/dev", type: "rsync"

This will copy your share/ subdirectory to the VM's /share/dev directory

© Virantha Ekanayake. Built using Pelican. Modified svbhack theme, based on theme by Carey Metcalfe