Opskelaton is an opinionated bootstrap tool for local Sandbox projects, it aims to solve the following common issues:

  • Developing Puppet/Chef modules/cookbooks on master machines which results with 'It works on my master/server' approach.

  • Large monolithic Puppet/Chef code bases, code isn’t modular or reusable.

  • Implicit/Missing dependencies including: Ruby version, OS, gems, modules/cookbooks.

  • Manual steps in setting up and maintaining such projects.

  • Non standard layout, projects missing README and LICENSE files, no clear separation between developed and dependant code.

  • Lacking development guidelines (for example extracting general modules and exporting them).

  • No continues build, linting and testing, provisioning code is second class citizen.

Opskeleton comes to solve these issues by introducing a decentralized development work flow with pre-defined layout, packaging and dependency management.

Currently Opskeleton supports Puppet and Chef, this guide is segmented to common functionality the respective separate sections for Puppet and Chef.



Perquisites (on Ubuntu):

  • Vagrant 1.8.x

  • RVM

  • Ruby >= 2.1.2

 $ rvm use system
 $ sudo gem install opskeleton


Both zsh and bash are supported just copy the macthing file from the project autocomplete folder.

$ opsk help
 Describe available commands or one spe...
 bumps up version (clearing old version...
 cleans up packaging products
 deploy packge into
 deploy packge into s3 bucket under pat...
 deploy packge using scp to host
 generate an rspec ready Puppet module
 generates a Chef based project
 generates a Puppet based project
 packages current module for celestial
 print opsk version


Opskeleton recommends the use of box-cutter in order to create Vagrant boxes in a consistent manner (as no free hosting solution currently exist):

# make sure to have latest packer
$ packer version
Packer v0.6.0
$ git clone git://
$ cd ubuntu-vm
# Edit Makefile.local
$ cat Makefile.local
# Makefile.local
CM := puppet
CM_VERSION := 3.6.1
$ make virtualbox/ubuntu1604

A useful convention for Box names:

ubuntu-{ubuntuversion}_puppet-3.6.1 ([os]-[version]_[provisioner]-[version])



Opskeleton supports the creation of Puppet based projects supporting dependency management (using librarian-puppet), linting and testing.



Opskeleton generates the complete folder structure for projects:



Opskelaton defines a module life cycle:

  1. Internal non reusable modules (usually specific to a client site) go under static-modules

  2. If we create a general reusable module which is ready for prime time we pull out to a new git repository.

  3. The extracted module is added (using librarian-puppet) back as a third party module under modules folder.

Life cycle scheme:


Creating new (static) modules is easy as:

$ opsk module foo

Each generated module will contain puppet-rspec with matching Rakefile.

Pushing changes

Making changes to third party modules is quite easy once librarian-puppet installed them locally (you can push only git based modules):

forge ""

mod 'puppetlabs/stdlib'
mod 'puppetlabs/apt'

mod 'strings/artifactory',
   :git => 'git://'

mod 'rip/module-data',
  :git => 'git://'

Its best practice to use git protocol (read only) which makes pushing changes from multiple modules a bit tedious, Opskeleton fixes that:

We can list the changes:

$ opsk uncommited
Listing changes for modules/artifactory:

changed files:

- metadata.json

added files:

untracked files:

We can commit them (providing a commit message per module or --message for all):

# We hacked a number of submodules, now we commit
$ opsk commit
Listing changes for modules/artifactory:

changed files:

- metadata.json

added files:

untracked files:

Commit the changes under modules/artifactory? (y/n) y
Commit message:
This is a nice change

For more commit options:

$ opsk help commit

  opsk commit [message]

  [--message=MESSAGE]  # optional commit message
  [--all], [--no-all]  # commit all

commit each changed puppet module under modules folder

Once commits are made we can push the changes:

$ opsk push
Push modules/artifactory? (y/n) y
pushing modules/artifactory ..

Opsk will add a remote writable repository for each submodule substituting the readonly protocol with a write enabled one, the default protocol is ssh (customizable by using --protocol).

For more options:

$ opsk help push

  opsk push

  [--protocol=PROTOCOL]  # remote ssh protocol (https or ssh)
                         # Default: ssh
  [--dry], [--no-dry]    # dry mode
  [--all], [--no-all]    # push all without asking

push each changed puppet module under modules folder


Opskelaton supports two levels of testing:

  • Static module testing that includes rspec and linting.

  • Integration testing using serverspecand Vagrant.

# linting all static modules
$ rake lint
# rspecing
$ rake modspec
# running serverspec
$ rake spec


Opskelaton fully supports deployment and portable execution of sandboxes on non Vagrant environments:

$ opsk generate_puppet foo ubuntu-13.10
$ cd foo-sandbox
# The package version file
$ cat opsk.yaml
  version: '0.0.1'
  name: foo

# post bundle and gem install ..
$ opsk package
      create  pkg/foo-sandbox-0.0.1
      create  pkg/foo-sandbox-0.0.1/scripts
      create  pkg/foo-sandbox-0.0.1/scripts/lookup.rb
       chmod  pkg/foo-sandbox-0.0.1/scripts/lookup.rb
      create  pkg/foo-sandbox-0.0.1/scripts/
       chmod  pkg/foo-sandbox-0.0.1/scripts/
      create  pkg/foo-sandbox-0.0.1/manifests/site.pp
       exist  pkg
$ ls pkg
foo-sandbox-0.0.1  foo-sandbox-0.0.1.tar.gz

The packaging process creates a portable tar file that can be run on any machine with puppet installed via the bundled

$ tar -xvzf foo-sandbox-0.0.1.tar.gz
$ cd foo-sandbox-0.0.1
$ sudo ./

An external node classifier based runner is also available under scripts/, this runner expects to get a <hostname>.yaml input file with the required node classes.


Keeping you box up to date with latest opsk version is easy, just re-generate it again and resolve conflicts by answering y/n:

# Moving to latest opsk
$ gem update opskeleton
# foo box already exists
$ opsk generate foo <vagrant-box>
 exist  foo-sandbox
    conflict  foo-sandbox/Vagrantfile
Overwrite /home/ronen/code/foo-sandbox/Vagrantfile? (enter "h" for help) [Ynaqdh]


Opskeleton generates a Vagrant file with couple of enhancements:

  • VAGRANT_BRIDGE (default eth0) for setting up public bridge on the go.

  • PUPPET_ENV (default dev) for setting puppet environment.

  • Puppet options preset to match modules and hiera folders.


Tracking the speed of our provisioning code is important for keeping a consistent level of service with the produced sandboxes, enabling benchmarking:

$ opsk generate_puppet redis ubuntu-16.04 --bench-enable
# install imagemagic before bundle install
$ sudo apt-get install imagemagick libmagickwand-dev
$ rake serverspec:redis
# with each run more result lines will be recorded
$ cat benchmark.json
{"total":656,"host":"redis","revision":"5d03a41ade9fc3dd5296d4119ccb0b0ad8290b9e","time":"2014-12-17 02:57:45 +0200"}
# add it to git for tracking
$ git add benchmark.json

Now after a number of runs we could plot and view the results of a single host or of all the hosts side by side:

$ rake plot:hosts plot:per_hosts
# resulting png files
$ google-chrome plots


The packaged tar files can be consumed using any tool and protocol (http, s3 etc), opsk has built in support for deploying public sandboxes into:

  • Bintray (make sure to configure the bintray API key):

$ opsk package
$ opsk deploy_bintray <bintray-repo>
   deployed foo-sandbox-0.0.1.tar.gz to<bintray-repo>/foo-sandbox-0.0.1.tar.gz
  • S3 (Make sure to configure s3 section under ~/.configuration.rb):

$ opsk package
$ opsk deploy_s3 <bucket> <path>
   deployed foo-sandbox-0.0.1.tar.gz to opsk-boxes/foo/foo-sandbox-0.0.1.tar.gz
Configuration.for('s3') {
  access_key ''
  secret_key ''
  region ''
  • Scp (Make sure to configure scp section under ~/.configuration.rb):

$ opsk package
$ opsk deploy_scp bar
   deployed foo-sandbox-0.0.1.tar.gz to foo@opsk-boxes:/var/boxes
Configuration.for('scp') {
  bar {
   host 'opsk-boxes'
   user 'foo'
   dest '/var/boxes'
   # optional
   port 2222