bbenoist / vscode-vagrant

Vagrant support for Visual Studio Code
https://marketplace.visualstudio.com/items/bbenoist.Vagrant
MIT License
38 stars 16 forks source link

Feature request: Vagrant Up then Remote Connection #18

Open JonTheNiceGuy opened 4 years ago

JonTheNiceGuy commented 4 years ago

It would be useful if we can use this plugin (or something similar) to perform vagrant up, then vagrant ssh to achieve connection to the remote machine (with vscode-remote-release).

I have no idea if this is feasible or even sensible, but it would be interesting!

depthoffocus commented 3 years ago

It would be useful!

In the interim I use a strategy to automatically maintain the remote hosts list, which is actually all you need. It solves the problem of the machines coming up on different ports each time.

I thought it worth describing here in case people find it interesting or useful.

Visual Studio Code can parse include directives in .ssh/config, but not wildcards (at the moment).

So I use triggers to regenerate a set of SSH config include files from vagrant ssh-config and store them in a known directory. I then have a method that generates a single index file including each of them, and in turn I include that from .ssh/config.

Basically:

Then each trigger action will maintain your remote SSH hosts list for you, without needing to restart vscode.

The triggers in Vagrantfile:

 config.trigger.after [:up, :provision, :reload, :resume] do |trigger|
    trigger.ruby do |env,machine|
      MyClass.up_trigger(env, machine)
    end
  end

  config.trigger.after [:destroy, :halt, :suspend] do |trigger|
    trigger.ruby do |env,machine|
       MyClass.down_trigger(env, machine)
    end
  end

Then in MyClass is the following code.

This function defines an SSH configuration directory within .vagrant, where I will write individual files containing the output of vagrant ssh-config:

    def ssh_config_dir
      cfg_dir = Pathname.new(Vagrant.user_data_path).join('mydir', 'ssh')
      cfg_dir.mkpath unless cfg_dir.exist?
      cfg_dir
    end

This function builds a master include file of all of those files, which gets stored in the same directory (so, err, don't call a vagrant box "include" ;-):

    def build_ssh_include_file(ssh_dir)
      return if !File.directory? ssh_dir

      include_file = [ ]
      Dir.entries(ssh_dir).each do |item| 
        next if File.directory? item  
        next if item == '.' or item == '..'
        next if item !~ /\.config$/i
        next if item == 'include.config'
        path = ssh_dir.join(item)
        include_file << "Include #{path}"
      end

      ssh_dir.join('include.config').write("# all vagrant hosts\n" + include_file.join("\n"))
    end

The up_trigger function uses bash to invoke vagrant ssh-config to write the SSH config to a file. So this is sort of Unix-only for now. I guess I could directly invoke the underlying Vagrant code that produces that output for a more portable approach.

It then rebuilds the index file.

    def up_trigger(env, machine)

      # make our SSH config directory if we need it
      cfg_dir = ssh_config_dir
      return if !File.directory? cfg_dir

      # now dump the vagrant SSH config into a named file
      ssh_config = `bash -c 'vagrant ssh-config'`
      cfg_dir.join(machine.name.to_s + '.config').write("\n" + ssh_config)

      build_ssh_include_file(cfg_dir)
    end

The down trigger removes the appropriate SSH config file and rebuilds the index. So the host will disappear from your vscode remotes.

    def down_trigger(env, machine)
      cfg_dir = ssh_config_dir
      return if !File.directory? cfg_dir

      cfg_file = cfg_dir.join(machine.name.to_s + '.config')
      cfg_file.unlink if File.file? cfg_file
      build_ssh_include_file(cfg_dir)
    end

So you then include the master list in .ssh/config:

Include ~/.vagrant.d/mydir/ssh/include.config