1

We started using Vagrant to setup our development environment. Now we would like to use the same Vagrantfile also in production/staging.

When I use the same vagrantfile that contains a virtualbox provider and gce I get the error

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: virtualbox
Requested provider: google

Is there a way I can vagrant up virtualbox and gce?

Vagrant.has_plugin?("nugrant")
Vagrant.require_version ">= 1.6.3"

Vagrant.configure("2") do |config|  
  config.vm.provider "virtualbox"
  config.vm.box = "yungsang/boot2docker"

  config.vm.provider :google do |google, override|
    override.vm.box = "gce"    
    google.google_project_id = $GOOGLE_PROJECT_ID
    google.google_client_email = $GOOGLE_CLIENT_EMAIL
    google.google_key_location = $GOOGLE_KEY_LOCATION

    # Override provider defaults
    google.name = "name"
    google.image = "ubuntu-1404-trusty-v20141212"
    google.machine_type = "n1-standard-1"
    google.zone = "europe-west1-c"
    google.metadata = {'custom' => 'metadata', 'production' => 'app'}
    google.tags = ['vagrantbox', 'prod']

    override.ssh.username = $LOCAL_USER
    override.ssh.private_key_path = $LOCAL_SSH_KEY

    config.vm.define :prod do |prod|
        prod.vm.provision :shell, inline: 'echo I am executed in prod only!!'
    end
  end

  config.vm.synced_folder ".", "/vagrant"

  # Fix busybox/udhcpc issue
  config.vm.provision :shell do |s|
    s.inline = <<-EOT
      if ! grep -qs ^nameserver /etc/resolv.conf; then
        sudo /sbin/udhcpc
      fi
      cat /etc/resolv.conf
    EOT
  end

  # Adjust datetime after suspend and resume
  config.vm.provision :shell do |s|
    s.inline = <<-EOT
      sudo /usr/local/bin/ntpclient -s -h pool.ntp.org
      date
    EOT
  end

  # Login docker hub
  config.vm.provision :shell do |s|
    s.inline = "/usr/bin/docker $@"
    s.args   = ["login", "-u", config.user.docker.username, "-p", config.user.docker.password, "-e", config.user.docker.email]
  end

  config.vm.provision :docker do |d|    
    d.pull_images "nginx"
    d.pull_images "mongodb"
    d.pull_images "java"    
  end

  ACTICE_SPRING_PROFILE = "te"

  config.vm.provision :docker do |d|
   # provision docker stuff here 
  end

  config.vm.network "forwarded_port", guest: 80, host: 8080
  config.vm.network "forwarded_port", guest: 443, host: 8443
end

Update:

I tried to solve the problem with a multi vm setup, but now I am facing the problem that vagrant uses an outside-in provisioning, so my GCE specific scripts like gce.vm.provision :shell, inline: 'curl -sSL https://get.docker.com/ubuntu/ | sudo sh' are executed at the end not at the beginning.

Vagrant.configure("2") do |config|  

  config.vm.define "dev", primary: true do |dev|    
    dev.vm.provider "virtualbox"
    dev.vm.box = "yungsang/boot2docker"

    dev.vm.synced_folder ".", "/vagrant"

    override.vm.provision :shell, inline: 'echo "Provision DEV"'
    # Fix busybox/udhcpc issue
    dev.vm.provision :shell do |s|
      s.inline = <<-EOT
        if ! grep -qs ^nameserver /etc/resolv.conf; then
          sudo /sbin/udhcpc
        fi
        cat /etc/resolv.conf
      EOT
    end

    # Adjust datetime after suspend and resume
    dev.vm.provision :shell do |s|
      s.inline = <<-EOT
        sudo /usr/local/bin/ntpclient -s -h pool.ntp.org
        date
      EOT
    end

    dev.vm.network "forwarded_port", guest: 80, host: 8080
    dev.vm.network "forwarded_port", guest: 443, host: 8443
  end

  config.vm.define "gce", autostart: false do |gce|    
    gce.vm.provider :google do |google, override|
      override.vm.box = "gce"
      google.google_project_id = $GOOGLE_PROJECT_ID
      google.google_client_email = $GOOGLE_CLIENT_EMAIL
      google.google_key_location = $GOOGLE_KEY_LOCATION

      # Override provider defaults
      google.name = "z-rechnung-#{TARGET_ENV}"
      google.image = "ubuntu-1404-trusty-v20141212"
      google.machine_type = "n1-standard-1"
      google.zone = "europe-west1-c"
      google.metadata = {'environment' => "#{TARGET_ENV}"}
      google.tags = ['vagrantbox', "#{TARGET_ENV}"]

      override.ssh.username = $LOCAL_USER
      override.ssh.private_key_path = $LOCAL_SSH_KEY

      gce.vm.provision :shell, inline: 'sudo apt-get update -y'
      gce.vm.provision :shell, inline: 'sudo apt-get upgrade -y'
      gce.vm.provision :shell, inline: 'curl -sSL https://get.docker.com/ubuntu/ | sudo sh'
    end
  end  

  # Login docker hub
  config.vm.provision :shell do |s|
    s.inline = "/usr/bin/docker $@"
    s.args   = ["login", "-u", config.user.docker.username, "-p", config.user.docker.password, "-e", config.user.docker.email]
  end

  config.vm.provision :docker do |d|    
    d.pull_images ....  
  end

  config.vm.provision :docker do |d| 
    d.run "image" ....  
  end
Vad1mo
  • 5,156
  • 6
  • 36
  • 65
  • Possible duplicate of [Using Vagrant to manage development and production environments?](http://stackoverflow.com/questions/18724275/using-vagrant-to-manage-development-and-production-environments) – kenorb Jun 10 '16 at 12:24

1 Answers1

0

The right answer is to remember that your Vagrantfile is just a Ruby program, first and foremost, and the execution of this program is to result in a datastructure that the CLI sub-commands traverse.

So, create functions that add provisioners to configuration, then call them in the "inside". For example,

def provisioner_one(config)
    config.vm.provision :shell, 'echo hello'
end

Vagrant.configure('2') do |config|
    # stuff here
    config.vm.define 'dev' do |dev, override|
        # whatever else here

        provisioner_one(dev)

        # other stuff here
    end
    # more other stuff here
end

This will DWIM.

Rob Kinyon
  • 1,770
  • 2
  • 19
  • 28