Skip to content

Ansible to India: Teleporting our development environment, and dealing with bugs

Recently, we started working with a development company in India, which faced us with a problem. Our development thus far is all done in-house, with our development servers located here, offline. This was never an issue for us, it was even desirable to do so. But if you decide to outsource some parts of a project (or an entire project), this can be troublesome. Think about speed impacts, security and what-not.

So we decided to provide our Indian team with a Vagrant box. This allows you to create a virtual machine, without the hassle of knowing anything about virtualization on the client side. All they need to know, is the command ‘vagrant up’, and they’re good to go.

Now, you do need some configuration to happen on this virtual machine, otherwise you’ll just be giving them, say, a standard Ubuntu machine. Which is nice, but not very practical.

I visited the Dutch PHP Conference (go there.), where I saw the talk by the awesome Erika Heidi. She showed what you can do with Ansible. Now I heard of Puppet and Chef, but something about the simplicity of Ansible got me intrigued.

This is my story into the awesome world of Ansible and Windows… </sarcasm>

So you’re saying Ansible isn’t awesome?

No, I am saying Windows isn’t, at least not in this case. I spent half a day trying to get Ansible to work with Windows, using Babun. Which is an ordeal by itself, which would be fine, if I got it to work 100%. I didn’t. Aside from the fact that I would’ve needed to explain like 10 steps to our India team (via a Readme and Skype), I didn’t manage to work out all that’s needed to get Ansible to work with the Vagrant box flawlessly. Note that you wouldn’t have these problems if you use Mac or Linux.

So, in all my desperation, I started Googling.

I came across a blog by another awesome person, Rob Allen.  He suggested running Ansible on the guest VM, which in my case was running Ubuntu. Bingo!

After I set this up, i was in business.

What did we need on our box?

Well, we needed quite a few services:

  • Apache
  • MySQL
  • PHP 5.4+ (ended up with 5.6, which is of course fine)
  • MongoDB
  • Solr
  • Composer

Apache

Apache was a hassle. We needed our source on the host machine, that is, in Windows, so that our Indian team could just develop on their local machine. But that was really the hardest part, which I figured out in an hour or so. I kept getting 403 Forbidden errors, which I resolved by adding:

<Directory />
    Options FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

to the vhost config for the site.

MySQL

The next step was MySQL, which was easy. I made a role which installed and started MySQL, and checked if I needed to import the data:

---
- name: 1. Install MySQL server
  apt: name=mysql-server state=present

- name: 2. Install unzip package
  apt: name=unzip state=present

- name: 3. Install python MySQL package
  apt: name=python-mysqldb state=present

- name: 4. Start MySQL server
  service: name=mysql state=started enabled=yes

- name: 5. Check if DB exists
  shell: mysql -e 'show databases;'
  register: databases

- name: 6. Create a new database
  mysql_db: name={{ dbname }} state=present collation=utf8_general_ci
  when: databases.stdout.find('{{ dbname }}') == -1

- name: 7. Create a database user
  mysql_user: name={{ username }} password={{ password }} priv=*.*:ALL host=localhost state=present
  when: databases.stdout.find('{{ dbname }}') == -1

- name: 8a. Copy DB structure
  copy: src=db_structure.sql.zip dest=/tmp/db_structure.sql.zip
  when: databases.stdout.find('{{ dbname }}') == -1

- name: 8b. Copy DB data
  copy: src=db_data.sql.zip dest=/tmp/db_data.sql.zip
  when: databases.stdout.find('{{ dbname }}') == -1

- name: 8c. Unzip DB structure
  unarchive: src=/tmp/db_structure.sql.zip dest=/tmp copy=no
  when: databases.stdout.find('{{ dbname }}') == -1

- name: 8d. Unzip DB data
  unarchive: src=/tmp/db_data.sql.zip dest=/tmp copy=no
  when: databases.stdout.find('{{ dbname }}') == -1

- name: 8e. Insert DB structure
  shell: cat /tmp/db_structure.sql.sql | mysql -u {{ username }} -p{{ password }} {{ dbname }}
  when: databases.stdout.find('{{ dbname }}') == -1

- name: 8f. Insert DB data
  shell: cat /tmp/db_data.sql.sql | mysql -u {{ username }} -p{{ password }} {{ dbname }}
  when: databases.stdout.find('{{ dbname }}') == -1

I used an external var file to store the database name, username and password.

What this basically does, is check if the database exists. If it does, it skips the creation of the database user, the database and the import of data, since we already have that. If we ever need to re-import the data, I can just add a task to drop the database, and it will be imported again

Note to self: I actually have to check if the database user exists too, to be able to skip that step if needed

MongoDB

This was a really easy step. I skipped checking if the data was already imported, because Mongo is blazing fast. So all I did was install Mongo if it needed to be installed, and ran mongorestore using a dump of our data.

Solr

For this, I used a standard role found on Ansible Galaxy: Role. Thanks, Jeff Geerling! Note that this role also required Java, which I also installed using a role by him. After installing, I just moved a dump of our Solr indexes to the location of Solr on the Vagrant box and everything was good to go! (Solr uses files as index).

Composer

To install Composer, I used a role provided by Jeff Geerling. Thanks again!

Our site’s code

Now this is where it got tricky again. Some of our code is hosted on Github, some is in our SVN server. On top of that, I had to use Composer to check out everything on the host machine. The directory with the source code was linked to the Vagrant guest, but there we run into Windows permission problems.

Long story short, I used a kind-of dirty workaround to get this all to work. I copied our composer.json and composer.lock file from version control to a temporary directory on the Vagrant guest, and ran composer install there.

After everything is done, I copied the vendor directory to the source directory (on the Windows host), and everything works fine.

All that was left now was to copy some modified config files (with locations to the databases and Solr etc.) to the project directory and presto! Everything worked 🙂

Conclusion

Ansible and Windows aren’t friend by default, but you can use Vagrant to make them friends of friends 😉 This works rather nicely! You’ll run into some more problems along the way, but nothing that can’t be solved with a little bit of configuration.

I hope this guide helps someone along the way. If you have any questions, just post a comment or hit me up on Twitter!

Published incodeexplanation

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *