If you’ve followed my prior blog posts you already know that I’ve been playing with Vagrant this year in an effort to improve my workflow. To date the biggest impact of the improved workflow is being able to recreate my self-contained WordPress plugin development system which runs a full GUI dev environment on CentOS 6.5. While that has been great for recovering from poorly designed laptop hardware, I am not really leveraging the power of Vagrant.
Today I have a new need and thus a new reason to extend my education in Vagrant. The WordPress plugins I develop need to function in older versions of PHP. If I write my plugins using PHP 5.5 then I run the risk of using functions that only work in newer versions of PHP. Since the WordPress baseline is PHP 5.2 that will prevent some percentage of users from using my plugins. By the same token, many users run newer versions of PHP that have deprecated functions. In those cases using PHP 5.2 specific functions will not work for those customers, again limiting my overall market. The ultimate goal is to write my plugins so they operate properly in PHP 5.2 up through the latest version of production which currently sits at version 5.5.
Vagrant is the right tool to get this job done.
Cloudy Vagrant Boxes
Up until today I have had a baseline WP Dev Kit Vagrant box, a “Vagrantized” version of my “uncluttered” Virtual Box system that has all of the tools I like to use when writing plugins. The box is stored on my Google Drive and served via proxy from the VagrantCloud service. Since that is the default location for the built-in Vagrant commands that is a good place to start.
The problem is that any time I need to create a new box it has to pull down a fairly large file from Google Drive to my local box. Depending on how much throttling the ISPs are throwing in the mix between Google servers and my house it can take anywhere from 20 minutes to 20 hours to get the file in place and spin up my box.
I need something faster. Local drive access will suffice for this latest project and Vagrant has methods to do just that.
Making It Local
To start things off I am going to make a copy of my latest fully-baked virtual box. This is a box that started as a vanilla WP Dev Kit box I pulled down from Vagrant Cloud and over the past month have layered on all of my code and other “special tweaks” that only I am interested in. To make it something Vagrant can “manhandle” I need to convert the full box into a Vagrant box format.
vagrant package --base "SLP Dev Box 2.0"
Now I have a full copy of my current running plugin development machine complete with updated code repositories, special data sets, and other “goodies” I am in the progress of building. Now I want to clone this “vagrant style” so I can set up a series ofprovisioning commands to alter the environment “on the fly”.
I create a new directory on my Windows box and initialize a new Vagrant box with the following commands:
[box type=”alert”]Make sure you are updated to the latest version of Vagrant when you run these commands. If you are upgrading from Vagrant versions prior to 1.6 on Windows you will want to fully uninstall Vagrant 1.x, delete the C:\Hashicorp directory and install the latest version. A reboot is required after the update.[/box]
vagrant box add --name slp_2_0 "C:\blah\blah\blah%20blah\one_dir_up\package.box"
The above command adds the package.box file that was created from the virtual box with my operating environment to the list of locally available Vagrant box images. This will make it easier to spin up new boxes and provision updates via the Vagrant shell, or other Vagrant provisioner, commands.
The command puts the package.box file into a usable format for Vagrant and assigns the label slp_2_0 for easier reference.
You can check your Vagrant box was added properly using the following command line command:
vagrant box list
Day 6 : Cloning
In case you missed it, that is meant to be a clever reference to The 6th Day… a movie about clones of former state politicians, or something like that. No, we are not cloning politicians. Who in the hell would want to do that?!?! Instead we are going to clone something that is actually useful to us… the original “Vagrantized” development box.
I am going to create a new directory where I can setup my Vagrantfile and related scripts to configure the base OS and software utilities to my liking for a new test case. In this case I want all the stuff on my main box plus some updates to PHP.
I’m sure that there is a shortcut to elminate the Vagrantfile editing by packaging the original box’s Vagrantfile in the base package but that will be a task for another blog post.
mkdir slp_2_0_with_php_5_5 vagrant init slp_2_0
This creates a Vagrantfile in the new folder that I need to edit to use the GUI. I follow my prior post on the subject and modify the Vagrantfile. I turn on the GUI interface and also force the display count to 1.
config.vm.provider "virtualbox" do |vb| # Don't boot with headless mode vb.gui = true # Set to one monitor vb.customize ["modifyvm", :id, "--monitorcount", "1"] end
Provisioning : The Magic Sauce
Provisioning was the last part that I needed to get in place and it took me a few tries to get it right. It is stupidly simple once you know what it is doing and how to get the commands in the right place.
The examples on the Vagrant site are a good start but are not very clear when viewing them within the context of a pre-existing Vagrantfile. My first test is the “dump the date to a text file” test case are presented on the Vagrant site. This will write the full date into a file named “provisioned_at”.
For this to work you MUST have an authorized_keys file in your root user directory. The shell provisioner logs in as ROOT. That is important to note as I was looking inside of the “vagrant” user directory which is the one I use for my daily editing.
You will also want to place the provision commands inside of the main Vagrant.configure block to be consistent with the default Puppet, Chef, and other examples. Below is my entire Vagrantfile with all of the comments boiled out so you can see how simple this can be.
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "slp_2_0" config.vm.boot_timeout = 600 config.vm.provider "virtualbox" do |vb| vb.gui = true vb.customize ["modifyvm", :id, "--monitorcount", "1"] end config.vm.provision "shell", inline: "date > provisioned_at" end
When the system boots it will write the current date to the root home directory. If you login as vagrant you can run the sudo command to see the file:
# sudo cat /root/provisioned_at
Upgrading PHP With Provisioner
Now that the basics are working we can use some shell command sequences to force the vagrant up command to upgrade PHP when the box boots. The Vagrantfile will instruct Vagrant to take a copy of my slp_2_0 box and spin it up as a new cloned virtual machine in VirtualBox. When it finishes booting it will run the yum update command, fetch the yum repository for Webtatic that provides access to the PHP 5.5 repo for CentOS 6.5, remove the old version of PHP 5.3, install PHP 5.5 with the MySQL hooks, and restart Apache. When it is done I have a fully copy of the SLP development environment but running on a PHP 5.5 instead of PHP 5.3 install.
Here is my Vagrantfile to accomplish that:
# Run SLP 2.0 Box # with PHP 5.5 instead of PHP 5.3 VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "slp_2_0" config.vm.boot_timeout = 600 config.vm.provider "virtualbox" do |vb| vb.gui = true vb.customize ["modifyvm", :id, "--monitorcount", "1"] end config.vm.provision "shell" do |s| s.inline = "date > provisioned_at" s.inline = "yum -y update" s.inline = "rpm -Uvh ; s.inline = "yum -y remove php-common" s.inline = "yum -y install php55w" s.inline = "yum -y install php-mysql" s.inline = "service httpd restart" end end