diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index cb76a2b..fcb3277 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,18 @@
Changelog
=========
+2017-02-20
+----------
+Hugo Antoniio Sepulveda Manriquez:
+ * Updated puppet plugin module:
+ * Installs Puppetlabs 4 PC1 agent software from apt.puppetlabs.com
+ * Enables you to install modules from forge.puppetlabs.com in the image
+
+ * Important limitations
+ * Only works for Wheezy and Jessie for now.
+ * If you need puppet 3, just add 'puppet' packages provider list.
+ * modules: When installing from forge, it assumes 'install --force'
+ * modules: When installing from forge, It assumes master version on forge
2016-06-04
----------
diff --git a/bootstrapvz/plugins/puppet/README.rst b/bootstrapvz/plugins/puppet/README.rst
index 530694f..86c3aa3 100644
--- a/bootstrapvz/plugins/puppet/README.rst
+++ b/bootstrapvz/plugins/puppet/README.rst
@@ -1,16 +1,25 @@
Puppet
------
-Installs `puppet `__ and optionally applies a
+Installs `puppet version 4 ` PC1 From the site
+repository `` and optionally applies a
manifest inside the chroot. You can also have it copy your puppet
configuration into the image so it is readily available once the image
is booted.
-Keep in mind that when applying a manifest, the system is in a chrooted
-environment. This can prevent daemons from running properly (e.g.
-listening to ports), they will also need to be shut down gracefully
-(which bootstrap-vz cannot do) before unmounting the volume. It is
-advisable to avoid starting any daemons inside the chroot at all.
+Rationale and use case
+~~~~~~~~~~~~~~~~~~~~~~
+
+You want to use this plugin when you wish to create an image and to be able to
+manage that image with Puppet. You have a Puppet 4 setup in mind and thus you
+want the image to contain the puppet agent software from the puppetlabs repo.
+You want it to almost contain everything you need to get it up and running
+This plugin does just that!
+While you're at it, throw in some modules from the forge as well!
+Want to include your own modules? Include them as assets!
+
+For now this plugin is only compatible with Debian versions Wheezy and Jessie.
+These are also the distributions supported by puppetlabs.
Settings
~~~~~~~~
@@ -18,7 +27,61 @@ Settings
- ``manifest``: Path to the puppet manifest that should be applied.
``optional``
- ``assets``: Path to puppet assets. The contents will be copied into
- ``/etc/puppet`` on the image. Any existing files will be overwritten.
- ``optional``
-- ``enable_agent``: Whether the puppet agent daemon should be enabled.
+ ``/etc/puppetlabs`` on the image. Any existing files will be overwritten.
``optional``
+- ``install_modules``: A list of modules you wish to install available from
+ `` inside the chroot. It will assume a FORCED
+ install of the modules.
+ This list is a list of tuples. Every tuple must at least contain the module
+ name. A version is optional, when no version is given, it will take the
+ latest version available from the forge.
+ Format: [module_name (required), version (optional)]
+- ``enable_agent``: Whether the puppet agent daemon should be enabled.
+ ``optional - not recommended``. disabled by default. UNTESTED
+
+An example bootstrap-vz manifest is included in the ``KVM`` folder of the
+manifests examples directory.
+
+Limitations
+~~~~~~~~~~~
+(Help is always welcome, feel free to chip in!)
+General:
+
+- This plugin only installs the PC1 package for now, needs to be extended to
+ be able to install the package of choice
+- The puppetlabs agent is only available to i386 and amd64 architectures. ARM
+ is not available from repository at this time. If you need to have the agent
+ on ARM, you need to build the agent yourself, and install them through the
+ ``packages`` section of the bootstrap-vz manifest
+
+Manifests:
+
+- Running puppet manifests is not recommended and untested, see below
+
+Assets:
+
+- The assets path must be ABSOLUTE to your manifest file.
+
+install_modules:
+
+- It assumes installing the given list of tuples of modules with the following
+ command:
+ "... install --force $module_name (--version $version_number)"
+ The module name is mandatory, the version is optional. When no version is
+ given, it will pick the master version of the
+ module from ``
+- It assumes the modules are installed into the "production" environment.
+ Installing into another environment e.g. develop, is currently not
+ implemented.
+- You cannot include local modules this way, to include you homebrewn modules,
+ You need to inject them through the assets directive.
+
+UNTESTED:
+
+- Enabling the agent and applying the manifest inside the chrooted environment.
+ Keep in mind that when applying a manifest when enabling the agent option,
+ the system is in a chrooted environment. This can prevent daemons from
+ running properly (e.g. listening to ports), they will also need to be shut
+ down gracefully (which bootstrap-vz cannot do) before unmounting the
+ volume. It is advisable to avoid starting any daemons inside the chroot at
+ all.
diff --git a/bootstrapvz/plugins/puppet/__init__.py b/bootstrapvz/plugins/puppet/__init__.py
index a1f3765..55ac88f 100644
--- a/bootstrapvz/plugins/puppet/__init__.py
+++ b/bootstrapvz/plugins/puppet/__init__.py
@@ -7,12 +7,17 @@ def validate_manifest(data, validator, error):
def resolve_tasks(taskset, manifest):
- taskset.add(tasks.AddPackages)
+ taskset.add(tasks.CheckRequestedDebianRelease)
+ taskset.add(tasks.AddPuppetlabsPC1SourcesList)
+ taskset.add(tasks.InstallPuppetlabsPC1ReleaseKey)
+ taskset.add(tasks.InstallPuppetAgent)
if 'assets' in manifest.plugins['puppet']:
taskset.add(tasks.CheckAssetsPath)
taskset.add(tasks.CopyPuppetAssets)
if 'manifest' in manifest.plugins['puppet']:
taskset.add(tasks.CheckManifestPath)
taskset.add(tasks.ApplyPuppetManifest)
+ if 'install_modules' in manifest.plugins['puppet']:
+ taskset.add(tasks.InstallModules)
if manifest.plugins['puppet'].get('enable_agent', False):
taskset.add(tasks.EnableAgent)
diff --git a/bootstrapvz/plugins/puppet/assets/gpg-keyrings-PC1/jessie/puppetlabs-pc1-keyring.gpg b/bootstrapvz/plugins/puppet/assets/gpg-keyrings-PC1/jessie/puppetlabs-pc1-keyring.gpg
new file mode 100644
index 0000000..33a7a49
Binary files /dev/null and b/bootstrapvz/plugins/puppet/assets/gpg-keyrings-PC1/jessie/puppetlabs-pc1-keyring.gpg differ
diff --git a/bootstrapvz/plugins/puppet/assets/gpg-keyrings-PC1/wheezy/puppetlabs-pc1-keyring.gpg b/bootstrapvz/plugins/puppet/assets/gpg-keyrings-PC1/wheezy/puppetlabs-pc1-keyring.gpg
new file mode 100644
index 0000000..33a7a49
Binary files /dev/null and b/bootstrapvz/plugins/puppet/assets/gpg-keyrings-PC1/wheezy/puppetlabs-pc1-keyring.gpg differ
diff --git a/bootstrapvz/plugins/puppet/manifest-schema.yml b/bootstrapvz/plugins/puppet/manifest-schema.yml
index 3e4ff76..26f88fd 100644
--- a/bootstrapvz/plugins/puppet/manifest-schema.yml
+++ b/bootstrapvz/plugins/puppet/manifest-schema.yml
@@ -12,6 +12,19 @@ properties:
assets: {$ref: '#/definitions/absolute_path'}
enable_agent: {type: boolean}
manifest: {$ref: '#/definitions/absolute_path'}
+ install_modules:
+ type: array
+ minItems: 1
+ items:
+ type: array
+ items:
+ name:
+ anyOf:
+ - pattern: ^[^/]+(/[^/]+)?$
+ version:
+ type: number
+ required: [name]
+ minItems: 1
minProperties: 1
additionalProperties: false
definitions:
diff --git a/bootstrapvz/plugins/puppet/tasks.py b/bootstrapvz/plugins/puppet/tasks.py
index cd12973..96144d6 100644
--- a/bootstrapvz/plugins/puppet/tasks.py
+++ b/bootstrapvz/plugins/puppet/tasks.py
@@ -1,12 +1,32 @@
+import os
from bootstrapvz.base import Task
from bootstrapvz.common import phases
-from bootstrapvz.common.tools import sed_i
-import os
+from bootstrapvz.common.exceptions import TaskError
+from bootstrapvz.common.releases import jessie, wheezy
+from bootstrapvz.common.tools import sed_i, log_check_call, rel_path
+from __builtin__ import str
+
+
+ASSETS_DIR_JESSIE = rel_path(__file__, 'assets/gpg-keyrings-PC1/jessie')
+ASSETS_DIR_WHEEZY = rel_path(__file__, 'assets/gpg-keyrings-PC1/wheezy')
+
+
+class CheckRequestedDebianRelease(Task):
+ description = 'Checking whether there is a release available for {info.manifest.release}'
+ phase = phases.validation
+
+ @classmethod
+ def run(cls, info):
+ from bootstrapvz.common.exceptions import TaskError
+ if not info.manifest.release == (jessie or wheezy):
+ msg = 'Debian {info.manifest.release} is not (yet) available in the Puppetlabs.com APT repository.'
+ raise TaskError(msg)
class CheckAssetsPath(Task):
description = 'Checking whether the assets path exist'
phase = phases.validation
+ predecessors = [CheckRequestedDebianRelease]
@classmethod
def run(cls, info):
@@ -21,12 +41,12 @@ class CheckAssetsPath(Task):
class CheckManifestPath(Task):
- description = 'Checking whether the manifest path exist'
+ description = 'Checking whether the manifest file path exist inside the assets'
phase = phases.validation
+ predecessors = [CheckAssetsPath]
@classmethod
def run(cls, info):
- from bootstrapvz.common.exceptions import TaskError
manifest = info.manifest.plugins['puppet']['manifest']
if not os.path.exists(manifest):
msg = 'The manifest file {manifest} does not exist.'.format(manifest=manifest)
@@ -36,28 +56,77 @@ class CheckManifestPath(Task):
raise TaskError(msg)
-class AddPackages(Task):
- description = 'Add puppet package'
+class InstallPuppetlabsPC1ReleaseKey(Task):
+ description = 'Install puppetlabs PC1 Release key into the keyring'
+ phase = phases.package_installation
+
+ @classmethod
+ def run(cls, info):
+ from shutil import copy
+ if (info.manifest.release == jessie):
+ key_path = os.path.join(ASSETS_DIR_JESSIE, 'puppetlabs-pc1-keyring.gpg')
+ if (info.manifest.release == wheezy):
+ key_path = os.path.join(ASSETS_DIR_WHEEZY, 'puppetlabs-pc1-keyring.gpg')
+ destination = os.path.join(info.root, 'etc/apt/trusted.gpg.d/puppetlabs-pc1-keyring.gpg')
+ copy(key_path, destination)
+
+
+class AddPuppetlabsPC1SourcesList(Task):
+ description = 'Adding Puppetlabs APT repo to the list of sources.'
phase = phases.preparation
@classmethod
def run(cls, info):
- info.packages.add('puppet')
+ if (info.manifest.release == jessie):
+ info.source_lists.add('puppetlabs', 'deb http://apt.puppetlabs.com jessie PC1')
+ if (info.manifest.release == wheezy):
+ info.source_lists.add('puppetlabs', 'deb http://apt.puppetlabs.com wheezy PC1')
-class CopyPuppetAssets(Task):
- description = 'Copying puppet assets'
+class InstallPuppetAgent(Task):
+ description = 'Install puppet-agent from https://apt.puppetlabs.com for {system.release}'
phase = phases.system_modification
+ @classmethod
+ def run(cls, info):
+ log_check_call(['chroot', info.root, 'apt-get', 'install', '--assume-yes', 'puppet-agent'])
+
+
+class InstallModules(Task):
+ description = 'Installing Puppet modules'
+ phase = phases.system_modification
+ predecessors = [InstallPuppetAgent]
+
+ @classmethod
+ def run(cls, info):
+ for module in info.manifest.plugins['puppet']['install_modules']:
+ command = ['chroot', info.root, '/opt/puppetlabs/bin/puppet', 'module', 'install', '--force']
+ if (len(module) == 1):
+ [module_name] = module
+ command.append(str(module_name))
+ if (len(module) == 2):
+ [module_name, module_version] = module
+ command.append(str(module_name))
+ command.append('--version')
+ command.append(str(module_version))
+ log_check_call(command)
+
+
+class CopyPuppetAssets(Task):
+ description = 'Copying declared custom puppet assets.'
+ phase = phases.system_modification
+ predecessors = [InstallModules]
+
@classmethod
def run(cls, info):
from bootstrapvz.common.tools import copy_tree
- copy_tree(info.manifest.plugins['puppet']['assets'], os.path.join(info.root, 'etc/puppet'))
+ copy_tree(info.manifest.plugins['puppet']['assets'], os.path.join(info.root, 'etc/puppetlabs/'))
class ApplyPuppetManifest(Task):
- description = 'Applying puppet manifest'
- phase = phases.user_modification
+ description = 'Applying puppet manifest.'
+ phase = phases.system_modification
+ predecessors = [CopyPuppetAssets]
@classmethod
def run(cls, info):
@@ -65,19 +134,14 @@ class ApplyPuppetManifest(Task):
hostname = handle.read().strip()
with open(os.path.join(info.root, 'etc/hosts'), 'a') as handle:
handle.write('127.0.0.1\t{hostname}\n'.format(hostname=hostname))
-
from shutil import copy
pp_manifest = info.manifest.plugins['puppet']['manifest']
manifest_rel_dst = os.path.join('tmp', os.path.basename(pp_manifest))
manifest_dst = os.path.join(info.root, manifest_rel_dst)
copy(pp_manifest, manifest_dst)
-
manifest_path = os.path.join('/', manifest_rel_dst)
- from bootstrapvz.common.tools import log_check_call
- log_check_call(['chroot', info.root,
- 'puppet', 'apply', manifest_path])
+ log_check_call(['chroot', info.root, 'puppet', 'apply', '--verbose', '--debug', manifest_path])
os.remove(manifest_dst)
-
hosts_path = os.path.join(info.root, 'etc/hosts')
sed_i(hosts_path, '127.0.0.1\s*{hostname}\n?'.format(hostname=hostname), '')
diff --git a/manifests/examples/kvm/jessie-puppet.yaml b/manifests/examples/kvm/jessie-puppet.yaml
new file mode 100644
index 0000000..1757570
--- /dev/null
+++ b/manifests/examples/kvm/jessie-puppet.yaml
@@ -0,0 +1,45 @@
+---
+name: debian-{system.release}-{system.architecture}-{%Y}{%m}{%d}
+provider:
+ name: kvm
+ virtio_modules:
+ - virtio_pci
+ - virtio_blk
+bootstrapper:
+ workspace: /target
+system:
+ release: jessie
+ architecture: amd64
+ bootloader: grub
+ charmap: UTF-8
+ locale: en_US
+ timezone: UTC
+volume:
+ backing: raw
+ partitions:
+ type: msdos
+ root:
+ filesystem: ext4
+ size: 10GiB
+packages:
+ install_standard: true
+ mirror: http://httpredir.debian.org/debian
+ install:
+ # required to be pre-installed for proper puppet functioning of
+ # puppetlabs-apt, it is also the primary puppet module
+ - lsb-release
+plugins:
+ # It is advisable to avoid running things as root, use a sudo account instead
+ admin_user:
+ username: administrator
+ password: something
+ # puppet plugin
+ puppet:
+ # The assets path MUST be ABSOLUTE on your project.
+ assets: /your/absolute/path/to/etc/puppetlabs
+ install_modules:
+ - [puppetlabs-accounts]
+ - [puppetlabs-apt]
+ - [puppetlabs-concat, 3.0.0]
+ - [puppetlabs-stdlib]
+ - [puppetlabs-apache, 1.11.0]
\ No newline at end of file