Vagrant Rust -- installs to /root

Heyo, new user here.

I am setting up a virtual machine to play around with Rust, and trying to use Vagrant, but I am running into two problems:

  1. The .cargo directory installs to /root, not /home/vagrant (default local user directory).
  2. The Rust installation says it completes successfully when I build the vm, but when I ssh into the vm and try running Rust commands, they don’t execute: specifically, if I run “rustc --version”, I get a command not found error.

I’m trying to use the inline script feature in the Vagrantfile to automate installation of a few things in my default box, you can view the Vagrantfile here. Otherwise the Vagrantfile settings are unchanged from the defaults.

Things I’ve tried:
-> Exiting the vm, running “vagrant halt”, and spinning it back up again, in hopes of fixing any $PATH issues automatically. No change in behavior.
-> Mucking around with changing users in the Vagrantfile, specifically adding a “sudo su” command before downloading the Rust install script with the curl command. No change in behavior. Not shown in the example Vagrantfile.

Not trying to use an additional external tool for provisioning. Haven’t tried writing a bash script externally instead of using the inline Vagrantfile script feature.

Ideas?

1 Like

The problem is that the provisioning script runs as root, but rustup is meant to be used by users.

sudo su won’t work in a provisioning script because it normally starts a new interactive shell. For a non-interactive alternative, commands can piped to su:

su vagrant <<EOF
cd ~
commands to run
more commands
EOF

The syntax used here is a heredoc, fed to stdin of the su command. You can alternately write <<'EOF' to prevent variable expansion if need be.


Be aware that PATH issues may require manual fixing anyways. rustup does attempt to take care of this for you, but IIRC the file it modifies is only read on login shells, and IMO it doesn’t really have any business touching that file to begin with. The binaries you need will be in $HOME/.cargo/bin.

Cool, that’s great. Rust installs as expected, and I didn’t have to mess with $PATH, but I’m still getting an error related to the heredoc.

default:   stable installed - rustc 1.29.0 (aa3ca1994 2018-09-11)
default: Rust is installed now. Great!
default: To get started you need Cargo's bin directory ($HOME/.cargo/bin) in your PATH
default: environment variable. Next time you log in this will be done automatically.
default: To configure your current shell run source $HOME/.cargo/env
default: bash: line 3: EOF: command not found

The SSH command responded with a non-zero exit status. Vagrant
assumes that this means the command failed. The output for this command
should be in the log above. Please read the output to determine what
went wrong.

I tried playing with the heredoc syntax, putting the closing EOF delimiter on the beginning of a newline, but bash is still trying to run EOF as a command.

The EOF must be the first, and only, thing on the line in the bash script. Even trailing whitespace is forbidden. Your case is made slightly more complicated by the fact that you’re doing this from inside a ruby heredoc.

Here’s some options:

Vagrant.configure("2") do |config|
  config.vm.box = "hashicorp/precise64"
  config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y git vim curl
su vagrant <<EOF
curl https://sh.rustup.rs -sSf | sh -s -- -y;
EOF
  SHELL
end

You can use ruby’s “squiggly” heredocs for the outer script, which strip the leading indent:

Vagrant.configure("2") do |config|
  config.vm.box = "hashicorp/precise64"
  config.vm.provision "shell", inline: <<~SHELL
    apt-get update
    apt-get install -y git vim curl
    su vagrant <<EOF
    curl https://sh.rustup.rs -sSf | sh -s -- -y;
    EOF
  SHELL
end

Since your command doesn’t contain any single quotes, you can just as easily echo a string instead of using a bash heredoc:

Vagrant.configure("2") do |config|
  config.vm.box = "hashicorp/precise64"
  config.vm.provision "shell", inline: <<~SHELL
    apt-get update
    apt-get install -y git vim curl
    echo 'curl https://sh.rustup.rs -sSf | sh -s -- -y;' | su vagrant
  SHELL
end

vagrant has support for provisioning as the vagrant user; here’s how I install rust in one of my vagrant envs:

  config.vm.provision "shell", privileged: false, inline: <<-SHELL
    curl https://sh.rustup.rs -sSf | sh -s -- -y
  SHELL

(to be clear, use privileged: false to run the provisioning script as non-root.)

2 Likes

Perfect, thanks all. All up and running now. The Vagrantfile I’m using is here, or below if anyone would like to reference it.

Vagrant.configure("2") do |config|
  config.vm.box = "hashicorp/precise64"
   config.vm.provision "shell", inline: <<~SHELL
     apt-get update
     apt-get install -y git vim curl
     echo 'curl https://sh.rustup.rs -sSf | sh -s -- -y;' | su vagrant
   SHELL
end