diff --git a/Gemfile b/Gemfile index 1b34f08..d68e2e5 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,9 @@ -source "http://rubygems.org" +source "https://rubygems.org" -gem "boxen", "~> 0.7" +gem "boxen", "0.7.3" group :development do gem "aws-sdk" + gem "net-ssh" + gem "rbvmomi" end diff --git a/Gemfile.lock b/Gemfile.lock index 4ad4f3e..c78be2d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,5 +1,5 @@ GEM - remote: http://rubygems.org/ + remote: https://rubygems.org/ specs: addressable (2.3.2) ansi (1.4.3) @@ -7,7 +7,7 @@ GEM json (~> 1.4) nokogiri (>= 1.4.4) uuidtools (~> 2.1) - boxen (0.7.1) + boxen (0.7.3) ansi (~> 1.4) hiera (~> 1.0.0) highline (~> 1.6) @@ -15,6 +15,7 @@ GEM librarian-puppet (~> 0.9) octokit (~> 1.15) puppet (~> 3.0) + builder (3.1.4) facter (1.6.17) faraday (0.8.5) multipart-post (~> 1.1) @@ -24,16 +25,17 @@ GEM hiera (1.0.0) highline (1.6.15) json (1.7.6) - json_pure (1.7.6) + json_pure (1.7.7) librarian-puppet (0.9.7) json puppet thor (~> 0.15) - multi_json (1.5.0) + multi_json (1.6.0) multipart-post (1.1.5) + net-ssh (2.6.5) netrc (0.7.7) nokogiri (1.5.6) - octokit (1.22.0) + octokit (1.23.0) addressable (~> 2.2) faraday (~> 0.8) faraday_middleware (~> 0.9) @@ -43,7 +45,12 @@ GEM puppet (3.1.0) facter (~> 1.6) hiera (~> 1.0) + rbvmomi (1.6.0) + builder + nokogiri (>= 1.4.1) + trollop thor (0.17.0) + trollop (2.0) uuidtools (2.1.3) PLATFORMS @@ -51,4 +58,6 @@ PLATFORMS DEPENDENCIES aws-sdk - boxen (~> 0.7) + boxen (= 0.7.3) + net-ssh + rbvmomi diff --git a/Puppetfile b/Puppetfile index 5c4f7de..a286c9c 100644 --- a/Puppetfile +++ b/Puppetfile @@ -1,3 +1,5 @@ +# This file manages Puppet module dependencies. +# # It works a lot like Bundler. We provide some core modules by # default. This ensures at least the ability to construct a basic # environment. @@ -28,7 +30,7 @@ github "inifile", "0.9.0", :repo => "cprice-puppet/puppetlabs-inifile" github "nginx", "0.2.1" github "nodejs", "0.0.2" github "nvm", "0.0.5" -github "ruby", "0.5.1" +github "ruby", "0.7.1" github "stdlib", "3.0.0", :repo => "puppetlabs/puppetlabs-stdlib" github "sudo", "0.0.1" diff --git a/Puppetfile.lock b/Puppetfile.lock index 8703d8c..dafe506 100644 --- a/Puppetfile.lock +++ b/Puppetfile.lock @@ -46,7 +46,7 @@ GITHUBTARBALL GITHUBTARBALL remote: boxen/puppet-ruby specs: - ruby (0.5.1) + ruby (0.7.1) GITHUBTARBALL remote: boxen/puppet-sudo @@ -74,7 +74,7 @@ DEPENDENCIES nginx (= 0.2.1) nodejs (= 0.0.2) nvm (= 0.0.5) - ruby (= 0.5.1) + ruby (= 0.7.1) stdlib (= 3.0.0) sudo (= 0.0.1) diff --git a/docs/personal-configuration.md b/docs/personal-configuration.md index 61ebe1c..a7a05f7 100644 --- a/docs/personal-configuration.md +++ b/docs/personal-configuration.md @@ -7,9 +7,12 @@ per-user configurations. How? The personal manifest. +## What even is a personal manifest? + Personal manifests live in `modules/people/manifests/.pp`, where `` is your GitHub username. -A basic personal manifest might look like so: + +The simplest personal manifest looks like this: ``` puppet class people::wfarr { @@ -17,19 +20,46 @@ class people::wfarr { } ``` -Now, each time `wfarr` runs Boxen it'll automatically print out "hello world" -somewhere during the run. -You can even run `boxen-my-config` to generate a default template for you -and open it up in your editor. -When you're done, you can simply run `boxen` and it'll include your changes -in your personal manifest. -**You should always keep your manifest committed and pushed to your repository**. -Otherwise, auto-updates won't work! +Ah, the good old "Hello World". +It's boring, but you can see there's really not much boilerplate involved. +Let's try something *real* this time: -The whole point of these personal manifest are they are _your_ manifest. -You shouldn't worry if the things in here are work-related or not. -This is about full automation. -Want to install Minecraft and Rdio by default? -Do it in your personal manifest. +``` puppet +class people::wfarr { + include boxen::development +} +``` -You can check out the [projects README](../modules/projects/README.md) for further examples. +So what does this do? +It clones every repo in the Boxen org to `~/src/boxen/`. +How? +Well, we can refer to [the source code](https://github.com/boxen/puppet-boxen/blob/master/manifests/development.pp)! +If you're new to Puppet, or are unsure of what that class is doing, check out +the [intro to puppet](./puppet.md) we've put together. + +## Running different code on multiple machines + +Puppet has conditionals and switching. +Typically, the most reliable way to ensure some code runs on one machine but not +others is to use the `case` statement on the `hostname` fact. +Example: + +``` puppet +case $::hostname { + 'scruffy': { + notify { "I'm Scruffy. The Janitor.": } + } + + 'bender': { + notify { "My full name is Bender Bending Rodriguez": } + } + + default: { + notify { "Wha?": } + } +} +``` + +One thing to note here is that Puppet always **requires** a default path +on a case statement. +Default is equivalent to "anything that isn't matched above". diff --git a/docs/puppet.md b/docs/puppet.md new file mode 100644 index 0000000..b8f2e31 --- /dev/null +++ b/docs/puppet.md @@ -0,0 +1,144 @@ +# wtf is a puppet? + +Puppet is configuration management tool, written in Ruby, that compiles +and runs code written in the Puppet language. + +But what does that actually mean in words a human can understand? +Puppet is a tool that runs some code and that code can do all sorts of +really powerful things to configure computers for you. + +Why do I want code mucking about with my laptop though? +For the exact same reasons you want code configuring your server. +In particular, homogeneity, reproducibility, reusability, and automation. +When you use code to express how a machine should be configured, +you know that all of your machines are configured the same way, +that you can repeat that configuration any number of times, +and that you don't have to do it manually each time. + +## How does Puppet work? + +A Puppet run has two main steps: compilation and application. + +The compilations step starts with reading in what's called the site manifest. +The site manifest is a single file that contains Puppet code that is responsible +for telling the compiler what other Puppet code it should compile. + +Here are the first few lines of the default site manifest for Boxen: + +``` +include boxen::environment +include homebrew +include gcc +``` + +This tells the Puppet compiler that it must include the classes +`boxen::environment`, `homebrew`, and `gcc`. +Puppet will look for those classes on the modulepath. +Typically, these files would be located at +`$modulepath/boxen/manifests/environment.pp` and +`$modulepath/homebrew/manifests/init.pp`. + +These might include other classes as well, or define **resources**. +Resources are the building blocks of Puppet. +A resource is an abstract description about a **thing** and the **state** +that thing should be in. +Every resource has a **type**, which is just a classification of resources. +For example, we might have a resource `Package[mysql]` and its type would be +`Package`. +Puppet also supports multiple providers for types which act as pluggable +backends depending on the operating system it's running on or the tools +available on a particular system (in the case of the `Package` type, +we might have providers for `yum` and for `aptget`). + +So now the Puppet compiler has finished tracking down and loading all the +classes and resources it needs. +Assuming we haven't encountered any compile-time errors, Puppet then begins +the next phase of a run: applying the catalog. + +All of the resources Puppet has collected into the catalog have formed a +DAG (directed, acyclic graph) that represents the order in which all these +resources can be applied in a correct order. +Puppet simply grabs the first "node" in this graph and traverses all nodes +in the graph, applying each resource as it goes. + +Application of an individual resource starts with Puppet asking "is this +resource in the state requested?" If the answer is yes, Puppet moves onto the +next node and repeats this process. If the answer is no, Puppet will make +whatever changes it can to reconcile the current state of the resource with +what it should be, and then continues on. + +Once all resources have been applied, the Puppet run is complete. + +## Declarative by nature + +One of the most confusing parts of the Puppet language to many newcomers is +how the Puppet catalog orders and applies resources. +The key thing to remember is that Puppet is a **declarative** language rather +than a procedural one. +In human words, the only order that matters in Puppet is order specified by +relationships between resources. + +Here's an example of how someone new to Puppet might write a class: + +``` puppet +class mysql { + file { '/etc/my.cnf': source => 'puppet:///modules/mysql/my.cnf.erb' ; } + package { 'mysql': } + service { 'mysql': } +} +``` + +Someone expecting Puppet to be procedural would read this manifest as a list +saying: + +* First create the my.cnf file +* Then install the mysql package +* Then start the mysql service + +The problem is, they would be **wrong**. +There is no guarantee Puppet will apply these resources in that order, +and it's quite likely that it won't. + +The proper way to ensure ordering in Puppet is to use one of the four +**relationship metaparameters**: + +* before - Run this resource before another resource +* notify - Same as before, but triggers a refresh on that resource +* require - Run this resource after another resource +* subscribe - Same as require, but triggers a refresh on that resource + +The behavior of these metaparameters should be pretty clear. +Triggering a resource simply means that a resource will "refresh" itself. +That typically means something like a `Service` resource restarting itself. +It's important to remember that these metaparameters are valid on **any** resource. + +So, let's rewrite our example properly: + +``` puppet +class mysql { + file { '/etc/my.cnf': + source => 'puppet:///modules/mysql/my.cnf.erb', + notify => Service['mysql'] + } + + package { 'mysql': + notify => Service['mysql'] + } + + service { 'mysql': } +} +``` + +Now we're telling Puppet what order to apply these resources in: + +* Make sure /etc/my.cnf is in place before we start the mysql service +* If /etc/my.cnf changes, tell mysql to restart +* Make sure the mysql package is in place before we start the mysql service +* If the mysql package changes, tell mysql to restart + +It's important to note that we didn't tell Puppet if `File[/etc/my.cnf]` +should come before or after `Package[mysql]`. +This is intentional. +Most package managers won't overwrite a configuration file that already exists +at package install-time, so in this case, we can assume installing the mysql +package won't clobber our custom `/etc/my.cnf` file. diff --git a/docs/rails.md b/docs/rails.md index 35cd487..79f69ab 100644 --- a/docs/rails.md +++ b/docs/rails.md @@ -18,11 +18,11 @@ class projects::rails_app { include phantomjs boxen::project { 'rails_app': - source => 'mycompany/rails_app', ruby => '1.9.3', mysql => true, redis => true, nginx => true, + source => 'username/rails_app' } } ``` diff --git a/manifests/site.pp b/manifests/site.pp index cb3e9ea..40b7d69 100644 --- a/manifests/site.pp +++ b/manifests/site.pp @@ -1,5 +1,6 @@ require boxen::environment -require homebrew::repo +require homebrew +require gcc Exec { group => 'staff', @@ -8,6 +9,8 @@ Exec { path => [ "${boxen::config::home}/rbenv/shims", + "${boxen::config::hime}/rbenv/bin", + "${boxen::config::hime}/rbenv/plugins/ruby-build/bin", "${boxen::config::home}/homebrew/bin", '/usr/bin', '/bin', @@ -16,7 +19,7 @@ Exec { ], environment => [ - "HOMEBREW_CACHE=${homebrew::cachedir}", + "HOMEBREW_CACHE=${homebrew::config::cachedir}", "HOME=/Users/${::luser}" ] } @@ -43,6 +46,8 @@ Service { provider => ghlaunchd } +Homebrew::Formula <| |> -> Package <| |> + node default { # core modules, needed for most things include dnsmasq diff --git a/script/bootstrap b/script/bootstrap index 6fac744..b8760f6 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -13,10 +13,7 @@ set -e rm -rf .bundle/config rm -rf .librarian/puppet/config -# Export CC to explicitly set the compiler used for cexts. - -export CC=gcc - # Bundle install unless we're already up to date. +export PATH=$(pwd)/vendor/shims:$PATH bundle install --binstubs bin --path .bundle --quiet "$@" diff --git a/script/boxen-my-config b/script/boxen-my-config index 3975d9e..66050b4 100755 --- a/script/boxen-my-config +++ b/script/boxen-my-config @@ -19,6 +19,6 @@ unless File.exist? path end end -exec(editor, path) if editor && system("tty -s") +exec(editor, path) if editor && system("test -t 1") puts path diff --git a/script/nuke b/script/nuke index d1ca2a5..4a06979 100755 --- a/script/nuke +++ b/script/nuke @@ -14,11 +14,13 @@ services = false OptionParser.new do |o| o.banner = "Remove most traces of Boxen from your machine." - o.on("--all", "Remove everything possible.") { all = true } - o.on("--force", "Actually do it.") { force = true } - o.on("--help", "Show this help.") { abort o.to_s } - o.on("--opt", "Remove /opt/boxen.") { opt = true } - o.on("--services", "Remove and unload services.") { services = true } + o.on("--all", "Remove everything possible.") { all = true } + o.on("--force", "Actually do it.") { force = true } + o.on("--help", "Show this help.") { abort o.to_s } + o.on("--opt", "Remove /opt/boxen.") { opt = true } + o.on("--services", "Remove and unload services.") { services = true } + o.on("--receipts", "Remove package receipts used by Puppet.") { receipts = true } + o.on("--gitconfig", "Remove Boxen-provided git credential helper config.") { gitconfig = true } o.parse! @@ -31,7 +33,7 @@ end if all || services boxen_services = [] - boxen_services << Dir["/Library/Launch*/com.boxen.*.plist"] + boxen_services << Dir["/Library/Launch*/dev.*.plist"] boxen_services.flatten.each do |plist| warn "-> Removing #{plist}." @@ -49,3 +51,13 @@ if all || opt warn "-> Removing /opt/boxen." system "rm", "-rf", "/opt/boxen" if force end + +if all || receipts + warn "-> Removing /var/db/.puppet_*." + system "rm", "-rf", "/var/db/.puppet_*" if force +end + +if all || gitconfig + warn "-> Removing git credential helper config." + system "/usr/bin/git", "config", "--global", "--unset", "credential.helper" +end diff --git a/vendor/cache/boxen-0.7.1.gem b/vendor/cache/boxen-0.7.1.gem deleted file mode 100644 index 9a7f6c0..0000000 Binary files a/vendor/cache/boxen-0.7.1.gem and /dev/null differ diff --git a/vendor/cache/boxen-0.7.3.gem b/vendor/cache/boxen-0.7.3.gem new file mode 100644 index 0000000..7c61115 Binary files /dev/null and b/vendor/cache/boxen-0.7.3.gem differ diff --git a/vendor/cache/builder-3.1.4.gem b/vendor/cache/builder-3.1.4.gem new file mode 100644 index 0000000..b6090be Binary files /dev/null and b/vendor/cache/builder-3.1.4.gem differ diff --git a/vendor/cache/json_pure-1.7.6.gem b/vendor/cache/json_pure-1.7.6.gem deleted file mode 100644 index b9bbd6c..0000000 Binary files a/vendor/cache/json_pure-1.7.6.gem and /dev/null differ diff --git a/vendor/cache/json_pure-1.7.7.gem b/vendor/cache/json_pure-1.7.7.gem new file mode 100644 index 0000000..b7d8d11 Binary files /dev/null and b/vendor/cache/json_pure-1.7.7.gem differ diff --git a/vendor/cache/multi_json-1.5.0.gem b/vendor/cache/multi_json-1.5.0.gem deleted file mode 100644 index adaa5f3..0000000 Binary files a/vendor/cache/multi_json-1.5.0.gem and /dev/null differ diff --git a/vendor/cache/multi_json-1.6.0.gem b/vendor/cache/multi_json-1.6.0.gem new file mode 100644 index 0000000..4716204 Binary files /dev/null and b/vendor/cache/multi_json-1.6.0.gem differ diff --git a/vendor/cache/net-ssh-2.6.5.gem b/vendor/cache/net-ssh-2.6.5.gem new file mode 100644 index 0000000..bba429d Binary files /dev/null and b/vendor/cache/net-ssh-2.6.5.gem differ diff --git a/vendor/cache/octokit-1.22.0.gem b/vendor/cache/octokit-1.22.0.gem deleted file mode 100644 index 362595a..0000000 Binary files a/vendor/cache/octokit-1.22.0.gem and /dev/null differ diff --git a/vendor/cache/octokit-1.23.0.gem b/vendor/cache/octokit-1.23.0.gem new file mode 100644 index 0000000..f5bff1a Binary files /dev/null and b/vendor/cache/octokit-1.23.0.gem differ diff --git a/vendor/cache/rbvmomi-1.6.0.gem b/vendor/cache/rbvmomi-1.6.0.gem new file mode 100644 index 0000000..e2f5ddd Binary files /dev/null and b/vendor/cache/rbvmomi-1.6.0.gem differ diff --git a/vendor/cache/trollop-2.0.gem b/vendor/cache/trollop-2.0.gem new file mode 100644 index 0000000..40f0c9f Binary files /dev/null and b/vendor/cache/trollop-2.0.gem differ diff --git a/vendor/puppet/cache/boxen-puppet-ruby-0.5.1.tar.gz b/vendor/puppet/cache/boxen-puppet-ruby-0.5.1.tar.gz deleted file mode 100644 index c2b2f54..0000000 Binary files a/vendor/puppet/cache/boxen-puppet-ruby-0.5.1.tar.gz and /dev/null differ diff --git a/vendor/puppet/cache/boxen-puppet-ruby-0.7.1.tar.gz b/vendor/puppet/cache/boxen-puppet-ruby-0.7.1.tar.gz new file mode 100644 index 0000000..c9f157c Binary files /dev/null and b/vendor/puppet/cache/boxen-puppet-ruby-0.7.1.tar.gz differ diff --git a/vendor/shims/xcrun b/vendor/shims/xcrun new file mode 100755 index 0000000..da58e73 --- /dev/null +++ b/vendor/shims/xcrun @@ -0,0 +1,4 @@ +#!/bin/sh +# A noop xcrun for initial Boxen runs. + +exec "$@"