Vagrant Puppet guest cli output on host - vagrant

I have been using Vagrant with Puppet for a few days; this is a cool tool in the context of automation.
I have a question. Sometimes apt operations (or git clone) take a few minutes to download all the packages. Vagrant logs all operations on the host's cli, but only those that have already been performed. There is no information about the currently executing task, so I am not sure if the machine hanged or if an operation is still running.
Is there a possibility to output all the guest's cli output on the host's cli in Vagrant?
I am running Vagrant 1.4.3 on Windows 8 via Git Bash and this solution didn't work for me:
Vagrant provision live output

You can pass extra options to the puppet command in the Vagrantfile, among which --verbose and/or --debug. This is the example reported in Vagrant documentation (link):
Vagrant.configure("2") do |config|
config.vm.provision "puppet" do |puppet|
puppet.options = "--verbose --debug"
end
end
By passing these options the output in the host console should be much more verbose.

Related

Using Vagrant to set up a VM with KVM/qemu without VirtualBox

I'm getting started Vagrant and want to use it with KVM/qemu (and the Virtual Machine Manager GUI), instead of installing VirtualBox. So I first installed Vagrant:
$ vagrant --version
Vagrant 1.9.1
$ vagrant box list
There are no installed boxes! Use `vagrant box add` to add some
As per these posts, I require vagrant-libvirt for it to work with KVM, so I installed that next:
$ vagrant plugin list
vagrant-libvirt (0.0.37)
vagrant-share (1.1.6, system)
Next, I to add a CentOS(7) box using vagrant box add "centos/7" and selected libvirt, when prompted. After which, I ran vagrant init and didn't encounter any errors:
$ vagrant init centos/7
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.
However, vagrant up seems to be erroring out, like so:
$ vagrant up
No usable default provider could be found for your system.
Vagrant relies on interactions with 3rd party systems, known as
"providers", to provide Vagrant with resources to run development
environments. Examples are VirtualBox, VMware, Hyper-V.
The easiest solution to this message is to install VirtualBox, which
is available for free on all major platforms.
If you believe you already have a provider available, make sure it
is properly installed and configured. You can see more details about
why a particular provider isn't working by forcing usage with
`vagrant up --provider=PROVIDER`, which should give you a more specific
error message for that particular provider.
Here's the provider section in the Vagrantfile
config.vm.provider :libvirt do |domain|
domain.driver = "qemu"
domain.memory = 512
domain.cpus = 1
end
I tried modifying it to:
config.vm.provider :libvirt do |domain|
domain.driver = "kvm"
domain.host = 'localhost'
domain.uri = 'qemu:///system'
domain.memory = 512
domain.cpus = 1
end
I also tried vagrant up --provider=kvm, vagrant up --provider=qemu, and vagrant up --provider=libvirt too, to no avail.
Is there any step that I've missed? Or another package/dependency that needs to be installed?
Edit: After the adding centos/7 using vagrant, it shows up when running vagrant box list.
$ vagrant box list
centos/7 (libvirt, 1611.01)
Start vagrant box with command
vagrant up --provider=kvm
Although it has been said in https://seven.centos.org/2017/08/updated-centos-vagrant-images-available-v1707-01/ that
The vagrant-libvirt plugin is only compatible with Vagrant 1.5 to 1.8
You can use either the command line option --provider=kvm or you can set the VAGRANT_DEFAULT_PROVIDER environment variable:
export VAGRANT_DEFAULT_PROVIDER=kvm # <-- may be in ~/.profile, /etc/profile, or elsewhere
vagrant up
vagrant-libvirt(0.0.40) is compatible with Vagrant 2.0.2 if you are running Ruby 2.3, at least on Linux Mint 18.3 (Ubuntu 16.04). I used vagrant from the Debian download on the vagrantUp website and installed the plugin using it without any problem.

How can I programmatically query Vagrant for its provisioning status?

The Goal
I am attempting to conditionally run the vagrant-berkshelf plugin. By default, enabling the plugin causes Berkshelf to resolve and vendor cookbooks on every single vagrant up (which is a relatively expensive operation) even if the current vagrant operation isn't a provisioning run. For example, I expect Berkshelf to run when I run:
vagrant up the first time, or
when I execute vagrant reload --provision.
The source implies there ought to be a way to query Vagrant itself to determine if it's a provisioning run. Specifically, there ought to be a way to hook into #env[:provision_enabled] or vagrant.actions.vm.provision, but I'm unable to figure out how to do this from within the Vagrantfile itself.
Is this method actually bound to the Vagrant object? If not there, then where? And how can I introspect it?
Software Versions
Vagrant 1.8.1
vagrant-berkshelf 4.1.0
What I've Tried
As a workaround, I have tried moving the Berkshelf plugin inside the Chef block, intending that it only run when the Chef provisioner does. For example:
Vagrant.configure(2) do |config|
config.berkshelf.enabled = false
config.vm.provision :chef_solo do |chef|
config.berkshelf.enabled = true
end
end
However, Berkshelf still runs every time I vagrant up or vagrant reload, which is not the desired behavior. The cookbooks are still resolved and vendored on each run. Consider the following elided output:
==> default: Updating Vagrant's Berkshelf...
==> default: Resolving cookbook dependencies...
==> default: Using karaf (0.2.1)
==> default: Vendoring karaf (0.2.1) to /Users/foo/.berkshelf/vagrant-berkshelf/shelves/berkshelf20160215-19428-unzcx1-default/karaf
Questions That Aren't Duplicates of This One
There is a vaguely related question where the accepted answer is an ugly hack that looks for the presence of .vagrant/machines/default/virtualbox/action_provision or similar, but it is not an exact duplicate of this question as it doesn't address how to programmatically query Vagrant's internal state through the runtime objects or API Vagrant exposes. It may hold a pragmatic (if kludgey) answer based on filesystem semaphores, but it does not answer the question I'm actually asking.
If it's possible for you to provision using vagrant provision instead of the --provision flag you can check with the following code in Vagrantfile:
if ARGV[0] == 'provision'
# Run berkshelf plugin
end
The code inside the conditional will only run on vagrant provision. This won't work when using vagrant reload with the --provision flag as you were saying, but you could simply run vagrant provision after running vagrant reload. You can also use if ARGV[0] == 'up' or if ARGV[0] == 'reload' to run when using other commands.
See: Getting command line arguments inside the Vagrantfile

How do I package a vagrantfile so that it is used when 'vagrant init' is called on the box?

I know this is a stupid question, I'm still struggling to grok vagrant.
I run vagrant on a windows host, and I'm building Linux guest VMs using VirtualBox. My guest VM is running, and now I want to package it.
The Vagrant documentation says "A common misconception is that the --vagrantfile option will package a Vagrantfile that is used when vagrant init is used with this box. This is not the case. Instead, a Vagrantfile is loaded and read as part of the Vagrant load process when the box is used. For more information, read about the Vagrantfile load order."
Got it. But that's what I want to do! When I run "vagrant package --output myboxname.box", my carefully-crafted Vagrant file does not appear to be in the package. I test the box as follows (in Windows, after copying the new box):
cd \some_new_dir
vagrant box add myboxname.box --name boxname
vagrant init boxname
The new Vagrantfile is the generic vagrant version, with none of my changes.
When I
vagrant up
The vm comes up fine, but (not surprisingly) none of Vagrantfile directives have happened.
I know I'm missing something basic -- can someone please help me out?
Try copying the Vagrantfile from the directory you ran vagrant package in to the \some_new_dir directory. Then, without running vagrant init (because this will overwrite the Vagrantfile with an empty file), run vagrant up to use the Vagrantfile.

Hot deploying app builds to Vagrant

Please note: although I mention Gradle/Groovy in this question, this is strictly about Vagrant usage, and could just as easily apply to any other language/build system.
I am new to Vagrant and am trying to figure out how Vagrantfiles, when pushed to source control, interact with that repo's build.
Say I have the following repo, built by Gradle:
src/
main/
groovy/
<lots of groovy source>
test/
groovy/
<lots of groovy test source>
build.gradle
settings.gradle
Now let's say that, without Vagrant, I would normally clone this repo and run gradle clean build to run unit tests on the code, and ultimately, package it into a running program (executable JAR). Then a gradle run starts the app.
Well, in a lot of GitHub repos I see Vagrantfiles committed. So obviously this is to make it easy to spin up a VM and run the respective app inside of. I'm trying to figure out the typical "flow" of incorporating a Vagrantfile into my repo above such that developers can:
Clone the repo
Build with Gradle
Somehow, deploy to the Vagrant box
Test the running app instance (running inside the box)
Tweak the code } #4, #5 and #6 quick/rapid dev-test-tweak cycles utilizing hot re-deploys
Re-test
Take a look at this Vagrantfile for a CAS server (chosen at random). I think this is where the magic happens, in terms of deploying and restarting the server on the box, but I checked the Vagrant docs for shell.inline and nothing concrete came up.
So I ask: How do I "integrate" my Vagrantfile with my build, such that the build produces a deployed, running app? Further, what do my run/deploy-test-code-redeploy cycles look like with Vagrant boxes (what I call "hot deploying")?
I'm going to explain how I would achieve what you are looking to do, this might not be the official way to do it, so anyone with more Vagrant experience should please provide pointers on where it can be improved. I've been working with Vagrant for about 6 months now. You say you are new to Vagrant, so I'll be as complete as I can, even though some parts you have probably already mastered, but might be useful to other users.
tl;dr; Skip to Creating the Vagrantfile section if you are already familiar with how the Vagrantfile works
Let's start with what the example Vagrantfile is doing.
config.vm.box = "puppetlabs/centos-6.5-64-puppet"
This is telling Vagrant to pull the box on which everything else is built. You can find a lot of official and community contributed boxes on the Vagrant Cloud. This one being from puppetlabs, based on CentOS 6.5 64-bit with Puppet already installed.
config.vm.network "forwarded_port", guest: 8080, host: 8088
This is telling Vagrant to forward port 8088 on your host to 8080 on the Vagrant box. So accessing http://127.0.0.1:8088 on your host will access port 8080 on the guest.
config.vm.provision :shell do |shell|
Provisioning is the process of setting up the Vagrant box when it is ran for the first time. Provisioning will only run once for a new VM, unless forced. See the provisioning section of the Basic Usage Vagrant Docs. This one specifically is executing a bunch of shell commands when it is being provisioned.
shell.inline = "command;
command;"
Shell inline is sending these commands, seperated by the semicolon, to the box. This is to automate the commands as if you were typing them in an SSH session yourself. The Vagrant Docs on Shell Provisioning has some more advanced uses where you can define an actual file to be executed.
Note: Your shell script should not try to execute tools that have not yet been installed. (ex. Running a Python script where Python is not available yet).
config.vm.provision "puppet" do |puppet|
I can't comment much on the Puppet section since I'm not a Puppet user (yet, probably). This is setting some Puppet values.
shell.inline = "cd /vagrant && mvn clean package;
sudo cp target/cas.war /srv/tomcat/cas/webapps/;
sudo /sbin/service tomcat-cas restart"
This is also executing shell commands. Basically changing directory, cleaning, copying cas.war to the webapps directory and then restarting the service. More on the /vagrant shared folder later. Now we have enough to start building our own Vagrant file on. I'm going to keep the sample simple to make it generic.
Creating the Vagrantfile
You will most likely want to build on a Vagrant box that already matches your requirements, but for now, let's not do that. You can however find a lot of already created boxes on the Vagrant Cloud. I'm going to show you how to get a (very) simple Python app running using Flask.
Pick your favourite distribution from the available Vagrant boxes. I'm going to use ubuntu/trusty64 since I use it on a daily basis. All command should be easily translated to other distributions.
Create a new directory for your project and open a shell / console window in it.
Using the console, initialize your Vagrant box vagrant init ubuntu/trusty64. This will create a base Vagrantfile for you to work from.
Open your Vagrantfile and uncomment config.vm.network "forwarded_port", guest: 5000, host: 8080. We want port 8080 to take us to port 5000 on the guest machine. Tip: For your project, it will be wise to choose a port that is most likely not already in use to avoid clashing with other apps. 8080 might be bad choice, 8089 will be better.
Let's add some scripts to execute on provisioning. Since Python is shipped with Ubuntu (and most other I know) we don't need to install Python, but we do need pip (a Python Package manager) and Flask.
config.vm.provision :shell do |shell|
shell.inline = "cd /vagrant;
sudo apt-get -y install python-pip;
sudo pip install Flask;"
end
This will change the directory to the Vagrant share. Install pip using Ubuntu's package manager, then install Flask using pip. The -y flag is to automatically have apt-get install without prompting for a yes/no question. You might need to run Vagrant up --provision a couple of times to get all your commands 100% correct.
Note on the Vagrant share: The Vagrant share is a directory that is synced between the host and guest machine and will be available under /vagrant. It includes all the files and directories in your project directory (where your Vagrantfile resides).
We now have all the tools we need to run our app. I've created an incredibly simple Flask app as a sample. Download it to your project directory from this Gist and name it app.py
Now we'll be able to run the Python app located in your project directory. I like to keep the install sections and running sections seperate. So add another section that starts the app.
Note: The & makes the app fork to the background so the vagrant up can complete. You'll probably want to do something more fancy than this with your app.
config.vm.provision :shell do |shell|
shell.inline = "/vagrant/app.py &"
end
Finally we can start everything and have Vagrant do its magic. In your console, in your project directory (where your Vagrant file is located). Run vagrant up.
Moment of truth. Open your browser (on the host) and browse to http://127.0.0.1:8080/. You should see Hello Vagrant Provisioned World!.
That takes care of the provisioning of your app. Automatically, from a Vagrantfile, that you can commit with your project code.
Now to get to your initial steps, and how this fits in.
Integrating into your development workflow
I'm listing your steps, integrated with Vagrant.
Clone the repo
This step stays the same, with the exception of a Vagrantfile included in your repo with provisioning for any required libraries and tools required for your project.
Run vagrant up in the project directory. This will automatically create and provision the box and share your project with the box.
You can build the project in the Vagrant provisioning steps, but if you are actively developing the application, you might not want to do that.
Test the running app instance (running inside the box) - Simply SSH into the box, enter the `/vagrant' directory and run your app.
Tweak the code } #4, #5 and #6 quick/rapid dev-test-tweak cycles utilizing hot re-deploys
Since your project is shared live between the host and the guest. you can simply stop the app (if running) and run the app again on the guest. No copying needed.
Re-test
This will give you quick developent cycles while keeping the environment the same. A new developer can simply clone and vagrant up to get going on the project without worrying about the environment and whatnot.
Continuous Integration is a vast topic. You can still apply the practises to your repo, etc. But I'd skip the CI deployment process while developing. I make use of Jenkins and Capistrano for my CI deployments, but it is too heavy weight for development. In production I won't use Vagrant since it will double-virtualize your VM already (unless you run bare metal). For production I'll make use of Docker and Fig.
I hope this explains how to integrate Vagrant into your flow for your project, please do comment if anything needs clarification. I believe the sample should word perfectly, since that is the goal of using Vagrant.

Understanding vagrant with a docker provisioner

So my goal here is to have Vagrant spin me up a VM that I can use as a rails web application development environment. I am very, very new to Vagrant, Docker, etc. and wanted to check if this even makes sense:
Should I be creating one Docker image, or two? My thought was that one image would be for rvm, ruby, and rails, and the other image would be for Apache.
The goal would be something that could be distributed to a few people, who would then get the exact same environment set up easily.
Here is my current Vagrantfile:
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "phusion/ubuntu-12.04-amd64"
config.vm.network "forwarded_port", :guest => 80, :host => 5000
# Share the docker configs
config.vm.synced_folder "./docker", "/docker"
config.vm.provision "docker" do |d|
d.build_image "-t me/rvm-dev /docker/rvm-dev"
d.run "me/rvm-dev"
end
config.vm.host_name = "coursera-rail.dev"
config.vm.network :forwarded_port, guest:80, host:8080
end
And here is my current (probably wrong) Dockerfile
(as an aside, I am trying to find some good guidance on creating a "docker" user account so I don't run everything as root)
## Dockerfile
FROM ubuntu:latest
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y curl
RUN mkdir -p /tmp/downloads
## Install RVM, Ruby, Rails
RUN cd /tmp/downloads
RUN \curl -L https://get.rvm.io | bash -s stable --ruby --rails
Lastly, the above works, and if I use vagrant ssh I can head in to my VM, but obviously I am unable to use RVM without doing docker run -i -t me/rvm-dev and getting a shell with docker. Is this supposed to be the workflow?
In my humble opinion, the best flow would be to
1) separate your app and db stack into vagrant boxes
or
2) run docker on the host (the physical machine) and your DB instance (mysql, etc..) inside a vagrant box.
Option one is best because you are "sandboxing" both layers of the stack (DB and APP) inside Vagrant thus leaving the OS on your local machine (windows, Linux, Mac OSX) instact. Of course, you could install/run your IDE on the physical machine.

Resources