Book Image

Vagrant Virtual Development Environment Cookbook

Book Image

Vagrant Virtual Development Environment Cookbook

Overview of this book

Table of Contents (17 chapters)
Vagrant Virtual Development Environment Cookbook
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Setting up a Puppetmaster with the puppet apply provisioner


In the first scenario, we'll take a deeper look at how to set up a Puppetmaster with the apply provisioner—using Puppet to manage the Puppetmaster itself. We can start this project in a couple of ways:

  • Bootstrap an entire Puppet environment by installing and configuring the Puppet Labs package repositories and installing Puppet

  • Using the Vagrant images provided by Puppet Labs and available on the Vagrant Cloud

In this example, we'll start with the Puppet Labs images. These images will have the Puppet agent preinstalled and ready to use. Bootstrapping instances to install Puppet typically involves installation and startup with a shell script that can make a development environment more complicated.

Note

A quick note on using Ubuntu images is that when using Debian-based boxes, it is typically a good idea (if not required) to execute an apt-get update command prior to executing package installations. As this often needs to be done prior to bootstrapping a Puppet install, it's often best to do this with an inline shell provisioner.

How to do it...

In this section, we'll discuss how we can set up a source-controlled Puppetmaster and also discuss how it can be bootstrapped. You will also learn how to create Puppet nodes. Let's begin.

Setting up a source controlled Puppetmaster

There are a few ways to start a Puppetmaster project with Vagrant, but I've found that it is often easiest to start with a working (if empty) Puppetmaster configuration and source control from a new Puppetmaster installation. To start a project:

  1. Create a new Vagrant machine. Start by initializing a box from a box provided by Puppet Labs and is available on the Vagrant Cloud. For this example, we'll use:

    vagrant init puppetlabs/ubuntu-14.04-64-puppet
    
  2. To start, we can add a simple shell provisioner to execute an apt-get update command (for Debian-based machines only) and execute the installation of a Puppetmaster:

    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    
    # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
    VAGRANTFILE_API_VERSION = "2"
    
    Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    config.vm.box = "puppetlabs/ubuntu-14.04-64-puppet"
      
      config.vm.define "puppetmaster" do |puppetmaster|
        puppetmaster.vm.hostname = "puppet"
        puppetmaster.vm.provision "shell", inline: "apt-get update && apt-get install -y puppetmaster"
      end
    end

    This will start a Vagrant box and install the puppetmaster package. We'll use this initial package installation to create an initial configuration directory.

  3. Start the box with the vagrant up command.

  4. Once the box has finished booting, copy the /etc/puppet directory to the /vagrant directory. Access the machine with the vagrant ssh command and copy the directory with the cp /etc/puppet /vagrant command.

    This will copy the contents of the configuration directory outside the virtual machine to the host machine. Verify that the contents of the working directory look something like this:

    ├── Vagrantfile
    ├── puppet
    │   ├── environments
    │   │   └── example_env
    │   │       ├── README.environment
    │   │       ├── manifests
    │   │       └── modules
    │   ├── manifests
    │   ├── modules
    │   ├── puppet.conf
    │   └── templates
  5. With our working directory set, destroy the Vagrant machine with the vagrant destroy command. This will leave a clean working directory to begin working.

  6. Before starting with our Puppetmaster, let's also allow all certificate exchanges to be signed automatically. Create a file in the Puppet root directory (the directory with puppet.conf) named autosign.conf with a single line:

    *

    This allows all certificate requests to be allowed to our local Puppetmaster. This isn't a good idea in a production environment, but it will make our development processes a bit simpler.

Bootstrapping a Puppetmaster

Now that we have a working directory, we can start bootstrapping a Puppetmaster. In some cases, a Puppetmaster can be bootstrapped with a shell script, but it's far more fun (and useful!) to manage a Puppetmaster with the Puppet itself.

  1. Start with our Vagrantfile in the previous step, but remove the step of installing the Puppetmaster itself:

    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    
    # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
    VAGRANTFILE_API_VERSION = "2"
    Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
      config.vm.box = "puppetlabs/ubuntu-14.04-64-puppet"
      config.vm.define "puppetmaster" do |puppetmaster|
        puppetmaster.vm.hostname = "puppet"
        puppetmaster.vm.provision "shell", inline: "apt-get update"
      end
    end

    This will start our Puppet machine and update the package repositories for use.

  2. Let's start simply by creating a single manifest file to bootstrap our Puppetmaster. In the manifests/ folder, add a new file named site.pp. This file is the manifest file for our Puppetmaster. Define the content of this file to simply output a notification. This will be the start of our iterative approach to develop puppet manifests:

    node /^puppet/ {
      notify{"Install a Puppetmaster": }
    }
  3. Define a puppet apply provisioner in the Vagrantfile. Immediately after the shell provisioner, add the Puppet provisioner block:

        puppetmaster.vm.provision "puppet"  do |puppet|
          puppet.manifests_path = "puppet/manifests"
          puppet.manifest_file  = "site.pp"
          puppet.module_path    = "puppet/modules"
        end

    This is a basic puppet apply provisioner block. It will look to begin catalog compilation with the site.pp file and use the modules/ directory to hold reusable Puppet modules.

  4. Start the virtual machine with the vagrant up command. The final step in booting the machine should be output from the Puppet provisioner:

    ==> puppetmaster: Notice: Compiled catalog for puppet.localdomain in environment production in 0.09 seconds
    ==> puppetmaster: Notice: Install a Puppetmaster
    ==> puppetmaster: Notice: /Stage[main]/Main/Node[puppet]/Notify[Install a Puppetmaster]/message: defined 'message' as 'Install a Puppetmaster'
    ==> puppetmaster: Notice: Finished catalog run in 0.01 seconds
    

    Our output notification here notes that the notify resource was successfully called by the Puppet provisioner. The Puppet provisioner can be called subsequently with the vagrant provision command rather than doing a full restart.

  5. With our initial Puppetmaster machine ready to provision, let's create an environment that allows us to modify the configuration of the Puppetmaster (and any Puppet modules) using a local text editor. To do this, we'll link our puppet/ directory in our host working directory to the /etc/puppet configuration directory on the guest. (This was our reason to copy files in our first step.) To write this puppet module, we will have to:

    1. Install the Puppetmaster package.

    2. Connect to the Vagrant machine with the vagrant ssh command.

    3. Remove the existing /etc/puppet directory installed as part of the Puppetmaster package. We will replace the installed directory with the one we created earlier in our Vagrant working directory.

    4. Create a symbolic link in the guest from /vagrant/puppet to /etc/puppet.

    5. Restart the Puppetmaster daemon with a service puppetmaster restart command. This will read any differences that are present in the symlinked working directory.

    If you have done puppet development previously, you might recognize this as a potential use of the package-file-service pattern. We can replace the notify command in the site.pp file created previously with some Puppet code that reflects the installation of the Puppetmaster. The full site.pp manifest looks like this:

    node /^puppet/ {
      package{"puppetmaster":
        ensure => '3.7.3-1puppetlabs1',
      }
    
      file{"/etc/puppet":
        ensure  => 'link',
        force   => 'true',
        target  => '/vagrant/puppet',
        require => Package["puppetmaster"],
        notify  => Service["puppetmaster"],
      }
    
      service{"puppetmaster":
        ensure => running,
        require => Package['puppetmaster'],
      }
    }

    This will install the Puppetmaster, link our Puppetmaster code, and start the Puppetmaster.

  6. Execute the manifest by running vagrant provision puppetmaster. This will provision and start a Puppetmaster instance in the virtual machine.

  7. Verify that the Puppetmaster is running successfully by logging in to the machine (vagrant ssh puppetmaster) and running the Puppet agent process. After logging in to the machine, become a super user by executing the following command:

    sudo puppet agent –t
    

    This will start the Puppet agent. The Puppet agent will attempt to communicate with a Puppetmaster at the default address (Puppet) and retrieve a catalog. The Puppet agent should return quickly, as no changes are registered between the run of the Vagrant provisioner and the agent run:

    Info: Retrieving pluginfacts
    Info: Retrieving plugin
    Info: Caching catalog for puppet.localdomain
    Info: Applying configuration version '1416969518'
    Notice: Finished catalog run in 0.09 seconds
    

This Puppetmaster setup can be used to continue developing Puppet code in order to deploy using the masterless or agent approach (both should be usable interchangeably). When developing modules, it is often enough to develop using the masterless approach, but it can also be useful to see how nodes interact in a full master/agent environment.