Last week, I looked at the getting a rails server pushed up to AWS using a Vagrant. After that was working, I decided I wanted to be able to test changes on a local VM, then push that VM to the cloud when I liked it, rather than test all my changes in the cloud.
In the directory where I had the Vagrantfile and the shared folder for the rails server, I did
vagrant up --provider=virtualbox, and I got this:
An active machine was found with a different provider. Vagrant currently allows each machine to be brought up with only a single provider at a time. A future version will remove this limitation. Until then, please destroy the existing machine to up with a new provider. Machine name: default Active provider: aws Requested provider: virtualbox
So apparently one of the choices is to
vagrant destroy and then
vagrant up with a different provider. Unfortunately,
vagrant destroy will flag my VM in AWS as “terminated,” which means it will be deleted. So that would mean an operation that I intend only to change from “dev mode” to “deploy mode” in my personal workflow would actually delete a VM in the cloud. That sounds like a recipe for disaster.
Another choice is just to maintain a separate folder, so that I do my dev work,
vagrant up, poke around on
localhost, and when I’m happy I copy the application folder from my “virtualbox” Vagrant project to my AWS Vagrant project. This isn’t acceptable either, because one reason I am using Vagrant is to avoid having any manual file copy steps in my deployment.
It looks like there are a few workarounds, none of which make me super happy.
- I could define multiple machines, one for each provider, and then vary which machine I call
vagrant upon. This would work, but I don’t like it because I’m using a feature that’s designed to let me spin up multiple different machines instead to spin up the same machine in multiple environments.
- I could have the config file check some environment variable to see which provider I currently care about. This seems like more work, and I already have enough environment variables to think about.
Also, mitchellh suggests option 1. So we’re going with option 1.
The first thing I did was just add these two lines to my Vagrantfile, after
config.vm.define "dev" config.vm.define "aws"
Those are the only changes I made.
Then I did
vagrant up dev --provision --provider=virtualbox. Vagrant dutifully went and found a version of the box I was using, for the virtualbox provider, and started downloading an image. (Side note: I work in coffee shops whenever I get the chance, but you may want to download vagrant box images on faster WiFi ahead of time.) That worked fine. I ssh’ed to the box with
vagrant ssh dev and made a superficial change to the static pages app from the rails tutorial, so that I would be able to tell whether my changes worked. Then I halted the VM, and did
vagrant up aws --provision --provider=aws. (Note that the first
aws in that command is the name of a VM. The
--provider=aws is what told Vagrant to spin this one up in the cloud.)
Actually, I ran
vagrant up --provision --provider=aws && vagrant ssh aws and then got a drink of water, because I was going to be waiting for a minute. (Specifically, my Vagrantfile causes AWS to wait while the cheapest tier of VM compiles some Rails dependency from source, which takes a couple minutes.)
It worked! I was able to visit the VM in my browser and immediately see the change I had made. No manual file copy. No manual deployment work at all, besides
bundle install and actually starting the web server.
I think, in retrospect, that the error message at the beginning of the post is too dire. I’d want it to say something like “You already launched the machine called ‘default’ with one provider. Vagrant associates machines with providers. You can add a line such as
config.vm.define "dev" to your Vagrantfile, and associate that machine with a different provider.” The suggestion that I use
vagrant destroy to handle this case seems like an over-reaction, and turned me off for a minute because I don’t like deleting things.
Anyway, that was the victory condition for this post. Till next time, happy learning!