devopsgroup-io/vagrant-hostmanager

Can't install plugin on Vagrant 2.1.2

danowar2k opened this issue ยท 14 comments

OS: Windows 7

I've just upgraded Vagrant from 2.0.4 to 2.1.2 by installing the new version over the old version.
Then I tried to install the plugin 1.8.9 and received the following:

C:/DP/Tools/Vagrant/embedded/gems/2.1.2/gems/vagrant-2.1.2/bin/vagrant:47:in `[]=': Invalid argument - ruby_setenv(VAGRANT_NO_PLUGINS) (Errno::EINVAL)
        from C:/DP/Tools/Vagrant/embedded/gems/2.1.2/gems/vagrant-2.1.2/bin/vagrant:47:in `block in <main>'
        from C:/DP/Tools/Vagrant/embedded/gems/2.1.2/gems/vagrant-2.1.2/bin/vagrant:36:in `each_index'
        from C:/DP/Tools/Vagrant/embedded/gems/2.1.2/gems/vagrant-2.1.2/bin/vagrant:36:in `<main>'
Installation of plugin vagrant-hostmanager has failed. Stopping Vagrant execution.
Installation of plugin vagrant-hostmanager has failed. Stopping Vagrant execution.
Installation of plugin vagrant-hostmanager has failed. Stopping Vagrant execution

Ok, this resolved itself...
In Vagrant 2.0.4, I had vagrant-hostmanager 1.8.8 installed. It seems after updating to another Vagrant version, the plugin install/update process of Vagrant is a bit wonky.
1.8.8 was in the Vagrant 2.0.4 gems folder, registered itself as installed, but vagrant install vagrant-hostmanager wanted to install the plugin again (because it wasn't present in the Vagrant 2.1.2 gems folder).

Doing update instead of install fixed that.

ouun commented

I'm having the same issue at the moment. Running any vagrant command tells me that I need to install vagrant-hostmanager first. What I did. Deleted vagrant completely for a couple of times and tried to find a way to get over this, but without success, yet. Any advice or is the plugin not compatible with the latest version? It also doesn't seem to find the correct version.

You also upgraded from Vagrant 2.0.4 to 2.1.2? And even if you run vagrant from somewhere where there is no Vagrantfile you get an error? Can you provide the command and the output?

I've successfully installed vagrant-hostmanager 1.8.9 on Vagrant 2.1.2...

ouun commented

Thanks for your answer, @danowar2k. You're right. Outside the folder with a Vagrantfile I get the correct list when running vagrant plugin list:

landrush (1.2.0)
  - Version Constraint: > 0
vagrant-bindfs (1.1.0)
  - Version Constraint: > 0
vagrant-hostmanager (1.8.9)
  - Version Constraint: > 0

But to get there I completely removed Vagrant first, installed 2.0.4 and the plugins and then upgraded Vagrant to 2.1.2. Still confused why I still get the error within a folder with Vagrantfile...

That depends. Are you able to post the Vagrantfile in here? I think if I see that I could tell you why you get the above error...

ouun commented

Yes sure, it's more or less the default by Trellis (roots/trellis):

# -*- mode: ruby -*-
# vi: set ft=ruby :

ANSIBLE_PATH = __dir__ # absolute path to Ansible directory on host machine
ANSIBLE_PATH_ON_VM = '/home/vagrant/trellis' # absolute path to Ansible directory on virtual machine

require File.join(ANSIBLE_PATH, 'lib', 'trellis', 'vagrant')
require File.join(ANSIBLE_PATH, 'lib', 'trellis', 'config')
require 'yaml'

vconfig = YAML.load_file("#{ANSIBLE_PATH}/vagrant.default.yml")

if File.exist?("#{ANSIBLE_PATH}/vagrant.local.yml")
  local_config = YAML.load_file("#{ANSIBLE_PATH}/vagrant.local.yml")
  vconfig.merge!(local_config) if local_config
end

ensure_plugins(vconfig.fetch('vagrant_plugins')) if vconfig.fetch('vagrant_install_plugins')

trellis_config = Trellis::Config.new(root_path: ANSIBLE_PATH)

Vagrant.require_version '>= 2.0.1'

Vagrant.configure('2') do |config|
  config.vm.box = vconfig.fetch('vagrant_box')
  config.vm.box_version = vconfig.fetch('vagrant_box_version')
  config.ssh.forward_agent = true
  config.vm.post_up_message = post_up_message

  # Fix for: "stdin: is not a tty"
  # https://github.com/mitchellh/vagrant/issues/1673#issuecomment-28288042
  config.ssh.shell = %{bash -c 'BASH_ENV=/etc/profile exec bash'}

  # Required for NFS to work
  if vconfig.fetch('vagrant_ip') == 'dhcp'
    config.vm.network :private_network, type: 'dhcp', hostsupdater: 'skip'

    cached_addresses = {}
    config.hostmanager.ip_resolver = proc do |vm, _resolving_vm|
      if cached_addresses[vm.name].nil?
        if vm.communicate.ready?
          vm.communicate.execute("hostname -I | cut -d ' ' -f 2") do |type, contents|
            cached_addresses[vm.name] = contents.split("\n").first[/(\d+\.\d+\.\d+\.\d+)/, 1]
          end
        end
      end
      cached_addresses[vm.name]
    end
  else
    config.vm.network :private_network, ip: vconfig.fetch('vagrant_ip'), hostsupdater: 'skip'
  end

  main_hostname, *hostnames = trellis_config.site_hosts_canonical
  config.vm.hostname = main_hostname

  if Vagrant.has_plugin?('vagrant-hostmanager') && !trellis_config.multisite_subdomains?
    redirects = trellis_config.site_hosts_redirects

    config.hostmanager.enabled = true
    config.hostmanager.manage_host = true
    config.hostmanager.aliases = hostnames + redirects
  elsif Vagrant.has_plugin?('landrush') && trellis_config.multisite_subdomains?
    config.landrush.enabled = true
    config.landrush.tld = config.vm.hostname
    hostnames.each { |host| config.landrush.host host, vconfig.fetch('vagrant_ip') }
  else
    fail_with_message "vagrant-hostmanager missing, please install the plugin with this command:\nvagrant plugin install vagrant-hostmanager\n\nOr install landrush for multisite subdomains:\nvagrant plugin install landrush"
  end

  bin_path = File.join(ANSIBLE_PATH_ON_VM, 'bin')

  if Vagrant::Util::Platform.wsl? || (Vagrant::Util::Platform.windows? and !Vagrant.has_plugin? 'vagrant-winnfsd')
    trellis_config.wordpress_sites.each_pair do |name, site|
      config.vm.synced_folder local_site_path(site), remote_site_path(name, site), owner: 'vagrant', group: 'www-data', mount_options: ['dmode=776', 'fmode=775']
    end

    config.vm.synced_folder ANSIBLE_PATH, ANSIBLE_PATH_ON_VM, mount_options: ['dmode=755', 'fmode=644']
    config.vm.synced_folder File.join(ANSIBLE_PATH, 'bin'), bin_path, mount_options: ['dmode=755', 'fmode=755']
  else
    if !Vagrant.has_plugin? 'vagrant-bindfs'
      fail_with_message "vagrant-bindfs missing, please install the plugin with this command:\nvagrant plugin install vagrant-bindfs"
    else
      trellis_config.wordpress_sites.each_pair do |name, site|
        config.vm.synced_folder local_site_path(site), nfs_path(name), type: 'nfs'
        config.bindfs.bind_folder nfs_path(name), remote_site_path(name, site), u: 'vagrant', g: 'www-data', o: 'nonempty'
        config.vm.synced_folder '../database/', '/srv/database'
      end

      config.vm.synced_folder ANSIBLE_PATH, '/ansible-nfs', type: 'nfs'
      config.bindfs.bind_folder '/ansible-nfs', ANSIBLE_PATH_ON_VM, o: 'nonempty', p: '0644,a+D'
      config.bindfs.bind_folder bin_path, bin_path, perms: '0755'
    end
  end

  vconfig.fetch('vagrant_synced_folders', []).each do |folder|
    options = {
      type: folder.fetch('type', 'nfs'),
      create: folder.fetch('create', false),
      mount_options: folder.fetch('mount_options', [])
    }

    destination_folder = folder.fetch('bindfs', true) ? nfs_path(folder['destination']) : folder['destination']

    config.vm.synced_folder folder['local_path'], destination_folder, options

    if folder.fetch('bindfs', true)
      config.bindfs.bind_folder destination_folder, folder['destination'], folder.fetch('bindfs_options', {})
    end
  end

  provisioner = local_provisioning? ? :ansible_local : :ansible
  provisioning_path = local_provisioning? ? ANSIBLE_PATH_ON_VM : ANSIBLE_PATH

  config.vm.provision provisioner do |ansible|
    if local_provisioning?
      ansible.install_mode = 'pip'
      ansible.provisioning_path = provisioning_path
      ansible.version = vconfig.fetch('vagrant_ansible_version')
    end

    ansible.compatibility_mode = '2.0'
    ansible.playbook = File.join(provisioning_path, 'dev.yml')
    ansible.galaxy_role_file = File.join(provisioning_path, 'requirements.yml') unless vconfig.fetch('vagrant_skip_galaxy') || ENV['SKIP_GALAXY']
    ansible.galaxy_roles_path = File.join(provisioning_path, 'vendor/roles')

    ansible.groups = {
      'web' => ['default'],
      'development' => ['default']
    }

    ansible.tags = ENV['ANSIBLE_TAGS']
    ansible.extra_vars = { 'vagrant_version' => Vagrant::VERSION }

    if vars = ENV['ANSIBLE_VARS']
      extra_vars = Hash[vars.split(',').map { |pair| pair.split('=') }]
      ansible.extra_vars.merge!(extra_vars)
    end
  end

  # Virtualbox settings
  config.vm.provider 'virtualbox' do |vb|
    vb.name = config.vm.hostname
    vb.customize ['modifyvm', :id, '--cpus', vconfig.fetch('vagrant_cpus')]
    vb.customize ['modifyvm', :id, '--memory', vconfig.fetch('vagrant_memory')]
    vb.customize ['modifyvm', :id, '--ioapic', vconfig.fetch('vagrant_ioapic', 'on')]

    # Fix for slow external network connections
    vb.customize ['modifyvm', :id, '--natdnshostresolver1', vconfig.fetch('vagrant_natdnshostresolver', 'on')]
    vb.customize ['modifyvm', :id, '--natdnsproxy1', vconfig.fetch('vagrant_natdnsproxy', 'on')]
  end

  # VMware Workstation/Fusion settings
  ['vmware_fusion', 'vmware_workstation'].each do |provider|
    config.vm.provider provider do |vmw, override|
      vmw.name = config.vm.hostname
      vmw.vmx['numvcpus'] = vconfig.fetch('vagrant_cpus')
      vmw.vmx['memsize'] = vconfig.fetch('vagrant_memory')
    end
  end

  # Parallels settings
  config.vm.provider 'parallels' do |prl, override|
    prl.name = config.vm.hostname
    prl.cpus = vconfig.fetch('vagrant_cpus')
    prl.memory = vconfig.fetch('vagrant_memory')
    prl.update_guest_tools = true
  end

  # Vagrant Triggers
  trellis_config.wordpress_sites.each do |(name, site)|
    #
    # Get database credentials
    #
    site['env'].merge!(trellis_config.vault_sites[name]['env'])
    db_name  = site['env']['db_name']
    db_user  = site['env']['db_user']
    db_pass  = site['env']['db_password']
    #
    # Importing database
    #
    config.trigger.after [:up, :resume] do |trigger|
      database_file = "../database/current/#{db_name}.sql"
      if File.exists?(database_file)
        trigger.info = "Importing database #{db_name}"
        trigger.run_remote = {inline: "mysql -u #{db_user} -p#{db_pass} #{db_name} < /srv/database/current/#{db_name}.sql"}
      else
        fail_with_message "#{database_file} was not found."
      end
    end
    #
    # Exporting database
    #
    config.trigger.before [:halt, :suspend] do |trigger|
      trigger.info = "Dumping database #{db_name}"
      trigger.run_remote = {inline: "mysqldump -u #{db_user} -p#{db_pass} #{db_name} > /srv/database/current/#{db_name}.sql"}
    end
  end
end

Thank you very much

Wow, this is not a standard Vagrantfile.

The problem (if it isn't something from the countless other imported files) lies here:

    cached_addresses = {}
    config.hostmanager.ip_resolver = proc do |vm, _resolving_vm|
      if cached_addresses[vm.name].nil?
        if vm.communicate.ready?
          vm.communicate.execute("hostname -I | cut -d ' ' -f 2") do |type, contents|
            cached_addresses[vm.name] = contents.split("\n").first[/(\d+\.\d+\.\d+\.\d+)/, 1]
          end
        end
      end
      cached_addresses[vm.name]
    end

The Vagrantfile references the plugin vagrant-hostmanager using config.hostmanager.

But why the error message? Vagrant itself doesn't produce error message like this. But look here:

require 'yaml'
vconfig = YAML.load_file("#{ANSIBLE_PATH}/vagrant.default.yml")

Trellis loads some YAML file containing the following:

vagrant_plugins:
  - name: vagrant-bindfs
  - name: vagrant-hostmanager

Also, Vagrant loads some functions from a file:

require File.join(ANSIBLE_PATH, 'lib', 'trellis', 'config')

This includes a function called ensure_plugins which is then called

ensure_plugins(vconfig.fetch('vagrant_plugins')) if vconfig.fetch('vagrant_install_plugins')

Every time you use a Vagrant command, this function is called with the above list of plugins.
Looking inside the function (https://github.com/roots/trellis/blob/master/lib/trellis/vagrant.rb),
this installs the plugins if they aren't installed yet.

The problem is that Vagrant can't discern whether a plugin is installed if you have upgraded to a new Vagrant version. The plugin was installed in the old Vagrant version, and the new Vagrant version somehow can't see that the plugin isn't installed in the new Vagrant version.

Maybe that is why the error is shown. Or not, but I personally think that this is not a problem with the vagrant-hostmanager plugin, but with the Trellis project, so maybe you should file a bug there...

EDIT: Also, you should probably tell them that you can circumvent the update woes by updating any Vagrant plugins before checking whether Vagrant should install a plugin. That removes my bug at least.

ouun commented

Thank you so much @danowar2k for your detailed answer. I'll indeed forward it to the Trellis community, as I mainly want to use the triggers, which are part of core at the latest Vagrant versions.

Best wishes,

Philipp

I can install 2.1.2, but 2.1.3 does not work:

  • Unknown configuration section 'hostmanager'.

But not getting any error while installation

This does not work in vagrant 2.1.3, 2.1.4
Had to downgrade to 2.1.2

I cannot get it to work with either vagrant 2.1.2 or 2.1.4.

Did you make sure your vagrant version?
It pretty sure worked with vagrant 2.12 for me
[ Just if you are wondering where to get an older version --> https://releases.hashicorp.com/vagrant/ ]

I managed to get around this error using 2.1.4
I just commented out the plugin check.
from:

#hostmanager adds hostname to hosts file of host
if Vagrant.has_plugin? "vagrant-hostmanager
    config.hostmanager.enabled = true
    config.hostmanager.manage_host = true

    # IP Address Fix (DHCP Private Network Problem, see https://github.com/smdahlen/vagrant-hostmanager/issues/86 )
    config.hostmanager.ip_resolver = proc do |vm, resolving_vm|
        if hostname = (vm.ssh_info && vm.ssh_info[:host])
            `vagrant ssh -c "hostname -I"`.split()[1]
        end
    end
    else
    puts "For using hostnames on your host system install hostmanager-plugin: vagrant plugin install vagrant-hostmanager"
        puts "and then run 'vagrant hostmanager'"
end

to:

#hostmanager adds hostname to hosts file of host
#if Vagrant.has_plugin? "vagrant-hostmanager"
	config.hostmanager.enabled = true
	config.hostmanager.manage_host = true

	# IP Address Fix (DHCP Private Network Problem, see https://github.com/smdahlen/vagrant-hostmanager/issues/86 )
	config.hostmanager.ip_resolver = proc do |vm, resolving_vm|
	  if hostname = (vm.ssh_info && vm.ssh_info[:host])
	    `vagrant ssh -c "hostname -I"`.split()[1]
	  end
    end

  #else
  #	puts "For using hostnames on your host system install hostmanager-plugin: vagrant plugin install vagrant-hostmanager"
  #	puts "and then run 'vagrant hostmanager'"
  #end

Maybe this will help you. It's not a good way but it works so far for me...

So...my issue was resolved. Now it is "hijacked" by other people. Do I close it or not?