14

In a Vagrant setup, I have to upload a couple of files from the host to the guest during the provisioning phase.

In https://docs.vagrantup.com/v2/provisioning/file.html I can see how to upload a single file, from a source to a destination, but how can I upload multiple files or a folder structure?

NOTE: I know I can do that using the shell provisioner, but in this particular case a set of file uploads would be more appropriate.

Giacomo Tesio
  • 7,144
  • 3
  • 31
  • 48

6 Answers6

12

You would need a separate config.vim.provision section for each file. You can add multiple of those sections to your Vagrantfile, like this:

config.vm.provision :file do |file|
  file.source = "/etc/file1.txt"
  file.destination = "/tmp/1.txt"
end

config.vm.provision :file do |file|
  file.source = "/etc/file2.txt"
  file.destination = "/tmp/2.txt"
end

Output:

[default] Running provisioner: file...
[default] Running provisioner: file...

You see it is executing both provisioning actions. You can verify the file presence inside the virtual machine:

vagrant ssh -- ls -al /tmp/{1,2}.txt
-rw-r--r-- 1 vagrant vagrant 4 Aug 27 08:22 /tmp/1.txt
-rw-rw-r-- 1 vagrant vagrant 4 Aug 27 08:22 /tmp/2.txt
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • Looks exactly what I was looking for... Any tip for entire folder structures? – Giacomo Tesio Aug 27 '14 at 08:47
  • @GiacomoTesio When you want to make a whole folder accessible, use [`config.vm.synced_folder`](https://docs.vagrantup.com/v2/synced-folders/) – hek2mgl Aug 27 '14 at 09:09
  • that's not what I need. For example I have a few files to be moved into /etc/apt/source.list.d/ from the host machine. I tried with tar in the shell provisioner (something like (cd root/ && tar cf - *) | (cd / && tar xf - --keep-old-files) ), but it doesn't works. – Giacomo Tesio Aug 27 '14 at 10:55
  • Then you need to iterate over the folder with ruby and create the `config.vm.provision` entries dynamically. – hek2mgl Aug 27 '14 at 11:38
12

Folder content uploads seem to work as well (I've only tried it with files, not nested folders):

config.vm.provision :file, source: '../folder', destination: "/tmp/folder"
Al Belsky
  • 1,544
  • 13
  • 15
  • 1
    Yep, that seems to be working just fine. Also with nested folders. – zifot Oct 12 '15 at 18:18
  • i had trouble with this. source:'../one/two', destination: '/destination' works as expected the first time, with all the files in /destination. Run vagrant provision again and you get all the files in /destination/two – Steve Jan 11 '16 at 01:48
  • 2
    While this appears to work, the problem is a nested folder issue. In this case `/tmp/` gets flushed with each restart of the Vagrant box so you won’t see it. But if you used this command with the following destination that’s persistent between restarts: `/home/vagrant/folder/`. The first time the Vagrant box is started you get `/home/vagrant/folder/`. The next time the Vagrant box is started you would get `/home/vagrant/folder/folder/`. And the next after that? `/home/vagrant/folder/folder/folder/`. `config.vm.synced_folder` with `type: "rsync"` works better. Using Vagrant 1.8.1. – Giacomo1968 Jan 27 '16 at 17:23
4

In case anybody else just needs a quick and dirty hack to copy a directory structure from the host to the guest, this is how I finally did it:

require 'pathname' # at the beginning of the Vagrantfile

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  # more configuration here

  r = Pathname.new 'root'
  Dir.glob(File.join("root", File.join("**","*"))) do |f|
    if !File.directory?(f) then
      s = Pathname.new f
      t = s.relative_path_from r
      config.vm.provision "file" do |fp|
        fp.source = s.to_s
        fp.destination = "/tmp/root/" + t.to_s
      end
    end
  end

  # more configuration here

end

Thanks to @hek2mgl for getting me on the right track.

Community
  • 1
  • 1
Giacomo Tesio
  • 7,144
  • 3
  • 31
  • 48
  • While this is an older answer, [the synced folder with Rsync option explained in this other answer conceptually works](http://stackoverflow.com/a/33089021/117259); just as the presented it’s dangerous. Setting a line like this in your Vagrantfile should work fine: `config.vm.synced_folder "upload/", "/home/vagrant/upload/", type: "rsync"`. – Giacomo1968 Jan 27 '16 at 17:17
1

This works for me, cd to your vagrant then run

vagrant up
vagrant ssh

vagrant@yourvagrant: sudo chown -R testuser:testuser /var/www/ or whatever folder you want to upload your files

and in you Vagrantfile, add

# we create add script to upload folder to a vagrant guest from local file
config.vm.provision :file, source: '/wamp/www/ian_loans', destination:  "/var/www/solidbond"

just replace the file directory to your needs.Exit and and don't forget to run in your vagrant directory

vagrant provision

finally go to your Ubuntu directory and see if the file you want to upload is there.

vagrant@yourvagrant: cd /var/your file directory
1

You can use file provisioner, as others had mentioned but it's still worth noting that it's possible to use a synced folder functionality with type set to rsync: http://docs.vagrantup.com/v2/synced-folders/rsync.html:

Vagrant can use rsync as a mechanism to sync a folder to the guest machine. This synced folder type is useful primarily in situations where other synced folder mechanisms are not available, such as when NFS or VirtualBox shared folders aren't available in the guest machine.

The rsync synced folder does a one-time one-way sync from the machine running to the machine being started by Vagrant.

On the first vagrant up syncing happens before provisioners are executed. Sample configuration in Vagrantfile would look like this:

config.vm.synced_folder "upload/", "/home/vagrant", type: "rsync"
zifot
  • 2,688
  • 20
  • 21
  • -1: As presented this config is quite dangerous and destructive to basic Vagrant functionality. I am using Vagrant 1.8.1 on Mac OS X 10.10.5 (Yosemite). By setting the source to `upload/` and the destination to `/home/vagrant` the Rsync process will overwrite `/home/vagrant` which means the Vagrant user’s `.ssh` directory will be wiped out so they can no longer login to this machine via SSH after this command is run. The destination should be `/home/vagrant/upload/` so the config should be, `config.vm.synced_folder "upload/", "/home/vagrant/upload/", type: "rsync"`. – Giacomo1968 Jan 27 '16 at 16:49
0

This is a little old but I'll throw another answer in here for entire directory structures for Windows users using PowerShell.

First, create a Powershell script that copies over an entire folder structure from a shared folder.

#Check if the directory you're copying already exists on the VM
$foldercheck = "path\to\folder\on\vm"
if (test-path $foldercheck)
{
    Write-Host "Folder 'path\to\folder\on\vm' already exists..."
}
else {
    #Create the new directory
    New-Item -ItemType Directory -Force -Path "path\to\folder\on\vm"

    #Copy over contents to the directory
    Copy-Item "\\VBOXSRV\<share_name>\path\to\folder\to\copy\*" -Destination "path\to\folder\on\vm" -recurse
}

Then, configure your Vagrantfile to automount a sharedfolder, copy over PowerShell scripts, and then run them in the order specified.

Vagrant.configure(2) do |config|
    config.vm.provider "virtualbox" do |vb|
        # Other settings
        # ...
        # Add shared folders
        vb.customize ["sharedfolder", "add", :id, "--name", "<share_name>", "--hostpath", "path/to/host/folder/location", "--automount"]
    end
    # =================================================================
    # PROVISIONING
    # =================================================================
    # Load up the files to the Guest environment for use by PowerShell
    config.vm.provision "file", source: "path/to/provisioning/files/powershellfile.ps1", destination: "path/to/temporary/location/powershellfile.ps1"
    # Rinse/repeat for additional provisioning files

    # Now provision files in the order they are specified
    config.vm.provision "shell", inline: "path/to/temporary/location/powershellfile.ps1"
    # Rinse/repeat to run PowerShell scripts
end
fujiiface
  • 1,262
  • 11
  • 15