Installing a puppet module from a manifest script

試著忘記壹切 提交于 2019-11-28 15:59:36

I ran into this problem as well. The trick is to download the modules using a vagrant shell command before the puppet provisioner runs.

config.vm.provision :shell do |shell|
  shell.inline = "mkdir -p /etc/puppet/modules;
                  puppet module install puppetlabs/nodejs;
                  puppet module install puppetlabs/apache"
end

config.vm.provision :puppet do |puppet|
  puppet.manifests_path = "puppet/manifests"
  puppet.manifest_file = "site.pp"
end

Order is important here, and since the puppet provisioner hasn't run the folder /etc/puppet/modules does not exist yet.

The reason I decided, like alonisser, to install the modules using the puppet module tool instead of using a module folder with the vagrant puppet provisioner was because I didn't want to have to download all of the dependencies of the modules I was going to use and store all of those modules in my source control. Running these two commands results in 5 dependencies that would otherwise sit in my git repository taking up space.

Here's what I did to make the puppet module install command run at most once:

$script = <<EOF
mkdir -p /etc/puppet/modules
(puppet module list | grep puppetlabs-mysql) ||
   puppet module install -v 2.1.0 puppetlabs/mysql
EOF

Vagrant::Config.run do |config|
   config.vm.provision :shell, :inline => $script

I use an approach similar to @brain_bacon - the additional complication I had is that in addition of pre-packaged modules like puppetlabs/nodejs I needed local modules relative to my Vagrantfile. I didn't want to check in the pre-packaged modules as part of my repository, nor use git submodules because of the problems pointed out by @Igor Popov.

Finally the solution I chose was to use a shell script to download the modules, but forcing their path into the shared directory between the Vagrant VM and the host, and using .gitignore to avoid that path being under source control.

To be clear, with this tree:

jcmendez$ tree
.
├── README.md
├── Vagrantfile
├── files
├── puppet
│   ├── manifests
│   │   └── init.pp
│   └── modules
│       ├── misc
│       │   └── manifests
│       │       └── init.pp
│       ├── mysql
   ...
│       └── wordpress
│           ├── files
│           │   ├── wordpress-db.sql
│           │   ├── wp-config.php
│           │   └── wp-tests-config.php
│           └── manifests
│               └── init.pp
└── wordpress

On .gitignore I added

  /puppet/modules/mysql

On Vagrantfile

  config.vm.provision :shell do |shell|
    shell.inline = "puppet module install puppetlabs/mysql --force --modulepath '/vagrant/puppet/modules'"
  end

  config.vm.provision :puppet do |puppet|
    puppet.manifests_path = 'puppet/manifests'
    puppet.module_path = 'puppet/modules'
    puppet.manifest_file  = "init.pp"
    puppet.options="--verbose --debug"
  end
sebastianwagner

You can install puppet modules on the host machine within your vagrantdir:

puppet module --modulepath=./puppet/modules/ install puppetlabs/mysql

Vagrant takes care to mount this directory to the right place. So there is no need to run scripts other than puppet itself on the node.

Inspired by wtanaka.com's answer, I implemented a solution like below which I think is much more readable.

1) create a new ruby file called 'puppet_deps.rb' under the same folder as Vagrantfile with code like below:

def install_dep(name, version, install_dir = nil)
    install_dir ||= '/etc/puppet/modules'
    "mkdir -p #{install_dir} && (puppet module list | grep #{name}) || puppet module install -v #{version} #{name}"
end

2) In your Vagrantfile, you can load this ruby file and use it to specify the puppet dependency:

# on top of your Vagrantfile
require './puppet_deps'
...
...
# in your vm definition, use a shell provisioning this:
config.vm.provision :shell, :inline => install_dep('puppetlabs-firewall', '1.1.3')
config.vm.provision :shell, :inline => install_dep('puppetlabs-stdlib', '4.3.2')

You can create a directory for modules and add the apt module that you downloaded from the forge. So it will be modules/apt/*. Then you can specify this module directory in Vagrantfile (module_path is relative to Vagrantfile):

Vagrant.configure("2") do |config|
  config.vm.provision :puppet do |puppet|
    puppet.module_path = "modules"
  end
end

For more information see the documentation.

@brain_bacon's strategy worked almost perfectly for me, with one small caveat - if the module already exists, then the provisioning script fails, halting the provisioning process. The following adjustment fixed this:

config.vm.provision :shell, :run => "always" do |shell|
  shell.inline = %{
    mkdir -p /etc/puppet/modules;
    function install_module {
      folder=`echo $1 | sed s/.*-//`
      if [ ! -d /etc/puppet/modules/$folder ]; then
        puppet module install $1
      fi
    }
    install_module stdlib
    install_module apt
    install_module ruby
  }
end

Using answers from this question I created this script:

#!/bin/bash

function install_module {
   IFS=':' read module version <<< "$1"
   if (puppet module list | grep $module ) >/dev/null; then
    echo "Module $module is already installed"
   else
        if [ -z "$version" ]; then
            puppet module install $module
        else 
        puppet module install -v $version $module
    fi
    fi  
}

if dpkg --compare-versions `puppet --version` "lt" 3.8.7; then
    sudo apt-get remove --purge -y puppet
    sudo apt-get -y autoremove
fi

if which puppet >/dev/null; then
    echo "Puppet is already installed"
else
    echo "Installing puppet"
    wget https://apt.puppetlabs.com/puppetlabs-release-trusty.deb
    sudo dpkg -i puppetlabs-release-trusty.deb
    sudo apt-get update
    sudo apt-get install -y puppet=3.8.7*
    mkdir -p /etc/puppet/modules
fi

for var in "$@" 
do
    install_module "$var"
done

Then you can use it from your Vagrantfile like this:

puppet_modules = [
    'puppetlabs-stdlib:4.16.0',
    'puppetlabs-apt:2.3.0',
    'puppet-nodejs:2.3.0'
    ]

config.vm.provision "shell", path: "puppet/scripts/puppet.sh", args: puppet_modules.join(" ")

It removes puppet from vm if version is lower than 3.8.7, then installs puppet 3.8.7, and then installs all the modules.

It would probably work only on debian/ubuntu boxes.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!