(puppetlabs/puppet) New pull request: fix missing -r flag in useradd.rb

933 views
Skip to first unread message

weareth...@puppetlabs.com

unread,
Jan 9, 2012, 1:45:08 AM1/9/12
to puppe...@googlegroups.com

Please review pull request #314: fix missing -r flag in useradd.rb opened by (nauwelaerts)

Description:

http://projects.puppetlabs.com/issues/10354

  • Opened: Mon Jan 09 06:45:28 UTC 2012
  • Based on: puppetlabs:2.7rc (87f6f0546f25faf4fa3d370357c4e5bf70d49fde)
  • Requested merge: nauwelaerts:master (4093f843e9c325e65b62126aa2eae1ce00e7f61a)

Diff follows:

diff --git a/CHANGELOG b/CHANGELOG
index 48c3090..2ca77ae 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1371,6 +1371,38 @@ d532e6d Fixing #3185 Rakefile is loading puppet.rb twice
 5aa596c Fix #3150 - require function doesn't like ::class syntax
 3457b87 Added time module to tagmail report
 
+2.6.13
+===
+e4ee794 (#10739) Provide default subjectAltNames while bootstrapping master
+9dfd011 (#5617)  Puppet queue logging
+a91cfa1 maint: Fix failing spec on old version of rspec
+aa2a762 (#10289) Add an ext script to upload facts to inventory server
+5129d38 (#10289) Add a safe alternative to REST for inventory service
+7514d32 missing includes in network XML-RPC handlers
+397a506 (#10244) Restore Mongrel XMLRPC functionality
+e7a6995 (#9794) k5login can overwrite arbitrary files as root
+0a92a70 Resist directory traversal attacks through indirections.
+8d86e5a (9547) Minor mods to acceptance tests
+2bf6721 Reset indirector state after configurer tests.
+bb224dd (#8770) Don't fail to set supplementary groups when changing user to root
+2a0de12 (#8770) Always fully drop privileges when changing user
+00c4b25 (#8662) Migrate suidmanager test case to rspec
+d7c9c76 (#8740) Do not enumerate files in the root directory.
+0e00473 (#3553) Explain that cron resources require time attributes
+769d432 (#8302) Improve documentation of exec providers
+c209f62 Add document outlining preferred contribution methods
+fb2ffd6 (#8596) Detect resource alias conflicts when titles do not match
+89c021c (#8418) Fix inspect app to have the correct run_mode
+3165364 maint: Adding logging to include environment when source fails
+f484851 maint: Add debug logging when the master receives a report
+e639868 Confine password disclosure acceptance test to hosts with required libraries
+a109c90 (maint) Cleanup and strengthen acceptance tests
+b268fb3 (#7144) Update Settings#writesub to convert mode to Fixnum
+4a2f22c (maint) Fix platform dection for RHEL
+111a4b5 (#6857) Password disclosure when changing a user's password
+
+2.6.12 (CVE-2011-3872 see http://puppetlabs.com/security/hotfixes/cve-2011-3872/)
+
 2.6.11
 ===
 e158b26 (#9793) "secure" indirector file backed terminus base class.
diff --git a/README_DEVELOPER.md b/README_DEVELOPER.md
new file mode 100644
index 0000000..7136ad2
--- /dev/null
+++ b/README_DEVELOPER.md
@@ -0,0 +1,63 @@
+# Developer README #
+
+This file is intended to provide a place for developers and contributors to
+document what other developers need to know about changes made to Puppet.
+
+# UTF-8 Handling #
+
+As Ruby 1.9 becomes more commonly used with Puppet, developers should be aware
+of major changes to the way Strings and Regexp objects are handled.
+Specifically, every instance of these two classes will have an encoding
+attribute determined in a number of ways.
+
+ * If the source file has an encoding specified in the magic comment at the
+   top, the instance will take on that encoding.
+ * Otherwise, the encoding will be determined by the LC\_LANG or LANG
+   environment variables.
+ * Otherwise, the encoding will default to ASCII-8BIT
+
+## References ##
+
+Excellent information about the differences between encodings in Ruby 1.8 and
+Ruby 1.9 is published in this blog series:
+[Understanding M17n](http://links.puppetlabs.com/understanding_m17n)
+
+## Encodings of Regexp and String instances ##
+
+In general, please be aware that Ruby 1.9 regular expressions need to be
+compatible with the encoding of a string being used to match them.  If they are
+not compatible you can expect to receive and error such as:
+
+    Encoding::CompatibilityError: incompatible encoding regexp match (ASCII-8BIT
+    regexp with UTF-8 string)
+
+In addition, some escape sequences were valid in Ruby 1.8 are no longer valid
+in 1.9 if the regular expression is not marked as an ASCII-8BIT object.  You
+may expect errors like this in this situation:
+
+    SyntaxError: (irb):7: invalid multibyte escape: /\xFF/
+
+This error is particularly common when serializing a string to other
+representations like JSON or YAML.  To resolve the problem you can explicitly
+mark the regular expression as ASCII-8BIT using the /n flag:
+
+    "a" =~ /\342\230\203/n
+
+Finally, any time you're thinking of a string as an array of bytes rather than
+an array of characters, common when escaping a string, you should work with
+everything in ASCII-8BIT.  Changing the encoding will not change the data
+itself and allow the Regexp and the String to deal with bytes rather than
+characters.
+
+Puppet provides a monkey patch to String which returns an encoding suitable for
+byte manipulations:
+
+    # Example of how to escape non ASCII printable characters for YAML.
+    >> snowman = "☃"
+    >> snowman.to_ascii8bit.gsub(/([\x80-\xFF])/n) { |x| "\\x#{x.unpack("C")[0].to_s(16)} }
+    => "\\xe2\\x98\\x83"
+
+If the Regexp is not marked as ASCII-8BIT using /n, then you can expect the
+SyntaxError, invalid multibyte escape as mentioned above.
+
+EOF
diff --git a/acceptance/tests/resource/file/source_attribtute.rb b/acceptance/tests/resource/file/source_attribtute.rb
deleted file mode 100644
index 3fa447a..0000000
--- a/acceptance/tests/resource/file/source_attribtute.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-test_name "The source attribute"
-
-step "Ensure the test environment is clean"
-on agents, 'rm -f /tmp/source_file_test.txt'
-
-# TODO: Add tests for puppet:// URIs with master/agent setups.
-# step "when using a puppet:/// URI with a master/agent setup"
-# step "when using a puppet://$server/ URI with a master/agent setup"
-
-step "Using a local file path"
-on agents, "echo 'Yay, this is the local file.' > /tmp/local_source_file_test.txt"
-manifest = "file { '/tmp/source_file_test.txt': source => '/tmp/local_source_file_test.txt', ensure => present }"
-
-apply_manifest_on agents, manifest
-agents.each do |host|
-  on host, "cat /tmp/source_file_test.txt" do
-    assert_match(/Yay, this is the local file./, stdout, "FIRST: File contents not matched on #{host}")
-  end
-end
-
-step "Ensure the test environment is clean"
-on agents, 'rm -f /tmp/source_file_test.txt'
-
-step "Using a puppet:/// URI with puppet apply"
-
-on agents, puppet_agent("--configprint modulepath") do
-  modulepath = stdout.split(':')[0]
-  modulepath = modulepath.chomp
-  on agents, "mkdir -p #{modulepath}/test_module/files"
-  #on agents, "echo 'Yay, this is the puppet:/// file.' > #{modulepath}/test_module/files/test_file.txt"
-  on agents, "echo 'Yay, this is the puppetfile.' > #{modulepath}/test_module/files/test_file.txt"
-end
-
-on agents, %q{echo "file { '/tmp/source_file_test.txt': source => 'puppet:///modules/test_module/test_file.txt', ensure => present }" > /tmp/source_test_manifest.pp}
-on agents, puppet_apply("/tmp/source_test_manifest.pp") 
-
-agents.each do |host|
-  on host, "cat /tmp/source_file_test.txt" do
-    assert_match(/Yay, this is the puppetfile./, stdout, "SECOND: File contents not matched on #{host}")
-  end
-end
-
-# Oops. We (Jesse & Jacob) ended up writing this before realizing that you
-# can't actually specify "source => 'http://...'".  However, we're leaving it
-# here, since there have been feature requests to support doing this.
-# -- Mon, 07 Mar 2011 16:12:56 -0800
-#
-#step "Ensure the test environment is clean"
-#on agents, 'rm -f /tmp/source_file_test.txt'
-#
-#step "when using an http:// file path"
-#
-#File.open '/tmp/puppet-acceptance-webrick-script.rb', 'w' do |file|
-#  file.puts %q{#!/usr/bin/env ruby
-#
-#require 'webrick'
-#
-#class Simple < WEBrick::HTTPServlet::AbstractServlet
-#  def do_GET(request, response)
-#    status, content_type, body = do_stuff_with(request)
-#
-#    response.status = status
-#    response['Content-Type'] = content_type
-#    response.body = body
-#  end
-#
-#  def do_stuff_with(request)
-#    return 200, "text/plain", "you got a page"
-#  end
-#end
-#
-#class SimpleTwo < WEBrick::HTTPServlet::AbstractServlet
-#  def do_GET(request, response)
-#    status, content_type, body = do_stuff_with(request)
-#
-#    response.status = status
-#    response['Content-Type'] = content_type
-#    response.body = body
-#  end
-#
-#  def do_stuff_with(request)
-#    return 200, "text/plain", "you got a different page"
-#  end
-#end
-#
-#server = WEBrick::HTTPServer.new :Port => 8081
-#trap "INT"  do server.shutdown end
-#trap "TERM" do server.shutdown end
-#trap "QUIT" do server.shutdown end
-#
-#server.mount "/", SimpleTwo
-#server.mount "/foo.txt", Simple
-#server.start
-#}
-#end
-#
-#scp_to master, '/tmp/puppet-acceptance-webrick-script.rb', '/tmp'
-#on master, "chmod +x /tmp/puppet-acceptance-webrick-script.rb && /tmp/puppet-acceptance-webrick-script.rb &"
-#
-#manifest = "file { '/tmp/source_file_test.txt': source => 'http://#{master}:8081/foo.txt', ensure => present }"
-#
-#apply_manifest_on agents, manifest
-#
-#on agents, 'test "$(cat /tmp/source_file_test.txt)" = "you got a page"'
-#
-#on master, "killall puppet-acceptance-webrick-script.rb"
diff --git a/acceptance/tests/resource/file/source_attribute.rb b/acceptance/tests/resource/file/source_attribute.rb
new file mode 100644
index 0000000..128bd32
--- /dev/null
+++ b/acceptance/tests/resource/file/source_attribute.rb
@@ -0,0 +1,131 @@
+test_name "The source attribute"
+
+step "Ensure the test environment is clean"
+on agents, 'rm -f /tmp/source_file_test.txt'
+
+step "when using a puppet:/// URI with a master/agent setup"
+modulepath = nil
+on master, puppet_master('--configprint modulepath') do
+  modulepath = stdout.split(':')[0].chomp
+end
+
+result_file = "/tmp/#{$$}-result-file"
+source_file = File.join(modulepath, 'source_test_module', 'files', 'source_file')
+manifest = "/tmp/#{$$}-source-test.pp"
+
+# Remove the SSL dir so we don't have cert issues
+on master, "rm -rf `puppet master --configprint ssldir`"
+on agents, "rm -rf `puppet agent --configprint ssldir`"
+
+on master, "mkdir -p #{File.dirname(source_file)}"
+on master, "echo 'the content is present' > #{source_file}"
+on master, %Q[echo "file { '#{result_file}': source => 'puppet:///modules/source_test_module/source_file', ensure => present }" > #{source_file}]
+
+with_master_running_on master, "--autosign true --manifest #{manifest} --dns_alt_names=\"puppet, $(hostname -s), $(hostname -f)\"" do
+  run_agent_on agents, "--test --server #{master}" do
+    on agents, "cat #{result_file}" do
+      assert_match(/the content is present/, stdout, "Result file not created")
+    end
+  end
+end
+
+# TODO: Add tests for puppet:// URIs with multi-master/agent setups.
+# step "when using a puppet://$server/ URI with a master/agent setup"
+
+step "Using a local file path"
+on agents, "echo 'Yay, this is the local file.' > /tmp/local_source_file_test.txt"
+manifest = "file { '/tmp/source_file_test.txt': source => '/tmp/local_source_file_test.txt', ensure => present }"
+
+apply_manifest_on agents, manifest
+agents.each do |host|
+  on host, "cat /tmp/source_file_test.txt" do
+    assert_match(/Yay, this is the local file./, stdout, "FIRST: File contents not matched on #{host}")
+  end
+end
+
+step "Ensure the test environment is clean"
+on agents, 'rm -f /tmp/source_file_test.txt'
+
+step "Using a puppet:/// URI with puppet apply"
+
+on agents, puppet_agent("--configprint modulepath") do
+  modulepath = stdout.split(':')[0]
+  modulepath = modulepath.chomp
+  on agents, "mkdir -p #{modulepath}/test_module/files"
+  #on agents, "echo 'Yay, this is the puppet:/// file.' > #{modulepath}/test_module/files/test_file.txt"
+  on agents, "echo 'Yay, this is the puppetfile.' > #{modulepath}/test_module/files/test_file.txt"
+end
+
+on agents, %q{echo "file { '/tmp/source_file_test.txt': source => 'puppet:///modules/test_module/test_file.txt', ensure => present }" > /tmp/source_test_manifest.pp}
+on agents, puppet_apply("/tmp/source_test_manifest.pp") 
+
+agents.each do |host|
+  on host, "cat /tmp/source_file_test.txt" do
+    assert_match(/Yay, this is the puppetfile./, stdout, "SECOND: File contents not matched on #{host}")
+  end
+end
+
+# Oops. We (Jesse & Jacob) ended up writing this before realizing that you
+# can't actually specify "source => 'http://...'".  However, we're leaving it
+# here, since there have been feature requests to support doing this.
+# -- Mon, 07 Mar 2011 16:12:56 -0800
+#
+#step "Ensure the test environment is clean"
+#on agents, 'rm -f /tmp/source_file_test.txt'
+#
+#step "when using an http:// file path"
+#
+#File.open '/tmp/puppet-acceptance-webrick-script.rb', 'w' do |file|
+#  file.puts %q{#!/usr/bin/env ruby
+#
+#require 'webrick'
+#
+#class Simple < WEBrick::HTTPServlet::AbstractServlet
+#  def do_GET(request, response)
+#    status, content_type, body = do_stuff_with(request)
+#
+#    response.status = status
+#    response['Content-Type'] = content_type
+#    response.body = body
+#  end
+#
+#  def do_stuff_with(request)
+#    return 200, "text/plain", "you got a page"
+#  end
+#end
+#
+#class SimpleTwo < WEBrick::HTTPServlet::AbstractServlet
+#  def do_GET(request, response)
+#    status, content_type, body = do_stuff_with(request)
+#
+#    response.status = status
+#    response['Content-Type'] = content_type
+#    response.body = body
+#  end
+#
+#  def do_stuff_with(request)
+#    return 200, "text/plain", "you got a different page"
+#  end
+#end
+#
+#server = WEBrick::HTTPServer.new :Port => 8081
+#trap "INT"  do server.shutdown end
+#trap "TERM" do server.shutdown end
+#trap "QUIT" do server.shutdown end
+#
+#server.mount "/", SimpleTwo
+#server.mount "/foo.txt", Simple
+#server.start
+#}
+#end
+#
+#scp_to master, '/tmp/puppet-acceptance-webrick-script.rb', '/tmp'
+#on master, "chmod +x /tmp/puppet-acceptance-webrick-script.rb && /tmp/puppet-acceptance-webrick-script.rb &"
+#
+#manifest = "file { '/tmp/source_file_test.txt': source => 'http://#{master}:8081/foo.txt', ensure => present }"
+#
+#apply_manifest_on agents, manifest
+#
+#on agents, 'test "$(cat /tmp/source_file_test.txt)" = "you got a page"'
+#
+#on master, "killall puppet-acceptance-webrick-script.rb"
diff --git a/acceptance/tests/ticket_7139_puppet_resource_file_qualified_paths.rb b/acceptance/tests/ticket_7139_puppet_resource_file_qualified_paths.rb
index f773ba1..e546d4c 100644
--- a/acceptance/tests/ticket_7139_puppet_resource_file_qualified_paths.rb
+++ b/acceptance/tests/ticket_7139_puppet_resource_file_qualified_paths.rb
@@ -5,7 +5,7 @@
 
 step "Run puppet file resource on /tmp/ticket-7139"
 agents.each do |host|
-  on(host, "puppet resource file /tmp/ticket-7139") do
+  on host, puppet("resource file /tmp/ticket-7139") do
     assert_match(/file \{ \'\/tmp\/ticket-7139\':/, stdout, "puppet resource file failed on #{host}")
   end
 end
diff --git a/conf/redhat/puppet.spec b/conf/redhat/puppet.spec
index 8834300..ef5ebc5 100644
--- a/conf/redhat/puppet.spec
+++ b/conf/redhat/puppet.spec
@@ -325,6 +325,12 @@ rm -rf %{buildroot}
 * Wed Jul 06 2011 Michael Stahnke <sta...@puppetlabs.com> - 2.7.2-0.1.rc1
 - Update to 2.7.2rc1
 
+* Mon Dec 12 2011 Matthaus Litteken <matt...@puppetlabs.com> - 2.6.13-1
+- Release of 2.6.13
+
+* Fri Oct 21 2011 Michael Stahnke <sta...@puppetlabs.com> - 2.6.12-1
+- CVE-2011-3872 fixes
+
 * Wed Jun 15 2011 Todd Zullinger <t...@pobox.com> - 2.6.9-0.1.rc1
 - Update rc versioning to ensure 2.6.9 final is newer to rpm
 - sync changes with Fedora/EPEL
diff --git a/ext/puppetstoredconfigclean.rb b/ext/puppetstoredconfigclean.rb
index dcbefa8..7e77239 100644
--- a/ext/puppetstoredconfigclean.rb
+++ b/ext/puppetstoredconfigclean.rb
@@ -8,7 +8,10 @@
 # duritong adapted and improved the script a bit.
 
 require 'getoptlong'
-config = '/etc/puppet/puppet.conf'
+require 'puppet'
+require 'puppet/rails'
+
+config = Puppet[:config]
 
 def printusage(error_code)
   puts "Usage: #{$0} [ list of hostnames as stored in hosts table ]"
@@ -17,14 +20,11 @@ def printusage(error_code)
   exit(error_code)
 end
 
-
-      opts = GetoptLong.new(
-
-    [ "--config",     "-c",   GetoptLong::REQUIRED_ARGUMENT ],
-    [ "--help",        "-h",   GetoptLong::NO_ARGUMENT ],
-    [ "--usage",       "-u",   GetoptLong::NO_ARGUMENT ],
-
-    [ "--version",     "-v",   GetoptLong::NO_ARGUMENT ]
+opts = GetoptLong.new(
+  [ "--config",  "-c", GetoptLong::REQUIRED_ARGUMENT ],
+  [ "--help",    "-h", GetoptLong::NO_ARGUMENT ],
+  [ "--usage",   "-u", GetoptLong::NO_ARGUMENT ],
+  [ "--version", "-v", GetoptLong::NO_ARGUMENT ]
 )
 
 begin
@@ -51,24 +51,35 @@ def printusage(error_code)
 
 printusage(1) unless ARGV.size > 0
 
-require 'puppet/rails'
-Puppet[:config] = config
-Puppet.parse_config
-pm_conf = Puppet.settings.instance_variable_get(:@values)[:master]
+if config != Puppet[:config]
+  Puppet[:config]=config
+  Puppet.settings.parse
+end
 
-adapter = pm_conf[:dbadapter]
-args = {:adapter => adapter, :log_level => pm_conf[:rails_loglevel]}
+master = Puppet.settings.instance_variable_get(:@values)[:master]
+main = Puppet.settings.instance_variable_get(:@values)[:main]
+db_config = main.merge(master)
+
+# get default values
+[:master, :main, :rails].each do |section|
+  Puppet.settings.params(section).each do |key|
+    db_config[key] ||= Puppet[key]
+  end
+end
+
+adapter = db_config[:dbadapter]
+args = {:adapter => adapter, :log_level => db_config[:rails_loglevel]}
 
 case adapter
   when "sqlite3"
-    args[:dbfile] = pm_conf[:dblocation]
-  when "mysql", "postgresql"
-    args[:host]     = pm_conf[:dbserver] unless pm_conf[:dbserver].to_s.empty?
-    args[:username] = pm_conf[:dbuser] unless pm_conf[:dbuser].to_s.empty?
-    args[:password] = pm_conf[:dbpassword] unless pm_conf[:dbpassword].to_s.empty?
-    args[:database] = pm_conf[:dbname] unless pm_conf[:dbname].to_s.empty?
-    args[:port]     = pm_conf[:dbport] unless pm_conf[:dbport].to_s.empty?
-    socket          = pm_conf[:dbsocket]
+    args[:dbfile] = db_config[:dblocation]
+  when "mysql", "mysql2", "postgresql"
+    args[:host]     = db_config[:dbserver] unless db_config[:dbserver].to_s.empty?
+    args[:username] = db_config[:dbuser] unless db_config[:dbuser].to_s.empty?
+    args[:password] = db_config[:dbpassword] unless db_config[:dbpassword].to_s.empty?
+    args[:database] = db_config[:dbname] unless db_config[:dbname].to_s.empty?
+    args[:port]     = db_config[:dbport] unless db_config[:dbport].to_s.empty?
+    socket          = db_config[:dbsocket]
     args[:socket]   = socket unless socket.to_s.empty?
   else
     raise ArgumentError, "Invalid db adapter #{adapter}"
@@ -78,14 +89,15 @@ def printusage(error_code)
 
 ActiveRecord::Base.establish_connection(args)
 
-ARGV.each { |hostname|
+ARGV.each do |hostname|
   if @host = Puppet::Rails::Host.find_by_name(hostname.strip)
-    print "Killing #{hostname}..."
+    print "Removing #{hostname} from storedconfig..."
     $stdout.flush
     @host.destroy
     puts "done."
   else
-    puts "Can't find host #{hostname}."
+    puts "Error: Can't find host #{hostname}."
   end
-}
+end
+
 exit 0
diff --git a/ext/rack/files/apache2.conf b/ext/rack/files/apache2.conf
index 381327c..097e3a0 100644
--- a/ext/rack/files/apache2.conf
+++ b/ext/rack/files/apache2.conf
@@ -26,6 +26,10 @@ Listen 8140
         SSLVerifyDepth  1
         SSLOptions +StdEnvVars
 
+        RequestHeader set X-SSL-Subject %{SSL_CLIENT_S_DN}e
+        RequestHeader set X-Client-DN %{SSL_CLIENT_S_DN}e
+        RequestHeader set X-Client-Verify %{SSL_CLIENT_VERIFY}e
+
         DocumentRoot /etc/puppet/rack/public/
         RackBaseURI /
         <Directory /etc/puppet/rack/>
diff --git a/install.rb b/install.rb
index d015c4d..0dc2d52 100755
--- a/install.rb
+++ b/install.rb
@@ -53,7 +53,7 @@
   $haverdoc = false
 end
 
-PREREQS = %w{openssl facter xmlrpc/client xmlrpc/server cgi}
+PREREQS = %w{openssl facter cgi}
 MIN_FACTER_VERSION = 1.5
 
 InstallOptions = OpenStruct.new
diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb
index 47dd44a..b684470 100644
--- a/lib/puppet/agent.rb
+++ b/lib/puppet/agent.rb
@@ -8,6 +8,9 @@ class Puppet::Agent
   require 'puppet/agent/locker'
   include Puppet::Agent::Locker
 
+  require 'puppet/agent/disabler'
+  include Puppet::Agent::Disabler
+
   attr_reader :client_class, :client, :splayed
 
   # Just so we can specify that we are "the" instance.
@@ -31,6 +34,10 @@ def run(*args)
       Puppet.notice "Run of #{client_class} already in progress; skipping"
       return
     end
+    if disabled?
+      Puppet.notice "Skipping run of #{client_class}; administratively disabled: #{disable_message}"
+      return
+    end
     result = nil
     block_run = Puppet::Application.controlled_run do
       splay
diff --git a/lib/puppet/agent/disabler.rb b/lib/puppet/agent/disabler.rb
new file mode 100644
index 0000000..34ab94b
--- /dev/null
+++ b/lib/puppet/agent/disabler.rb
@@ -0,0 +1,27 @@
+require 'puppet/util/anonymous_filelock'
+
+module Puppet::Agent::Disabler
+  # Let the daemon run again, freely in the filesystem.
+  def enable
+    disable_lockfile.unlock
+  end
+
+  # Stop the daemon from making any catalog runs.
+  def disable(msg='')
+    disable_lockfile.lock(msg)
+  end
+
+  def disable_lockfile
+    @disable_lockfile ||= Puppet::Util::AnonymousFilelock.new(lockfile_path+".disabled")
+
+    @disable_lockfile
+  end
+
+  def disabled?
+    disable_lockfile.locked?
+  end
+
+  def disable_message
+    disable_lockfile.message
+  end
+end
diff --git a/lib/puppet/agent/locker.rb b/lib/puppet/agent/locker.rb
index 98f5b38..d41b125 100644
--- a/lib/puppet/agent/locker.rb
+++ b/lib/puppet/agent/locker.rb
@@ -3,16 +3,6 @@
 # Break out the code related to locking the agent.  This module is just
 # included into the agent, but having it here makes it easier to test.
 module Puppet::Agent::Locker
-  # Let the daemon run again, freely in the filesystem.
-  def enable
-    lockfile.unlock(:anonymous => true)
-  end
-
-  # Stop the daemon from making any catalog runs.
-  def disable
-    lockfile.lock(:anonymous => true)
-  end
-
   # Yield if we get a lock, else do nothing.  Return
   # true/false depending on whether we get the lock.
   def lock
diff --git a/lib/puppet/application.rb b/lib/puppet/application.rb
index b7cb116..f6dac39 100644
--- a/lib/puppet/application.rb
+++ b/lib/puppet/application.rb
@@ -263,12 +263,15 @@ def preinit
   end
 
   def initialize(command_line = nil)
+
     require 'puppet/util/command_line'
     @command_line = command_line || Puppet::Util::CommandLine.new
     set_run_mode self.class.run_mode
     @options = {}
 
     require 'puppet'
+    require 'puppet/util/instrumentation'
+    Puppet::Util::Instrumentation.init
   end
 
   # WARNING: This is a totally scary, frightening, and nasty internal API.  We
diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb
index a3854a8..46bb741 100644
--- a/lib/puppet/application/agent.rb
+++ b/lib/puppet/application/agent.rb
@@ -39,7 +39,12 @@ def preinit
   end
 
   option("--centrallogging")
-  option("--disable")
+
+  option("--disable [MESSAGE]") do |message|
+    options[:disable] = true
+    options[:disable_message] = message
+  end
+
   option("--enable")
   option("--debug","-d")
   option("--fqdn FQDN","-f")
@@ -49,14 +54,6 @@ def preinit
   option("--fingerprint")
   option("--digest DIGEST")
 
-  option("--serve HANDLER", "-s") do |arg|
-    if Puppet::Network::Handler.handler(arg)
-      options[:serve] << arg.to_sym
-    else
-      raise "Could not find handler for #{arg}"
-    end
-  end
-
   option("--no-client") do |arg|
     options[:client] = false
   end
@@ -101,9 +98,9 @@ def help
 USAGE
 -----
 puppet agent [--certname <name>] [-D|--daemonize|--no-daemonize]
-  [-d|--debug] [--detailed-exitcodes] [--digest <digest>] [--disable] [--enable]
+  [-d|--debug] [--detailed-exitcodes] [--digest <digest>] [--disable [message]] [--enable]
   [--fingerprint] [-h|--help] [-l|--logdest syslog|<file>|console]
-  [--no-client] [--noop] [-o|--onetime] [--serve <handler>] [-t|--test]
+  [--no-client] [--noop] [-o|--onetime] [-t|--test]
   [-v|--verbose] [-V|--version] [-w|--waitforcert <seconds>]
 
 
@@ -205,6 +202,9 @@ def help
   not want the central configuration to override the local state until
   everything is tested and committed.
 
+  Disable can also take an optional message that will be reported by the
+  'puppet agent' at the next disabled run.
+
   'puppet agent' uses the same lock file while it is running, so no more
   than one 'puppet agent' process is working at a time.
 
@@ -247,15 +247,6 @@ def help
   run. Useful for interactively running puppet agent when used in
   conjunction with the --no-daemonize option.
 
-* --serve:
-  Start another type of server. By default, 'puppet agent' will start a
-  service handler that allows authenticated and authorized remote nodes
-  to trigger the configuration to be pulled down and applied. You can
-  specify any handler here that does not require configuration, e.g.,
-  filebucket, ca, or resource. The handlers are in
-  'lib/puppet/network/handler', and the names must match exactly, both
-  in the call to 'serve' and in 'namespaceauth.conf'.
-
 * --test:
   Enable the most common options used for testing. These are 'onetime',
   'verbose', 'ignorecache', 'no-daemonize', 'no-usecacheonfailure',
@@ -384,7 +375,7 @@ def enable_disable_client(agent)
     if options[:enable]
       agent.enable
     elsif options[:disable]
-      agent.disable
+      agent.disable(options[:disable_message] || 'reason not specified')
     end
     exit(0)
   end
@@ -395,17 +386,9 @@ def setup_listen
       exit(14)
     end
 
-    handlers = nil
-
-    if options[:serve].empty?
-      handlers = [:Runner]
-    else
-      handlers = options[:serve]
-    end
-
     require 'puppet/network/server'
     # No REST handlers yet.
-    server = Puppet::Network::Server.new(:xmlrpc_handlers => handlers, :port => Puppet[:puppetport])
+    server = Puppet::Network::Server.new(:port => Puppet[:puppetport])
 
     @daemon.server = server
   end
@@ -416,6 +399,35 @@ def setup_host
     cert = @host.wait_for_cert(waitforcert) unless options[:fingerprint]
   end
 
+  def setup_agent
+    # We need tomake the client either way, we just don't start it
+    # if --no-client is set.
+    require 'puppet/agent'
+    require 'puppet/configurer'
+    @agent = Puppet::Agent.new(Puppet::Configurer)
+
+    enable_disable_client(@agent) if options[:enable] or options[:disable]
+
+    @daemon.agent = agent if options[:client]
+
+    # It'd be nice to daemonize later, but we have to daemonize before the
+    # waitforcert happens.
+    @daemon.daemonize if Puppet[:daemonize]
+
+    setup_host
+
+    @objects = []
+
+    # This has to go after the certs are dealt with.
+    if Puppet[:listen]
+      unless Puppet[:onetime]
+        setup_listen
+      else
+        Puppet.notice "Ignoring --listen on onetime run"
+      end
+    end
+  end
+
   def setup
     setup_test if options[:test]
 
@@ -460,31 +472,10 @@ def setup
 
     Puppet::Resource::Catalog.indirection.cache_class = :yaml
 
-    # We need tomake the client either way, we just don't start it
-    # if --no-client is set.
-    require 'puppet/agent'
-    require 'puppet/configurer'
-    @agent = Puppet::Agent.new(Puppet::Configurer)
-
-    enable_disable_client(@agent) if options[:enable] or options[:disable]
-
-    @daemon.agent = agent if options[:client]
-
-    # It'd be nice to daemonize later, but we have to daemonize before the
-    # waitforcert happens.
-    @daemon.daemonize if Puppet[:daemonize]
-
-    setup_host
-
-    @objects = []
-
-    # This has to go after the certs are dealt with.
-    if Puppet[:listen]
-      unless Puppet[:onetime]
-        setup_listen
-      else
-        Puppet.notice "Ignoring --listen on onetime run"
-      end
+    unless options[:fingerprint]
+      setup_agent
+    else
+      setup_host
     end
   end
 end
diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb
index 5df00d7..e9b4e7a 100644
--- a/lib/puppet/application/apply.rb
+++ b/lib/puppet/application/apply.rb
@@ -14,6 +14,14 @@ class Puppet::Application::Apply < Puppet::Application
   option("--detailed-exitcodes")
 
   option("--apply catalog",  "-a catalog") do |arg|
+    Puppet.warning <<EOM
+--apply is deprecated and will be removed in the future. Please
+use 'puppet apply --catalog <catalog>'.
+EOM
+    options[:catalog] = arg
+  end
+
+  option("--catalog catalog",  "-c catalog") do |arg|
     options[:catalog] = arg
   end
 
@@ -46,7 +54,7 @@ def help
 -----
 puppet apply [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
   [-e|--execute] [--detailed-exitcodes] [-l|--logdest <file>]
-  [--apply <catalog>] <file>
+  [--apply <catalog>] [--catalog <catalog>] <file>
 
 
 DESCRIPTION
@@ -107,6 +115,11 @@ def help
 
 * --apply:
   Apply a JSON catalog (such as one generated with 'puppet master --compile'). You can
+  either specify a JSON file or pipe in JSON from standard input. Deprecated, please
+  use --catalog instead.
+
+* --catalog:
+  Apply a JSON catalog (such as one generated with 'puppet master --compile'). You can
   either specify a JSON file or pipe in JSON from standard input.
 
 
@@ -114,6 +127,7 @@ def help
 -------
     $ puppet apply -l /tmp/manifest.log manifest.pp
     $ puppet apply --modulepath=/root/dev/modules -e "include ntpd::server"
+    $ puppet apply --catalog catalog.json
 
 
 AUTHOR
diff --git a/lib/puppet/application/cert.rb b/lib/puppet/application/cert.rb
index 7285d88..7b14311 100644
--- a/lib/puppet/application/cert.rb
+++ b/lib/puppet/application/cert.rb
@@ -17,11 +17,11 @@ def subcommand=(name)
     @subcommand = (sub == :clean ? :destroy : sub)
   end
 
-  option("--clean", "-c") do
+  option("--clean", "-c") do |arg|
     self.subcommand = "destroy"
   end
 
-  option("--all", "-a") do
+  option("--all", "-a") do |arg|
     @all = true
   end
 
@@ -29,7 +29,7 @@ def subcommand=(name)
     @digest = arg
   end
 
-  option("--signed", "-s") do
+  option("--signed", "-s") do |arg|
     @signed = true
   end
 
@@ -39,7 +39,7 @@ def subcommand=(name)
 
   require 'puppet/ssl/certificate_authority/interface'
   Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.reject {|m| m == :destroy }.each do |method|
-    option("--#{method.to_s.gsub('_','-')}", "-#{method.to_s[0,1]}") do
+    option("--#{method.to_s.gsub('_','-')}", "-#{method.to_s[0,1]}") do |arg|
       self.subcommand = method
     end
   end
@@ -48,7 +48,7 @@ def subcommand=(name)
     options[:allow_dns_alt_names] = value
   end
 
-  option("--verbose", "-v") do
+  option("--verbose", "-v") do |arg|
     Puppet::Util::Log.level = :info
   end
 
diff --git a/lib/puppet/application/inspect.rb b/lib/puppet/application/inspect.rb
index 6737128..f3a005b 100644
--- a/lib/puppet/application/inspect.rb
+++ b/lib/puppet/application/inspect.rb
@@ -118,6 +118,7 @@ def run_command
       end
 
       @report.configuration_version = catalog.version
+      @report.environment = Puppet[:environment]
 
       inspect_starttime = Time.now
       @report.add_times("config_retrieval", inspect_starttime - retrieval_starttime)
diff --git a/lib/puppet/application/instrumentation_data.rb b/lib/puppet/application/instrumentation_data.rb
new file mode 100644
index 0000000..e4f86f1
--- /dev/null
+++ b/lib/puppet/application/instrumentation_data.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Instrumentation_data < Puppet::Application::IndirectionBase
+end
diff --git a/lib/puppet/application/instrumentation_listener.rb b/lib/puppet/application/instrumentation_listener.rb
new file mode 100644
index 0000000..64029b5
--- /dev/null
+++ b/lib/puppet/application/instrumentation_listener.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Instrumentation_listener < Puppet::Application::IndirectionBase
+end
diff --git a/lib/puppet/application/instrumentation_probe.rb b/lib/puppet/application/instrumentation_probe.rb
new file mode 100644
index 0000000..b31f95c
--- /dev/null
+++ b/lib/puppet/application/instrumentation_probe.rb
@@ -0,0 +1,4 @@
+require 'puppet/application/indirection_base'
+
+class Puppet::Application::Instrumentation_probe < Puppet::Application::IndirectionBase
+end
diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb
index b4da770..553e279 100644
--- a/lib/puppet/application/master.rb
+++ b/lib/puppet/application/master.rb
@@ -166,10 +166,6 @@ def main
     require 'puppet/file_serving/content'
     require 'puppet/file_serving/metadata'
 
-    xmlrpc_handlers = [:Status, :FileServer, :Master, :Report, :Filebucket]
-
-    xmlrpc_handlers << :CA if Puppet[:ca]
-
     # Make sure we've got a localhost ssl cert
     Puppet::SSL::Host.localhost
 
@@ -189,11 +185,11 @@ def main
 
     unless options[:rack]
       require 'puppet/network/server'
-      @daemon.server = Puppet::Network::Server.new(:xmlrpc_handlers => xmlrpc_handlers)
+      @daemon.server = Puppet::Network::Server.new()
       @daemon.daemonize if Puppet[:daemonize]
     else
       require 'puppet/network/http/rack'
-      @app = Puppet::Network::HTTP::Rack.new(:xmlrpc_handlers => xmlrpc_handlers, :protocols => [:rest, :xmlrpc])
+      @app = Puppet::Network::HTTP::Rack.new()
     end
 
     Puppet.notice "Starting Puppet master version #{Puppet.version}"
diff --git a/lib/puppet/application/module.rb b/lib/puppet/application/module.rb
new file mode 100644
index 0000000..0b1c20e
--- /dev/null
+++ b/lib/puppet/application/module.rb
@@ -0,0 +1,3 @@
+require 'puppet/application/face_base'
+
+class Puppet::Application::Module < Puppet::Application::FaceBase; end
diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb
index 83b5a9a..5df3b7b 100644
--- a/lib/puppet/configurer.rb
+++ b/lib/puppet/configurer.rb
@@ -116,6 +116,7 @@ def retrieve_and_apply_catalog(options, fact_options)
 
     report = options[:report]
     report.configuration_version = catalog.version
+    report.environment = Puppet[:environment]
 
     benchmark(:notice, "Finished catalog run") do
       catalog.apply(options)
@@ -178,9 +179,17 @@ def send_report(report)
   end
 
   def save_last_run_summary(report)
-    Puppet::Util::FileLocking.writelock(Puppet[:lastrunfile], 0660) do |file|
-      file.print YAML.dump(report.raw_summary)
-    end
+    last_run = Puppet.settings.setting(:lastrunfile)
+    last_run.create = true # force file creation
+
+    resource = last_run.to_resource
+    resource[:content] = YAML.dump(report.raw_summary)
+
+    catalog = Puppet::Resource::Catalog.new("last_run_file")
+    catalog.add_resource(resource)
+    ral = catalog.to_ral
+    ral.host_config = false
+    ral.apply
   rescue => detail
     puts detail.backtrace if Puppet[:trace]
     Puppet.err "Could not save last run local report: #{detail}"
diff --git a/lib/puppet/configurer/downloader.rb b/lib/puppet/configurer/downloader.rb
index b369620..54075ee 100644
--- a/lib/puppet/configurer/downloader.rb
+++ b/lib/puppet/configurer/downloader.rb
@@ -63,14 +63,16 @@ def file
 
   private
 
+  require 'sys/admin' if Puppet.features.microsoft_windows?
+
   def default_arguments
     {
       :path => path,
       :recurse => true,
       :source => source,
       :tag => name,
-      :owner => Process.uid,
-      :group => Process.gid,
+      :owner => Puppet.features.microsoft_windows? ? Sys::Admin.get_login : Process.uid,
+      :group => Puppet.features.microsoft_windows? ? 'S-1-0-0' : Process.gid,
       :purge => true,
       :force => true,
       :backup => false,
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 0789237..ac40fbf 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -199,6 +199,10 @@ module Puppet
       essentially means that you can't have any code outside of a node, class, or definition other
       than in the site manifest."]
   )
+  Puppet.setdefaults(:module_tool,
+    :module_repository  => ['http://forge.puppetlabs.com', "The module repository"],
+    :module_working_dir => ['$vardir/puppet-module', "The directory into which module tool data is stored"]
+  )
 
   hostname = Facter["hostname"].value
   domain = Facter["domain"].value
@@ -606,7 +610,12 @@ module Puppet
       :mode => 0640,
       :desc => "The log file for puppet agent.  This is generally not used."
     },
-    :server => ["puppet", "The server to which server puppet agent should connect"],
+    :server => {
+      :default => "puppet",
+      :desc => "The server to which the puppet agent should connect"
+    },
+    :use_srv_records => [true, "Whether the server will search for SRV records in DNS for the current domain."],
+    :srv_domain => [ "#{domain}", "The domain which will be queried to find the SRV records of servers to use."],
     :ignoreschedules => [false,
       "Boolean; whether puppet agent should ignore schedules.  This is useful
       for initial puppet agent runs."],
@@ -705,11 +714,11 @@ module Puppet
       "Whether to send reports after every transaction."
     ],
     :lastrunfile =>  { :default => "$statedir/last_run_summary.yaml",
-      :mode => 0660,
+      :mode => 0644,
       :desc => "Where puppet agent stores the last run report summary in yaml format."
     },
     :lastrunreport =>  { :default => "$statedir/last_run_report.yaml",
-      :mode => 0660,
+      :mode => 0644,
       :desc => "Where puppet agent stores the last run report in yaml format."
     },
     :graph => [false, "Whether to create dot graph files for the different
diff --git a/lib/puppet/face/catalog.rb b/lib/puppet/face/catalog.rb
index 10b15d2..efd4ee7 100644
--- a/lib/puppet/face/catalog.rb
+++ b/lib/puppet/face/catalog.rb
@@ -66,6 +66,7 @@
 
       report = Puppet::Transaction::Report.new("apply")
       report.configuration_version = catalog.version
+      report.environment = Puppet[:environment]
 
       Puppet::Util::Log.newdestination(report)
 
diff --git a/lib/puppet/face/config.rb b/lib/puppet/face/config.rb
index 05fc406..2875770 100644
--- a/lib/puppet/face/config.rb
+++ b/lib/puppet/face/config.rb
@@ -37,6 +37,9 @@
 
     when_invoked do |*args|
       options = args.pop
+
+      args = [ "all" ] if args.empty?
+
       Puppet.settings[:configprint] = args.join(",")
       Puppet.settings.print_config_options
       nil
diff --git a/lib/puppet/face/instrumentation_data.rb b/lib/puppet/face/instrumentation_data.rb
new file mode 100644
index 0000000..1abf7cd
--- /dev/null
+++ b/lib/puppet/face/instrumentation_data.rb
@@ -0,0 +1,28 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:instrumentation_data, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Manage instrumentation listener accumulated data."
+  description <<-EOT
+    This subcommand allows to retrieve the various listener data.
+  EOT
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+  get_action(:save).summary "Invalid for this subcommand."
+  get_action(:search).summary "Invalid for this subcommand."
+
+  find = get_action(:find)
+  find.summary "Retrieve listener data."
+  find.render_as = :pson
+  find.returns <<-EOT
+    The data of an instrumentation listener
+  EOT
+  find.examples <<-EOT
+    Retrieve listener data:
+
+    $ puppet instrumentation_data find performance --terminus rest
+  EOT
+
+end
diff --git a/lib/puppet/face/instrumentation_listener.rb b/lib/puppet/face/instrumentation_listener.rb
new file mode 100644
index 0000000..de4a742
--- /dev/null
+++ b/lib/puppet/face/instrumentation_listener.rb
@@ -0,0 +1,96 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:instrumentation_listener, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Manage instrumentation listeners."
+  description <<-EOT
+    This subcommand enables/disables or list instrumentation listeners.
+  EOT
+
+  get_action(:destroy).summary "Invalid for this subcommand."
+
+  find = get_action(:find)
+  find.summary "Retrieve a single listener."
+  find.render_as = :pson
+  find.returns <<-EOT
+    The status of an instrumentation listener
+  EOT
+  find.examples <<-EOT
+    Retrieve a given listener:
+
+    $ puppet instrumentation_listener find performance --terminus rest
+  EOT
+
+  search = get_action(:search)
+  search.summary "Retrieve all instrumentation listeners statuses."
+  search.arguments "<dummy_text>"
+  search.render_as = :pson
+  search.returns <<-EOT
+    The statuses of all instrumentation listeners
+  EOT
+  search.short_description <<-EOT
+    This retrieves all instrumentation listeners
+  EOT
+  search.notes <<-EOT
+    Although this action always returns all instrumentation listeners, it requires a dummy search
+    key; this is a known bug.
+  EOT
+  search.examples <<-EOT
+    Retrieve the state of the listeners running in the remote puppet master:
+
+    $ puppet instrumentation_listener search x --terminus rest
+  EOT
+
+  def manage(name, activate)
+    Puppet::Util::Instrumentation::Listener.indirection.terminus_class = :rest
+    listener = Puppet::Face[:instrumentation_listener, '0.0.1'].find(name)
+    if listener
+      listener.enabled = activate
+      Puppet::Face[:instrumentation_listener, '0.0.1'].save(listener)
+    end
+  end
+
+  action :enable do
+    summary "Enable a given instrumentation listener."
+    arguments "<listener>"
+    returns "Nothing."
+    description <<-EOT
+      Enable a given instrumentation listener. After being enabled the listener
+      will start receiving instrumentation notifications from the probes if those
+      are enabled.
+    EOT
+    examples <<-EOT
+      Enable the "performance" listener in the running master:
+
+      $ puppet instrumentation_listener enable performance --terminus rest
+    EOT
+
+    when_invoked do |name, options|
+      manage(name, true)
+    end
+  end
+
+  action :disable do
+    summary "Disable a given instrumentation listener."
+    arguments "<listener>"
+    returns "Nothing."
+    description <<-EOT
+      Disable a given instrumentation listener. After being disabled the listener
+      will stop receiving instrumentation notifications from the probes.
+    EOT
+    examples <<-EOT
+      Disable the "performance" listener in the running master:
+
+      $ puppet instrumentation_listener disable performance --terminus rest
+    EOT
+
+    when_invoked do |name, options|
+      manage(name, false)
+    end
+  end
+
+  get_action(:save).summary "API only: modify an instrumentation listener status."
+  get_action(:save).arguments "<listener>"
+end
diff --git a/lib/puppet/face/instrumentation_probe.rb b/lib/puppet/face/instrumentation_probe.rb
new file mode 100644
index 0000000..52b331c
--- /dev/null
+++ b/lib/puppet/face/instrumentation_probe.rb
@@ -0,0 +1,77 @@
+require 'puppet/indirector/face'
+
+Puppet::Indirector::Face.define(:instrumentation_probe, '0.0.1') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Manage instrumentation probes."
+  description <<-EOT
+    This subcommand enables/disables or list instrumentation listeners.
+  EOT
+
+  get_action(:find).summary "Invalid for this subcommand."
+
+  search = get_action(:search)
+  search.summary "Retrieve all probe statuses."
+  search.arguments "<dummy_text>"
+  search.render_as = :pson
+  search.returns <<-EOT
+    The statuses of all instrumentation probes
+  EOT
+  search.short_description <<-EOT
+    This retrieves all instrumentation probes
+  EOT
+  search.notes <<-EOT
+    Although this action always returns all instrumentation probes, it requires a dummy search
+    key; this is a known bug.
+  EOT
+  search.examples <<-EOT
+    Retrieve the state of the probes running in the remote puppet master:
+
+    $ puppet instrumentation_probe search x --terminus rest
+  EOT
+
+  action :enable do
+    summary "Enable all instrumentation probes."
+    arguments "<dummy>"
+    returns "Nothing."
+    description <<-EOT
+      Enable all instrumentation probes. After being enabled, all enabled listeners
+      will start receiving instrumentation notifications from the probes.
+    EOT
+    examples <<-EOT
+      Enable the probes for the running master:
+
+      $ puppet instrumentation_probe enable x --terminus rest
+    EOT
+
+    when_invoked do |name, options|
+      Puppet::Face[:instrumentation_probe, '0.0.1'].save(nil)
+    end
+  end
+
+  action :disable do
+    summary "Disable all instrumentation probes."
+    arguments "<dummy>"
+    returns "Nothing."
+    description <<-EOT
+      Disable all instrumentation probes. After being disabled, no listeners
+      will receive instrumentation notifications.
+    EOT
+    examples <<-EOT
+      Disable the probes for the running master:
+
+      $ puppet instrumentation_probe disable x --terminus rest
+    EOT
+
+    when_invoked do |name, options|
+      Puppet::Face[:instrumentation_probe, '0.0.1'].destroy(nil)
+    end
+  end
+
+  get_action(:save).summary "API only: enable all instrumentation probes."
+  get_action(:save).arguments "<dummy>"
+
+  get_action(:destroy).summary "API only: disable all instrumentation probes."
+  get_action(:destroy).arguments "<dummy>"
+end
diff --git a/lib/puppet/face/module.rb b/lib/puppet/face/module.rb
new file mode 100644
index 0000000..bab553c
--- /dev/null
+++ b/lib/puppet/face/module.rb
@@ -0,0 +1,12 @@
+require 'puppet/face'
+require 'puppet/module_tool'
+
+Puppet::Face.define(:module, '1.0.0') do
+  copyright "Puppet Labs", 2011
+  license   "Apache 2 license; see COPYING"
+
+  summary "Creates, installs and searches for modules on the Puppet Forge."
+  description <<-EOT
+    Creates, installs and searches for modules on the Puppet Forge.
+  EOT
+end
diff --git a/lib/puppet/face/module/build.rb b/lib/puppet/face/module/build.rb
new file mode 100644
index 0000000..2273634
--- /dev/null
+++ b/lib/puppet/face/module/build.rb
@@ -0,0 +1,31 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:build) do
+    summary "Build a module release package."
+    description <<-EOT
+      Build a module release archive file by processing the Modulefile in the
+      module directory.  The release archive file will be stored in the pkg
+      directory of the module directory.
+    EOT
+
+    returns "Pathname object representing the path to the release archive."
+
+    examples <<-EOT
+      Build a module release:
+
+      $ puppet module build puppetlabs-apache
+      notice: Building /Users/kelseyhightower/puppetlabs-apache for release
+      puppetlabs-apache/pkg/puppetlabs-apache-0.0.1.tar.gz
+    EOT
+
+    arguments "<path>"
+
+    when_invoked do |path, options|
+      Puppet::Module::Tool::Applications::Builder.run(path, options)
+    end
+
+    when_rendering :console do |return_value|
+      # Get the string representation of the Pathname object.
+      return_value.to_s
+    end
+  end
+end
diff --git a/lib/puppet/face/module/changes.rb b/lib/puppet/face/module/changes.rb
new file mode 100644
index 0000000..0266611
--- /dev/null
+++ b/lib/puppet/face/module/changes.rb
@@ -0,0 +1,38 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:changes) do
+    summary "Show modified files of an installed module."
+    description <<-EOT
+      Show files that have been modified after installation of a given module
+      by comparing the on-disk md5 checksum of each file against the module's
+      metadata.
+    EOT
+
+    returns "Array of strings representing paths of modified files."
+
+    examples <<-EOT
+      Show modified files of an installed module:
+
+      $ puppet module changes /etc/puppet/modules/vcsrepo/
+      warning: 1 files modified
+      lib/puppet/provider/vcsrepo.rb
+    EOT
+
+    arguments "<path>"
+
+    when_invoked do |path, options|
+      root_path = Puppet::Module::Tool.find_module_root(path)
+      Puppet::Module::Tool::Applications::Checksummer.run(root_path, options)
+    end
+
+    when_rendering :console do |return_value|
+      if return_value.empty?
+        Puppet.notice "No modified files"
+      else
+        Puppet.warning "#{return_value.size} files modified"
+      end
+      return_value.map do |changed_file|
+        "#{changed_file}"
+      end.join("\n")
+    end
+  end
+end
diff --git a/lib/puppet/face/module/clean.rb b/lib/puppet/face/module/clean.rb
new file mode 100644
index 0000000..6372630
--- /dev/null
+++ b/lib/puppet/face/module/clean.rb
@@ -0,0 +1,30 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:clean) do
+    summary "Clean the module download cache."
+    description <<-EOT
+      Clean the module download cache.
+    EOT
+
+    returns <<-EOT
+      Return a status Hash:
+
+        { :status => "success", :msg => "Cleaned module cache." }
+    EOT
+
+    examples <<-EOT
+      Clean the module download cache:
+
+      $ puppet module clean
+      Cleaned module cache.
+    EOT
+
+    when_invoked do |options|
+      Puppet::Module::Tool::Applications::Cleaner.run(options)
+    end
+
+    when_rendering :console do |return_value|
+      # Print the status message to the console.
+      return_value[:msg]
+    end
+  end
+end
diff --git a/lib/puppet/face/module/generate.rb b/lib/puppet/face/module/generate.rb
new file mode 100644
index 0000000..b9dc354
--- /dev/null
+++ b/lib/puppet/face/module/generate.rb
@@ -0,0 +1,40 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:generate) do
+    summary "Generate boilerplate for a new module."
+    description <<-EOT
+      Generate boilerplate for a new module by creating a directory
+      pre-populated with a directory structure and files recommended for
+      Puppet best practices.
+    EOT
+
+    returns "Array of Pathname objects representing paths of generated files."
+
+    examples <<-EOT
+      Generate a new module in the current directory:
+
+      $ puppet module generate puppetlabs-ssh
+      notice: Generating module at /Users/kelseyhightower/puppetlabs-ssh
+      puppetlabs-ssh
+      puppetlabs-ssh/tests
+      puppetlabs-ssh/tests/init.pp
+      puppetlabs-ssh/spec
+      puppetlabs-ssh/spec/spec_helper.rb
+      puppetlabs-ssh/spec/spec.opts
+      puppetlabs-ssh/README
+      puppetlabs-ssh/Modulefile
+      puppetlabs-ssh/metadata.json
+      puppetlabs-ssh/manifests
+      puppetlabs-ssh/manifests/init.pp
+    EOT
+
+    arguments "<name>"
+
+    when_invoked do |name, options|
+      Puppet::Module::Tool::Applications::Generator.run(name, options)
+    end
+
+    when_rendering :console do |return_value|
+      return_value.map {|f| f.to_s }.join("\n")
+    end
+  end
+end
diff --git a/lib/puppet/face/module/install.rb b/lib/puppet/face/module/install.rb
new file mode 100644
index 0000000..8f95ff4
--- /dev/null
+++ b/lib/puppet/face/module/install.rb
@@ -0,0 +1,83 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:install) do
+    summary "Install a module from a repository or release archive."
+    description <<-EOT
+      Install a module from a release archive file on-disk or by downloading
+      one from a repository. Unpack the archive into the install directory
+      specified by the --install-dir option, which defaults to
+      #{Puppet.settings[:modulepath].split(File::PATH_SEPARATOR).first}
+    EOT
+
+    returns "Pathname object representing the path to the installed module."
+
+    examples <<-EOT
+      Install a module from the default repository:
+
+      $ puppet module install puppetlabs/vcsrepo
+      notice: Installing puppetlabs-vcsrepo-0.0.4.tar.gz to /etc/puppet/modules/vcsrepo
+      /etc/puppet/modules/vcsrepo
+
+      Install a specific module version from a repository:
+
+      $ puppet module install puppetlabs/vcsrepo -v 0.0.4
+      notice: Installing puppetlabs-vcsrepo-0.0.4.tar.gz to /etc/puppet/modules/vcsrepo
+      /etc/puppet/modules/vcsrepo
+
+      Install a module into a specific directory:
+
+      $ puppet module install puppetlabs/vcsrepo --install-dir=/usr/share/puppet/modules
+      notice: Installing puppetlabs-vcsrepo-0.0.4.tar.gz to /usr/share/puppet/modules/vcsrepo
+      /usr/share/puppet/modules/vcsrepo
+
+      Install a module from a release archive:
+
+      $ puppet module install puppetlabs-vcsrepo-0.0.4.tar.gz
+      notice: Installing puppetlabs-vcsrepo-0.0.4.tar.gz to /etc/puppet/modules/vcsrepo
+      /etc/puppet/modules/vcsrepo
+    EOT
+
+    arguments "<name>"
+
+    option "--force", "-f" do
+      summary "Force overwrite of existing module, if any."
+      description <<-EOT
+        Force overwrite of existing module, if any.
+      EOT
+    end
+
+    option "--install-dir=", "-i=" do
+      default_to { Puppet.settings[:modulepath].split(File::PATH_SEPARATOR).first }
+      summary "The directory into which modules are installed."
+      description <<-EOT
+        The directory into which modules are installed, defaults to the first
+        directory in the modulepath.
+      EOT
+    end
+
+    option "--module-repository=", "-r=" do
+      default_to { Puppet.settings[:module_repository] }
+      summary "Module repository to use."
+      description <<-EOT
+        Module repository to use.
+      EOT
+    end
+
+    option "--version=", "-v=" do
+      summary "Module version to install."
+      description <<-EOT
+        Module version to install, can be a requirement string, eg '>= 1.0.3',
+        defaults to latest version.
+      EOT
+    end
+
+    when_invoked do |name, options|
+      Puppet::Module::Tool::Applications::Installer.run(name, options)
+    end
+
+    when_rendering :console do |return_value|
+      # Get the string representation of the Pathname object and print it to
+      # the console.
+      return_value.to_s
+    end
+  end
+end
diff --git a/lib/puppet/face/module/search.rb b/lib/puppet/face/module/search.rb
new file mode 100644
index 0000000..fdc2c98
--- /dev/null
+++ b/lib/puppet/face/module/search.rb
@@ -0,0 +1,66 @@
+Puppet::Face.define(:module, '1.0.0') do
+  action(:search) do
+    summary "Search a repository for a module."
+    description <<-EOT
+      Search a repository for modules whose names match a specific substring.
+    EOT
+
+    returns "Array of module metadata hashes"
+
+    examples <<-EOT
+      Search the default repository for a module:
+
+      $ puppet module search puppetlabs
+      notice: Searching http://forge.puppetlabs.com
+      notice: 24 found.
+      puppetlabs/apache (0.0.3)
+      puppetlabs/collectd (0.0.1)
+      puppetlabs/ruby (0.0.1)
+      puppetlabs/vcsrepo (0.0.4)
+      puppetlabs/gcc (0.0.3)
+      puppetlabs/passenger (0.0.2)
+      puppetlabs/DeveloperBootstrap (0.0.5)
+      jeffmccune/tomcat (1.0.1)
+      puppetlabs/motd (1.0.0)
+      puppetlabs/lvm (0.1.0)
+      puppetlabs/rabbitmq (1.0.4)
+      puppetlabs/prosvc_repo (1.0.1)
+      puppetlabs/stdlib (2.2.0)
+      puppetlabs/java (0.1.5)
+      puppetlabs/activemq (0.1.6)
+      puppetlabs/mcollective (0.1.8)
+      puppetlabs/git (0.0.2)
+      puppetlabs/ntp (0.0.4)
+      puppetlabs/nginx (0.0.1)
+      puppetlabs/cloud_provisioner (0.6.0rc1)
+      puppetlabs/mrepo (0.1.1)
+      puppetlabs/f5 (0.1.0)
+      puppetlabs/firewall (0.0.3)
+      puppetlabs/bprobe (0.0.3)
+    EOT
+
+    arguments "<term>"
+
+    option "--module-repository=", "-r=" do
+      default_to { Puppet.settings[:module_repository] }
+      summary "Module repository to use."
+      description <<-EOT
+        Module repository to use.
+      EOT
+    end
+
+    when_invoked do |term, options|
+      Puppet.notice "Searching #{options[:module_repository]}"
+      Puppet::Module::Tool::Applications::Searcher.run(term, options)
+    end
+
+    when_rendering :console do |return_value|
+      Puppet.notice "#{return_value.size} found."
+      return_value.map do |match|
+        # We reference the full_name here when referring to the full_module_name,
+        # because full_name is what is returned from the forge API call.
+        "#{match['full_name']} (#{match['version']})"
+      end.join("\n")
+    end
+  end
+end
diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb
index 8813197..7e60734 100644
--- a/lib/puppet/feature/base.rb
+++ b/lib/puppet/feature/base.rb
@@ -44,7 +44,7 @@
 Puppet.features.add(:root) { require 'puppet/util/suidmanager'; Puppet::Util::SUIDManager.root? }
 
 # We've got mongrel available
-Puppet.features.add(:mongrel, :libs => %w{rubygems mongrel puppet/network/http_server/mongrel})
+Puppet.features.add(:mongrel, :libs => %w{rubygems mongrel puppet/network/http/mongrel})
 
 # We have lcs diff
 Puppet.features.add :diff, :libs => %w{diff/lcs diff/lcs/hunk}
diff --git a/lib/puppet/file_serving/metadata.rb b/lib/puppet/file_serving/metadata.rb
index 587c219..131f9cb 100644
--- a/lib/puppet/file_serving/metadata.rb
+++ b/lib/puppet/file_serving/metadata.rb
@@ -17,20 +17,6 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::Base
 
   PARAM_ORDER = [:mode, :ftype, :owner, :group]
 
-  def attributes_with_tabs
-    raise(ArgumentError, "Cannot manage files of type #{ftype}") unless ['file','directory','link'].include? ftype
-    desc = []
-    PARAM_ORDER.each { |check|
-      check = :ftype if check == :type
-      desc << send(check)
-    }
-
-    desc << checksum
-    desc << @destination rescue nil if ftype == 'link'
-
-    desc.join("\t")
-  end
-
   def checksum_type=(type)
     raise(ArgumentError, "Unsupported checksum type #{type}") unless respond_to?("#{type}_file")
 
diff --git a/lib/puppet/indirector/catalog/active_record.rb b/lib/puppet/indirector/catalog/active_record.rb
index 365cdfe..754d740 100644
--- a/lib/puppet/indirector/catalog/active_record.rb
+++ b/lib/puppet/indirector/catalog/active_record.rb
@@ -5,19 +5,9 @@
 class Puppet::Resource::Catalog::ActiveRecord < Puppet::Indirector::ActiveRecord
   use_ar_model Puppet::Rails::Host
 
-  # If we can find the host, then return a catalog with the host's resources
-  # as the vertices.
+  # We don't retrieve catalogs from storeconfigs
   def find(request)
-    return nil unless request.options[:cache_integration_hack]
-    return nil unless host = ar_model.find_by_name(request.key)
-
-    catalog = Puppet::Resource::Catalog.new(host.name)
-
-    host.resources.each do |resource|
-      catalog.add_resource resource.to_transportable
-    end
-
-    catalog
+    nil
   end
 
   # Save the values from a Facts instance as the facts on a Rails Host instance.
diff --git a/lib/puppet/indirector/certificate/rest.rb b/lib/puppet/indirector/certificate/rest.rb
index 921b857..1cbf06a 100644
--- a/lib/puppet/indirector/certificate/rest.rb
+++ b/lib/puppet/indirector/certificate/rest.rb
@@ -6,6 +6,7 @@ class Puppet::SSL::Certificate::Rest < Puppet::Indirector::REST
 
   use_server_setting(:ca_server)
   use_port_setting(:ca_port)
+  use_srv_service(:ca)
 
   def find(request)
     return nil unless result = super
diff --git a/lib/puppet/indirector/exec.rb b/lib/puppet/indirector/exec.rb
index 8ea13ff..e6325ad 100644
--- a/lib/puppet/indirector/exec.rb
+++ b/lib/puppet/indirector/exec.rb
@@ -39,7 +39,7 @@ def query(name)
     end
 
     if output =~ /\A\s*\Z/ # all whitespace
-      Puppet.debug "Empty response for #{name} from exec #{self.name} terminus"
+      Puppet.debug "Empty response for #{name} from #{self.name} terminus"
       return nil
     else
       return output
diff --git a/lib/puppet/indirector/facts/inventory_active_record.rb b/lib/puppet/indirector/facts/inventory_active_record.rb
index db4c63f..93eee8a 100644
--- a/lib/puppet/indirector/facts/inventory_active_record.rb
+++ b/lib/puppet/indirector/facts/inventory_active_record.rb
@@ -2,6 +2,7 @@
 require 'puppet/rails/inventory_node'
 require 'puppet/rails/inventory_fact'
 require 'puppet/indirector/active_record'
+require 'puppet/util/retryaction'
 
 class Puppet::Node::Facts::InventoryActiveRecord < Puppet::Indirector::ActiveRecord
   def find(request)
@@ -13,19 +14,21 @@ def find(request)
   end
 
   def save(request)
-    facts = request.instance
-    node = Puppet::Rails::InventoryNode.find_by_name(request.key) || Puppet::Rails::InventoryNode.create(:name => request.key, :timestamp => facts.timestamp)
-    node.timestamp = facts.timestamp
+    Puppet::Util::RetryAction.retry_action :retries => 4, :retry_exceptions => {ActiveRecord::StatementInvalid => 'MySQL Error.  Retrying'} do
+      facts = request.instance
+      node = Puppet::Rails::InventoryNode.find_by_name(request.key) || Puppet::Rails::InventoryNode.create(:name => request.key, :timestamp => facts.timestamp)
+      node.timestamp = facts.timestamp
 
-    ActiveRecord::Base.transaction do
-      Puppet::Rails::InventoryFact.delete_all(:node_id => node.id)
-      # We don't want to save internal values as facts, because those are
-      # metadata that belong on the node
-      facts.values.each do |name,value|
-        next if name.to_s =~ /^_/
-        node.facts.build(:name => name, :value => value)
+      ActiveRecord::Base.transaction do
+        Puppet::Rails::InventoryFact.delete_all(:node_id => node.id)
+        # We don't want to save internal values as facts, because those are
+        # metadata that belong on the node
+        facts.values.each do |name,value|
+          next if name.to_s =~ /^_/
+          node.facts.build(:name => name, :value => value)
+        end
+        node.save
       end
-      node.save
     end
   end
 
diff --git a/lib/puppet/indirector/file_content/rest.rb b/lib/puppet/indirector/file_content/rest.rb
index 59975d3..1f6bc6e 100644
--- a/lib/puppet/indirector/file_content/rest.rb
+++ b/lib/puppet/indirector/file_content/rest.rb
@@ -4,4 +4,6 @@
 
 class Puppet::Indirector::FileContent::Rest < Puppet::Indirector::REST
   desc "Retrieve file contents via a REST HTTP interface."
+
+  use_srv_service(:fileserver)
 end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index 20b260b..7296be2 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -1,12 +1,19 @@
 require 'puppet/util/docs'
 require 'puppet/indirector/envelope'
 require 'puppet/indirector/request'
+require 'puppet/util/instrumentation/instrumentable'
 
 # The class that connects functional classes with their different collection
 # back-ends.  Each indirection has a set of associated terminus classes,
 # each of which is a subclass of Puppet::Indirector::Terminus.
 class Puppet::Indirector::Indirection
   include Puppet::Util::Docs
+  extend Puppet::Util::Instrumentation::Instrumentable
+
+  probe :find, :label => Proc.new { |parent, key, *args| "find_#{parent.name}_#{parent.terminus_class}" }, :data => Proc.new { |parent, key, *args| { :key => key }}
+  probe :save, :label => Proc.new { |parent, key, *args| "save_#{parent.name}_#{parent.terminus_class}" }, :data => Proc.new { |parent, key, *args| { :key => key }}
+  probe :search, :label => Proc.new { |parent, key, *args| "search_#{parent.name}_#{parent.terminus_class}" }, :data => Proc.new { |parent, key, *args| { :key => key }}
+  probe :destroy, :label => Proc.new { |parent, key, *args| "destroy_#{parent.name}_#{parent.terminus_class}" }, :data => Proc.new { |parent, key, *args| { :key => key }}
 
   @@indirections = []
 
diff --git a/lib/puppet/indirector/instrumentation_data.rb b/lib/puppet/indirector/instrumentation_data.rb
new file mode 100644
index 0000000..f1bea33
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_data.rb
@@ -0,0 +1,3 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::InstrumentationData
+end
diff --git a/lib/puppet/indirector/instrumentation_data/local.rb b/lib/puppet/indirector/instrumentation_data/local.rb
new file mode 100644
index 0000000..6510d7f
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_data/local.rb
@@ -0,0 +1,19 @@
+require 'puppet/indirector/instrumentation_data'
+
+class Puppet::Indirector::InstrumentationData::Local < Puppet::Indirector::Code
+  def find(request)
+    model.new(request.key)
+  end
+
+  def search(request)
+    raise Puppet::DevError, "You cannot search for instrumentation data"
+  end
+
+  def save(request)
+    raise Puppet::DevError, "You cannot save instrumentation data"
+  end
+
+  def destroy(request)
+    raise Puppet::DevError, "You cannot remove instrumentation data"
+  end
+end
diff --git a/lib/puppet/indirector/instrumentation_data/rest.rb b/lib/puppet/indirector/instrumentation_data/rest.rb
new file mode 100644
index 0000000..28b2117
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_data/rest.rb
@@ -0,0 +1,5 @@
+require 'puppet/indirector/rest'
+require 'puppet/indirector/instrumentation_data'
+
+class Puppet::Indirector::InstrumentationData::Rest < Puppet::Indirector::REST
+end
diff --git a/lib/puppet/indirector/instrumentation_listener.rb b/lib/puppet/indirector/instrumentation_listener.rb
new file mode 100644
index 0000000..6aaa71c
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_listener.rb
@@ -0,0 +1,3 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::InstrumentationListener
+end
diff --git a/lib/puppet/indirector/instrumentation_listener/local.rb b/lib/puppet/indirector/instrumentation_listener/local.rb
new file mode 100644
index 0000000..7257801
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_listener/local.rb
@@ -0,0 +1,23 @@
+require 'puppet/indirector/instrumentation_listener'
+
+class Puppet::Indirector::InstrumentationListener::Local < Puppet::Indirector::Code
+  def find(request)
+    Puppet::Util::Instrumentation[request.key]
+  end
+
+  def search(request)
+    Puppet::Util::Instrumentation.listeners
+  end
+
+  def save(request)
+    res = request.instance
+    Puppet::Util::Instrumentation[res.name] = res
+    nil # don't leak the listener
+  end
+
+  def destroy(request)
+    listener = Puppet::Util::Instrumentation[request.key]
+    raise "Listener #{request.key} hasn't been subscribed" unless listener
+    Puppet::Util::Instrumentation.unsubscribe(listener)
+  end
+end
diff --git a/lib/puppet/indirector/instrumentation_listener/rest.rb b/lib/puppet/indirector/instrumentation_listener/rest.rb
new file mode 100644
index 0000000..0bc8122
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_listener/rest.rb
@@ -0,0 +1,5 @@
+require 'puppet/indirector/instrumentation_listener'
+require 'puppet/indirector/rest'
+
+class Puppet::Indirector::InstrumentationListener::Rest < Puppet::Indirector::REST
+end
diff --git a/lib/puppet/indirector/instrumentation_probe.rb b/lib/puppet/indirector/instrumentation_probe.rb
new file mode 100644
index 0000000..3e51444
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_probe.rb
@@ -0,0 +1,3 @@
+# A stub class, so our constants work.
+class Puppet::Indirector::InstrumentationProbe
+end
diff --git a/lib/puppet/indirector/instrumentation_probe/local.rb b/lib/puppet/indirector/instrumentation_probe/local.rb
new file mode 100644
index 0000000..dd0a3f7
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_probe/local.rb
@@ -0,0 +1,24 @@
+require 'puppet/indirector/instrumentation_probe'
+require 'puppet/indirector/code'
+require 'puppet/util/instrumentation/indirection_probe'
+
+class Puppet::Indirector::InstrumentationProbe::Local < Puppet::Indirector::Code
+  def find(request)
+  end
+
+  def search(request)
+    probes = []
+    Puppet::Util::Instrumentation::Instrumentable.each_probe do |probe|
+      probes << Puppet::Util::Instrumentation::IndirectionProbe.new("#{probe.klass}.#{probe.method}")
+    end
+    probes
+  end
+
+  def save(request)
+    Puppet::Util::Instrumentation::Instrumentable.enable_probes
+  end
+
+  def destroy(request)
+    Puppet::Util::Instrumentation::Instrumentable.disable_probes
+  end
+end
diff --git a/lib/puppet/indirector/instrumentation_probe/rest.rb b/lib/puppet/indirector/instrumentation_probe/rest.rb
new file mode 100644
index 0000000..57e6fcf
--- /dev/null
+++ b/lib/puppet/indirector/instrumentation_probe/rest.rb
@@ -0,0 +1,5 @@
+require 'puppet/indirector/rest'
+require 'puppet/indirector/instrumentation_probe'
+
+class Puppet::Indirector::InstrumentationProbe::Rest < Puppet::Indirector::REST
+end
diff --git a/lib/puppet/indirector/report/rest.rb b/lib/puppet/indirector/report/rest.rb
index 601da9e..a40a9f8 100644
--- a/lib/puppet/indirector/report/rest.rb
+++ b/lib/puppet/indirector/report/rest.rb
@@ -4,4 +4,5 @@ class Puppet::Transaction::Report::Rest < Puppet::Indirector::REST
   desc "Get server report over HTTP via REST."
   use_server_setting(:report_server)
   use_port_setting(:report_port)
+  use_srv_service(:report)
 end
diff --git a/lib/puppet/indirector/request.rb b/lib/puppet/indirector/request.rb
index b6b69ea..98b79f9 100644
--- a/lib/puppet/indirector/request.rb
+++ b/lib/puppet/indirector/request.rb
@@ -1,6 +1,8 @@
 require 'cgi'
 require 'uri'
 require 'puppet/indirector'
+require 'puppet/util/pson'
+require 'puppet/network/resolver'
 
 # This class encapsulates all of the information you need to make an
 # Indirection call, and as a a result also handles REST calls.  It's somewhat
@@ -14,6 +16,54 @@ class Puppet::Indirector::Request
 
   OPTION_ATTRIBUTES = [:ip, :node, :authenticated, :ignore_terminus, :ignore_cache, :instance, :environment]
 
+  # Load json before trying to register.
+  Puppet.features.pson? and ::PSON.register_document_type('IndirectorRequest',self)
+
+  def self.from_pson(json)
+    raise ArgumentError, "No indirection name provided in json data" unless indirection_name = json['type']
+    raise ArgumentError, "No method name provided in json data" unless method = json['method']
+    raise ArgumentError, "No key provided in json data" unless key = json['key']
+
+    request = new(indirection_name, method, key, json['attributes'])
+
+    if instance = json['instance']
+      klass = Puppet::Indirector::Indirection.instance(request.indirection_name).model
+      if instance.is_a?(klass)
+        request.instance = instance
+      else
+        request.instance = klass.from_pson(instance)
+      end
+    end
+
+    request
+  end
+
+  def to_pson(*args)
+    result = {
+      'document_type' => 'IndirectorRequest',
+      'data' => {
+        'type' => indirection_name,
+        'method' => method,
+        'key' => key
+      }
+    }
+    data = result['data']
+    attributes = {}
+    OPTION_ATTRIBUTES.each do |key|
+      next unless value = send(key)
+      attributes[key] = value
+    end
+
+    options.each do |opt, value|
+      attributes[opt] = value
+    end
+
+    data['attributes'] = attributes unless attributes.empty?
+    data['instance'] = instance if instance
+
+    result.to_pson(*args)
+  end
+
   # Is this an authenticated request?
   def authenticated?
     # Double negative, so we just get true or false
@@ -61,9 +111,11 @@ def initialize(indirection_name, method, key_or_instance, options_or_instance =
     self.indirection_name = indirection_name
     self.method = method
 
+    options = options.inject({}) { |hash, ary| hash[ary[0].to_sym] = ary[1]; hash }
+
     set_attributes(options)
 
-    @options = options.inject({}) { |hash, ary| hash[ary[0].to_sym] = ary[1]; hash }
+    @options = options
 
     if key_or_instance.is_a?(String) || key_or_instance.is_a?(Symbol)
       key = key_or_instance
@@ -150,11 +202,36 @@ def to_s
     return(uri ? uri : "/#{indirection_name}/#{key}")
   end
 
+  def do_request(srv_service=:puppet, default_server=Puppet.settings[:server], default_port=Puppet.settings[:masterport], &block)
+    # We were given a specific server to use, so just use that one.
+    # This happens if someone does something like specifying a file
+    # source using a puppet:// URI with a specific server.
+    return yield self if !self.server.nil?
+
+    if Puppet.settings[:use_srv_records]
+      Puppet::Network::Resolver.each_srv_record(Puppet.settings[:srv_domain], srv_service) do |srv_server, srv_port|
+        begin
+          self.server = srv_server
+          self.port   = srv_port
+          return yield self
+        rescue SystemCallError => e
+          Puppet.warning "Error connecting to #{srv_server}:#{srv_port}: #{e.message}"
+        end
+      end
+    end
+
+    # ... Fall back onto the default server.
+    Puppet.debug "No more servers left, falling back to #{default_server}:#{default_port}" if Puppet.settings[:use_srv_records]
+    self.server = default_server
+    self.port   = default_port
+    return yield self
+  end
+
   private
 
   def set_attributes(options)
     OPTION_ATTRIBUTES.each do |attribute|
-      if options.include?(attribute)
+      if options.include?(attribute.to_sym)
         send(attribute.to_s + "=", options[attribute])
         options.delete(attribute)
       end
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index c8a45d7..6e5725f 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -19,15 +19,24 @@ def self.use_server_setting(setting)
     @server_setting = setting
   end
 
-  def self.server
-    Puppet.settings[server_setting || :server]
-  end
-
   # Specify the setting that we should use to get the port.
   def self.use_port_setting(setting)
     @port_setting = setting
   end
 
+  # Specify the service to use when doing SRV record lookup
+  def self.use_srv_service(service)
+    @srv_service = service
+  end
+
+  def self.srv_service
+    @srv_service || :puppet
+  end
+
+  def self.server
+    Puppet.settings[server_setting || :server]
+  end
+
   def self.port
     Puppet.settings[port_setting || :masterport].to_i
   end
@@ -110,20 +119,29 @@ def http_request(method, request, *args)
   def find(request)
     uri, body = request_to_uri_and_body(request)
     uri_with_query_string = "#{uri}?#{body}"
-    # WEBrick in Ruby 1.9.1 only supports up to 1024 character lines in an HTTP request
-    # http://redmine.ruby-lang.org/issues/show/3991
-    response = if "GET #{uri_with_query_string} HTTP/1.1\r\n".length > 1024
-      http_post(request, uri, body, headers)
-    else
-      http_get(request, uri_with_query_string, headers)
+
+    response = request.do_request(self.class.srv_service, self.class.server, self.class.port) do |request|
+      # WEBrick in Ruby 1.9.1 only supports up to 1024 character lines in an HTTP request
+      # http://redmine.ruby-lang.org/issues/show/3991
+      if "GET #{uri_with_query_string} HTTP/1.1\r\n".length > 1024
+        http_post(request, uri, body, headers)
+      else
+        http_get(request, uri_with_query_string, headers)
+      end
     end
-    result = deserialize response
+    result = deserialize(response)
+
+    return nil unless result
+
     result.name = request.key if result.respond_to?(:name=)
     result
   end
 
   def head(request)
-    response = http_head(request, indirection2uri(request), headers)
+    response = request.do_request(self.class.srv_service, self.class.server, self.class.port) do |request|
+      http_head(request, indirection2uri(request), headers)
+    end
+
     case response.code
     when "404"
       return false
@@ -136,20 +154,28 @@ def head(request)
   end
 
   def search(request)
-    unless result = deserialize(http_get(request, indirection2uri(request), headers), true)
-      return []
+    result = request.do_request(self.class.srv_service, self.class.server, self.class.port) do |request|
+      deserialize(http_get(request, indirection2uri(request), headers), true)
     end
-    result
+
+    # result from the server can be nil, but we promise to return an array...
+    result || []
   end
 
   def destroy(request)
     raise ArgumentError, "DELETE does not accept options" unless request.options.empty?
-    deserialize http_delete(request, indirection2uri(request), headers)
+
+    request.do_request(self.class.srv_service, self.class.server, self.class.port) do |request|
+      return deserialize(http_delete(request, indirection2uri(request), headers))
+    end
   end
 
   def save(request)
     raise ArgumentError, "PUT does not accept options" unless request.options.empty?
-    deserialize http_put(request, indirection2uri(request), request.instance.render, headers.merge({ "Content-Type" => request.instance.mime }))
+
+    request.do_request(self.class.srv_service, self.class.server, self.class.port) do |request|
+      deserialize http_put(request, indirection2uri(request), request.instance.render, headers.merge({ "Content-Type" => request.instance.mime }))
+    end
   end
 
   private
diff --git a/lib/puppet/module.rb b/lib/puppet/module.rb
index 00468df..6f84e07 100644
--- a/lib/puppet/module.rb
+++ b/lib/puppet/module.rb
@@ -99,11 +99,6 @@ def exist?
     ! path.nil?
   end
 
-  # Find the first 'files' directory.  This is used by the XMLRPC fileserver.
-  def file_directory
-    subpath("files")
-  end
-
   def license_file
     return @license_file if defined?(@license_file)
 
diff --git a/lib/puppet/module_tool.rb b/lib/puppet/module_tool.rb
new file mode 100644
index 0000000..c11fd58
--- /dev/null
+++ b/lib/puppet/module_tool.rb
@@ -0,0 +1,97 @@
+# Load standard libraries
+require 'pathname'
+require 'fileutils'
+require 'puppet/module_tool/utils'
+
+# Define tool
+module Puppet
+  class Module
+    module Tool
+
+      # Directory names that should not be checksummed.
+      ARTIFACTS = ['pkg', /^\./, /^~/, /^#/, 'coverage']
+      FULL_MODULE_NAME_PATTERN = /\A([^-\/|.]+)[-|\/](.+)\z/
+      REPOSITORY_URL = Puppet.settings[:module_repository]
+
+      # Is this a directory that shouldn't be checksummed?
+      #
+      # TODO: Should this be part of Checksums?
+      # TODO: Rename this method to reflect it's purpose?
+      # TODO: Shouldn't this be used when building packages too?
+      def self.artifact?(path)
+        case File.basename(path)
+        when *ARTIFACTS
+          true
+        else
+          false
+        end
+      end
+
+      # Return the +username+ and +modname+ for a given +full_module_name+, or raise an
+      # ArgumentError if the argument isn't parseable.
+      def self.username_and_modname_from(full_module_name)
+        if matcher = full_module_name.match(FULL_MODULE_NAME_PATTERN)
+          return matcher.captures
+        else
+          raise ArgumentError, "Not a valid full name: #{full_module_name}"
+        end
+      end
+
+      # Read HTTP proxy configurationm from Puppet's config file, or the
+      # http_proxy environment variable.
+      def self.http_proxy_env
+        proxy_env = ENV["http_proxy"] || ENV["HTTP_PROXY"] || nil
+        begin
+          return URI.parse(proxy_env) if proxy_env
+        rescue URI::InvalidURIError
+          return nil
+        end
+        return nil
+      end
+
+      def self.http_proxy_host
+        env = http_proxy_env
+
+        if env and env.host then
+          return env.host
+        end
+
+        if Puppet.settings[:http_proxy_host] == 'none'
+          return nil
+        end
+
+        return Puppet.settings[:http_proxy_host]
+      end
+
+      def self.http_proxy_port
+        env = http_proxy_env
+
+        if env and env.port then
+          return env.port
+        end
+
+        return Puppet.settings[:http_proxy_port]
+      end
+
+      def self.find_module_root(path)
+        for dir in [path, Dir.pwd].compact
+          if File.exist?(File.join(dir, 'Modulefile'))
+            return dir
+          end
+        end
+        raise ArgumentError, "Could not find a valid module at #{path ? path.inspect : 'current directory'}"
+      end
+    end
+  end
+end
+
+# Load remaining libraries
+require 'puppet/module_tool/applications'
+require 'puppet/module_tool/cache'
+require 'puppet/module_tool/checksums'
+require 'puppet/module_tool/contents_description'
+require 'puppet/module_tool/dependency'
+require 'puppet/module_tool/metadata'
+require 'puppet/module_tool/modulefile'
+require 'puppet/module_tool/repository'
+require 'puppet/module_tool/skeleton'
diff --git a/lib/puppet/module_tool/applications.rb b/lib/puppet/module_tool/applications.rb
new file mode 100644
index 0000000..e7d54dc
--- /dev/null
+++ b/lib/puppet/module_tool/applications.rb
@@ -0,0 +1,12 @@
+module Puppet::Module::Tool
+  module Applications
+    require 'puppet/module_tool/applications/application'
+    require 'puppet/module_tool/applications/builder'
+    require 'puppet/module_tool/applications/checksummer'
+    require 'puppet/module_tool/applications/cleaner'
+    require 'puppet/module_tool/applications/generator'
+    require 'puppet/module_tool/applications/installer'
+    require 'puppet/module_tool/applications/searcher'
+    require 'puppet/module_tool/applications/unpacker'
+  end
+end
diff --git a/lib/puppet/module_tool/applications/application.rb b/lib/puppet/module_tool/applications/application.rb
new file mode 100644
index 0000000..5f8c0c4
--- /dev/null
+++ b/lib/puppet/module_tool/applications/application.rb
@@ -0,0 +1,83 @@
+require 'net/http'
+require 'semver'
+
+module Puppet::Module::Tool
+  module Applications
+    class Application
+      include Utils::Interrogation
+
+      def self.run(*args)
+        new(*args).run
+      end
+
+      attr_accessor :options
+
+      def initialize(options = {})
+        @options = options
+      end
+
+      def repository
+        @repository ||= Repository.new(@options[:module_repository])
+      end
+
+      def run
+        raise NotImplementedError, "Should be implemented in child classes."
+      end
+
+      def discuss(response, success, failure)
+        case response
+        when Net::HTTPOK, Net::HTTPCreated
+          Puppet.notice success
+        else
+          errors = PSON.parse(response.body)['error'] rescue "HTTP #{response.code}, #{response.body}"
+          Puppet.warning "#{failure} (#{errors})"
+        end
+      end
+
+      def metadata(require_modulefile = false)
+        unless @metadata
+          unless @path
+            raise ArgumentError, "Could not determine module path"
+          end
+          @metadata = Puppet::Module::Tool::Metadata.new
+          contents = ContentsDescription.new(@path)
+          contents.annotate(@metadata)
+          checksums = Checksums.new(@path)
+          checksums.annotate(@metadata)
+          modulefile_path = File.join(@path, 'Modulefile')
+          if File.file?(modulefile_path)
+            Puppet::Module::Tool::ModulefileReader.evaluate(@metadata, modulefile_path)
+          elsif require_modulefile
+            raise ArgumentError, "No Modulefile found."
+          end
+        end
+        @metadata
+      end
+
+      def load_modulefile!
+        @metadata = nil
+        metadata(true)
+      end
+
+      # Use to extract and validate a module name and version from a
+      # filename
+      # Note: Must have @filename set to use this
+      def parse_filename!
+        @release_name = File.basename(@filename,'.tar.gz')
+        match = /^(.*?)-(.*?)-(\d+\.\d+\.\d+.*?)$/.match(@release_name)
+        if match then
+          @username, @module_name, @version = match.captures
+        else
+          raise ArgumentError, "Could not parse filename to obtain the username, module name and version.  (#{@release_name})"
+        end
+        @full_module_name = [@username, @module_name].join('-')
+        unless @username && @module_name
+          raise ArgumentError, "Username and Module name not provided"
+        end
+        unless SemVer.valid?(@version)
+          raise ArgumentError, "Invalid version format: #{@version} (Semantic Versions are acceptable: http://semver.org)"
+        end
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/applications/builder.rb b/lib/puppet/module_tool/applications/builder.rb
new file mode 100644
index 0000000..322020a
--- /dev/null
+++ b/lib/puppet/module_tool/applications/builder.rb
@@ -0,0 +1,91 @@
+require 'fileutils'
+
+module Puppet::Module::Tool
+  module Applications
+    class Builder < Application
+
+      def initialize(path, options = {})
+        @path = File.expand_path(Puppet::Module::Tool.find_module_root(path))
+        @pkg_path = File.join(@path, 'pkg')
+        super(options)
+      end
+
+      def run
+        load_modulefile!
+        create_directory
+        copy_contents
+        add_metadata
+        Puppet.notice "Building #{@path} for release"
+        tar
+        gzip
+        relative = Pathname.new(File.join(@pkg_path, filename('tar.gz'))).relative_path_from(Pathname.new(Dir.pwd))
+
+        # Return the Pathname object representing the path to the release
+        # archive just created. This return value is used by the module_tool
+        # face build action, and displayed to on the console using the to_s
+        # method.
+        #
+        # Example return value:
+        #
+        #   <Pathname:puppetlabs-apache/pkg/puppetlabs-apache-0.0.1.tar.gz>
+        #
+        relative
+      end
+
+      private
+
+      def filename(ext)
+        ext.sub!(/^\./, '')
+        "#{metadata.release_name}.#{ext}"
+      end
+
+      def tar
+        tar_name = filename('tar')
+        Dir.chdir(@pkg_path) do
+          FileUtils.rm tar_name rescue nil
+          unless system "tar -cf #{tar_name} #{metadata.release_name}"
+            raise RuntimeError, "Could not create #{tar_name}"
+          end
+        end
+      end
+
+      def gzip
+        Dir.chdir(@pkg_path) do
+          FileUtils.rm filename('tar.gz') rescue nil
+          unless system "gzip #{filename('tar')}"
+            raise RuntimeError, "Could not compress #{filename('tar')}"
+          end
+        end
+      end
+
+      def create_directory
+        FileUtils.mkdir(@pkg_path) rescue nil
+        if File.directory?(build_path)
+          FileUtils.rm_rf(build_path)
+        end
+        FileUtils.mkdir(build_path)
+      end
+
+      def copy_contents
+        Dir[File.join(@path, '*')].each do |path|
+          case File.basename(path)
+          when *Puppet::Module::Tool::ARTIFACTS
+            next
+          else
+            FileUtils.cp_r path, build_path
+          end
+        end
+      end
+
+      def add_metadata
+        File.open(File.join(build_path, 'metadata.json'), 'w') do |f|
+          f.write(PSON.pretty_generate(metadata))
+        end
+      end
+
+      def build_path
+        @build_path ||= File.join(@pkg_path, metadata.release_name)
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/applications/checksummer.rb b/lib/puppet/module_tool/applications/checksummer.rb
new file mode 100644
index 0000000..2ea1ef5
--- /dev/null
+++ b/lib/puppet/module_tool/applications/checksummer.rb
@@ -0,0 +1,47 @@
+module Puppet::Module::Tool
+  module Applications
+    class Checksummer < Application
+
+      def initialize(path, options = {})
+        @path = Pathname.new(path)
+        super(options)
+      end
+
+      def run
+        changes = []
+        if metadata_file.exist?
+          sums = Checksums.new(@path)
+          (metadata['checksums'] || {}).each do |child_path, canonical_checksum|
+            path = @path + child_path
+            if canonical_checksum != sums.checksum(path)
+              changes << child_path
+            end
+          end
+        else
+          raise ArgumentError, "No metadata.json found."
+        end
+
+        # Return an Array of strings representing file paths of files that have
+        # been modified since this module was installed. All paths are relative
+        # to the installed module directory. This return value is used by the
+        # module_tool face changes action, and displayed on the console.
+        #
+        # Example return value:
+        #
+        #   [ "REVISION", "metadata.json", "manifests/init.pp"]
+        #
+        changes
+      end
+
+      private
+
+      def metadata
+        PSON.parse(metadata_file.read)
+      end
+
+      def metadata_file
+        (@path + 'metadata.json')
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/applications/cleaner.rb b/lib/puppet/module_tool/applications/cleaner.rb
new file mode 100644
index 0000000..c42687f
--- /dev/null
+++ b/lib/puppet/module_tool/applications/cleaner.rb
@@ -0,0 +1,16 @@
+module Puppet::Module::Tool
+  module Applications
+    class Cleaner < Application
+      def run
+        Puppet::Module::Tool::Cache.clean
+
+        # Return a status Hash containing the status of the clean command
+        # and a status message. This return value is used by the module_tool
+        # face clean action, and the status message, return_value[:msg], is
+        # displayed on the console.
+        #
+        { :status => "success", :msg => "Cleaned module cache." }
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/applications/generator.rb b/lib/puppet/module_tool/applications/generator.rb
new file mode 100644
index 0000000..699fe24
--- /dev/null
+++ b/lib/puppet/module_tool/applications/generator.rb
@@ -0,0 +1,141 @@
+require 'pathname'
+require 'fileutils'
+require 'erb'
+
+module Puppet::Module::Tool
+  module Applications
+    class Generator < Application
+
+      def initialize(full_module_name, options = {})
+        begin
+          @metadata = Metadata.new(:full_module_name => full_module_name)
+        rescue ArgumentError
+          raise "Could not generate directory #{full_module_name.inspect}, you must specify a dash-separated username and module name."
+        end
+        super(options)
+      end
+
+      def skeleton
+        @skeleton ||= Skeleton.new
+      end
+
+      def get_binding
+        binding
+      end
+
+      def run
+        if destination.directory?
+          raise ArgumentError, "#{destination} already exists."
+        end
+        Puppet.notice "Generating module at #{Dir.pwd}/#{@metadata.dashed_name}"
+        files_created = []
+        skeleton.path.find do |path|
+          if path == skeleton
+            destination.mkpath
+          else
+            node = Node.on(path, self)
+            if node
+              node.install!
+              files_created << node.target
+            else
+              Puppet.notice "Could not generate from #{path}"
+            end
+          end
+        end
+
+        # Return an array of Pathname objects representing file paths of files
+        # and directories just generated. This return value is used by the
+        # module_tool face generate action, and displayed on the console.
+        #
+        # Example return value:
+        #
+        #   [
+        #     #<Pathname:puppetlabs-apache>,
+        #     #<Pathname:puppetlabs-apache/tests>,
+        #     #<Pathname:puppetlabs-apache/tests/init.pp>,
+        #     #<Pathname:puppetlabs-apache/spec>,
+        #     #<Pathname:puppetlabs-apache/spec/spec_helper.rb>,
+        #     #<Pathname:puppetlabs-apache/spec/spec.opts>,
+        #     #<Pathname:puppetlabs-apache/README>,
+        #     #<Pathname:puppetlabs-apache/Modulefile>,
+        #     #<Pathname:puppetlabs-apache/metadata.json>,
+        #     #<Pathname:puppetlabs-apache/manifests>,
+        #     #<Pathname:puppetlabs-apache/manifests/init.pp"
+        #   ]
+        #
+        files_created
+      end
+
+      def destination
+        @destination ||= Pathname.new(@metadata.dashed_name)
+      end
+
+      class Node
+        def self.types
+          @types ||= []
+        end
+        def self.inherited(klass)
+          types << klass
+        end
+        def self.on(path, generator)
+          klass = types.detect { |t| t.matches?(path) }
+          if klass
+            klass.new(path, generator)
+          end
+        end
+        def initialize(source, generator)
+          @generator = generator
+          @source = source
+        end
+        def read
+          @source.read
+        end
+        def target
+          target = @generator.destination + @source.relative_path_from(@generator.skeleton.path)
+          components = target.to_s.split(File::SEPARATOR).map do |part|
+            part == 'NAME' ? @generator.metadata.name : part
+          end
+          Pathname.new(components.join(File::SEPARATOR))
+        end
+        def install!
+          raise NotImplementedError, "Abstract"
+        end
+      end
+
+      class DirectoryNode < Node
+        def self.matches?(path)
+          path.directory?
+        end
+        def install!
+          target.mkpath
+        end
+      end
+
+      class ParsedFileNode < Node
+        def self.matches?(path)
+          path.file? && path.extname == '.erb'
+        end
+        def target
+          path = super
+          path.parent + path.basename('.erb')
+        end
+        def contents
+          template = ERB.new(read)
+          template.result(@generator.send(:get_binding))
+        end
+        def install!
+          target.open('w') { |f| f.write contents }
+        end
+      end
+
+      class FileNode < Node
+        def self.matches?(path)
+          path.file?
+        end
+        def install!
+          FileUtils.cp(@source, target)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/applications/installer.rb b/lib/puppet/module_tool/applications/installer.rb
new file mode 100644
index 0000000..ad423bd
--- /dev/null
+++ b/lib/puppet/module_tool/applications/installer.rb
@@ -0,0 +1,89 @@
+require 'open-uri'
+require 'pathname'
+require 'tmpdir'
+
+module Puppet::Module::Tool
+  module Applications
+    class Installer < Application
+
+      def initialize(name, options = {})
+        if File.exist?(name)
+          if File.directory?(name)
+            # TODO Unify this handling with that of Unpacker#check_clobber!
+            raise ArgumentError, "Module already installed: #{name}"
+          end
+          @source = :filesystem
+          @filename = File.expand_path(name)
+          parse_filename!
+        else
+          @source = :repository
+          begin
+            @username, @module_name = Puppet::Module::Tool::username_and_modname_from(name)
+          rescue ArgumentError
+            raise "Could not install module with invalid name: #{name}"
+          end
+          @version_requirement = options[:version]
+        end
+        super(options)
+      end
+
+      def force?
+        options[:force]
+      end
+
+      def run
+        case @source
+        when :repository
+          if match['file']
+            begin
+              cache_path = repository.retrieve(match['file'])
+            rescue OpenURI::HTTPError => e
+              raise RuntimeError, "Could not install module: #{e.message}"
+            end
+            module_dir = Unpacker.run(cache_path, options)
+          else
+            raise RuntimeError, "Malformed response from module repository."
+          end
+        when :filesystem
+          repository = Repository.new('file:///')
+          uri = URI.parse("file://#{URI.escape(File.expand_path(@filename))}")
+          cache_path = repository.retrieve(uri)
+          module_dir = Unpacker.run(cache_path, options)
+        else
+          raise ArgumentError, "Could not determine installation source"
+        end
+
+        # Return the Pathname object representing the path to the installed
+        # module. This return value is used by the module_tool face install
+        # action, and displayed to on the console.
+        #
+        # Example return value:
+        #
+        #   "/etc/puppet/modules/apache"
+        #
+        module_dir
+      end
+
+      private
+
+      def match
+        return @match ||= begin
+          url = repository.uri + "/users/#{@username}/modules/#{@module_name}/releases/find.json"
+          if @version_requirement
+            url.query = "version=#{URI.escape(@version_requirement)}"
+          end
+          begin
+            raw_result = read_match(url)
+          rescue => e
+            raise ArgumentError, "Could not find a release for this module (#{e.message})"
+          end
+          @match = PSON.parse(raw_result)
+        end
+      end
+
+      def read_match(url)
+        return url.read
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/applications/searcher.rb b/lib/puppet/module_tool/applications/searcher.rb
new file mode 100644
index 0000000..0a2267b
--- /dev/null
+++ b/lib/puppet/module_tool/applications/searcher.rb
@@ -0,0 +1,40 @@
+module Puppet::Module::Tool
+  module Applications
+    class Searcher < Application
+
+      def initialize(term, options = {})
+        @term = term
+        super(options)
+      end
+
+      def run
+        request = Net::HTTP::Get.new("/modules.json?q=#{URI.escape(@term)}")
+        response = repository.make_http_request(request)
+        case response
+        when Net::HTTPOK
+          matches = PSON.parse(response.body)
+        else
+          raise RuntimeError, "Could not execute search (HTTP #{response.code})"
+          matches = []
+        end
+
+        # Return a list of module metadata hashes that match the search query.
+        # This return value is used by the module_tool face install search,
+        # and displayed to on the console.
+        #
+        # Example return value:
+        #
+        # [
+        #   {
+        #     "name"        => "nginx",
+        #     "project_url" => "http://github.com/puppetlabs/puppetlabs-nginx",
+        #     "version"     => "0.0.1",
+        #     "full_name"   => "puppetlabs/nginx" # full_name comes back from
+        #   }                                     # API all to the forge.
+        # ]
+        #
+        matches
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/applications/unpacker.rb b/lib/puppet/module_tool/applications/unpacker.rb
new file mode 100644
index 0000000..6dd1fca
--- /dev/null
+++ b/lib/puppet/module_tool/applications/unpacker.rb
@@ -0,0 +1,70 @@
+require 'pathname'
+require 'tmpdir'
+
+module Puppet::Module::Tool
+  module Applications
+    class Unpacker < Application
+
+      def initialize(filename, options = {})
+        @filename = Pathname.new(filename)
+        parse_filename!
+        super(options)
+        @module_dir = Pathname.new(options[:install_dir]) + @module_name
+      end
+
+      def run
+        extract_module_to_install_dir
+        tag_revision
+
+        # Return the Pathname object representing the directory where the
+        # module release archive was unpacked the to, and the module release
+        # name.
+        @module_dir
+      end
+
+      private
+
+      def tag_revision
+        File.open("#{@module_dir}/REVISION", 'w') do |f|
+          f.puts "module: #{@username}/#{@module_name}"
+          f.puts "version: #{@version}"
+          f.puts "url: file://#{@filename.expand_path}"
+          f.puts "installed: #{Time.now}"
+        end
+      end
+
+      def extract_module_to_install_dir
+        delete_existing_installation_or_abort!
+
+        build_dir = Puppet::Module::Tool::Cache.base_path + "tmp-unpacker-#{Digest::SHA1.hexdigest(@filename.basename.to_s)}"
+        build_dir.mkpath
+        begin
+          Puppet.notice "Installing #{@filename.basename} to #{@module_dir.expand_path}"
+          unless system "tar xzf #{@filename} -C #{build_dir}"
+            raise RuntimeError, "Could not extract contents of module archive."
+          end
+          # grab the first directory
+          extracted = build_dir.children.detect { |c| c.directory? }
+          FileUtils.mv extracted, @module_dir
+        ensure
+          build_dir.rmtree
+        end
+      end
+
+      def delete_existing_installation_or_abort!
+        return unless @module_dir.exist?
+
+        if !options[:force]
+          Puppet.warning "Existing module '#{@module_dir.expand_path}' found"
+          response = prompt "Overwrite module installed at #{@module_dir.expand_path}? [y/N]"
+          unless response =~ /y/i
+            raise RuntimeError, "Aborted installation."
+          end
+        end
+
+        Puppet.warning "Deleting #{@module_dir.expand_path}"
+        FileUtils.rm_rf @module_dir
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/cache.rb b/lib/puppet/module_tool/cache.rb
new file mode 100644
index 0000000..b254780
--- /dev/null
+++ b/lib/puppet/module_tool/cache.rb
@@ -0,0 +1,56 @@
+require 'uri'
+
+module Puppet::Module::Tool
+
+  # = Cache
+  #
+  # Provides methods for reading files from local cache, filesystem or network.
+  class Cache
+
+    # Instantiate new cahe for the +repositry+ instance.
+    def initialize(repository, options = {})
+      @repository = repository
+      @options = options
+    end
+
+    # Return filename retrieved from +uri+ instance. Will download this file and
+    # cache it if needed.
+    #
+    # TODO: Add checksum support.
+    # TODO: Add error checking.
+    def retrieve(url)
+      (path + File.basename(url.to_s)).tap do |cached_file|
+        uri = url.is_a?(::URI) ? url : ::URI.parse(url)
+        unless cached_file.file?
+          if uri.scheme == 'file'
+            FileUtils.cp(URI.unescape(uri.path), cached_file)
+          else
+            # TODO: Handle HTTPS; probably should use repository.contact
+            data = read_retrieve(uri)
+            cached_file.open('wb') { |f| f.write data }
+          end
+        end
+      end
+    end
+
+    # Return contents of file at the given URI's +uri+.
+    def read_retrieve(uri)
+      return uri.read
+    end
+
+    # Return Pathname for repository's cache directory, create it if needed.
+    def path
+      return @path ||= (self.class.base_path + @repository.cache_key).tap{ |o| o.mkpath }
+    end
+
+    # Return the base Pathname for all the caches.
+    def self.base_path
+      Pathname(Puppet.settings[:module_working_dir]) + 'cache'
+    end
+
+    # Clean out all the caches.
+    def self.clean
+      base_path.rmtree if base_path.exist?
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/checksums.rb b/lib/puppet/module_tool/checksums.rb
new file mode 100644
index 0000000..a566090
--- /dev/null
+++ b/lib/puppet/module_tool/checksums.rb
@@ -0,0 +1,52 @@
+require 'digest/md5'
+
+module Puppet::Module::Tool
+
+  # = Checksums
+  #
+  # This class proides methods for generating checksums for data and adding
+  # them to +Metadata+.
+  class Checksums
+    include Enumerable
+
+    # Instantiate object with string +path+ to create checksums from.
+    def initialize(path)
+      @path = Pathname.new(path)
+    end
+
+    # Return checksum for the +Pathname+.
+    def checksum(pathname)
+      return Digest::MD5.hexdigest(pathname.read)
+    end
+
+    # Return checksums for object's +Pathname+, generate if it's needed.
+    # Result is a hash of path strings to checksum strings.
+    def data
+      unless @data
+        @data = {}
+        @path.find do |descendant|
+          if Puppet::Module::Tool.artifact?(descendant)
+            Find.prune
+          elsif descendant.file?
+            path = descendant.relative_path_from(@path)
+            @data[path.to_s] = checksum(descendant)
+          end
+        end
+      end
+      return @data
+    end
+
+    # TODO: Why?
+    def each(&block)
+      data.each(&block)
+    end
+
+    # Update +Metadata+'s checksums with this object's.
+    def annotate(metadata)
+      metadata.checksums.replace(data)
+    end
+
+    # TODO: Move the Checksummer#run checksum checking to here?
+
+  end
+end
diff --git a/lib/puppet/module_tool/contents_description.rb b/lib/puppet/module_tool/contents_description.rb
new file mode 100644
index 0000000..f6a94e2
--- /dev/null
+++ b/lib/puppet/module_tool/contents_description.rb
@@ -0,0 +1,82 @@
+module Puppet::Module::Tool
+
+  # = ContentsDescription
+  #
+  # This class populates +Metadata+'s Puppet type information.
+  class ContentsDescription
+
+    # Instantiate object for string +module_path+.
+    def initialize(module_path)
+      @module_path = module_path
+    end
+
+    # Update +Metadata+'s Puppet type information.
+    def annotate(metadata)
+      metadata.types.replace data.clone
+    end
+
+    # Return types for this module. Result is an array of hashes, each of which
+    # describes a Puppet type. The type description hash structure is:
+    # * :name => Name of this Puppet type.
+    # * :doc => Documentation for this type.
+    # * :properties => Array of hashes representing the type's properties, each
+    #   containing :name and :doc.
+    # * :parameters => Array of hashes representing the type's parameters, each
+    #   containing :name and :doc.
+    # * :providers => Array of hashes representing the types providers, each
+    #   containing :name and :doc.
+    # TODO Write a TypeDescription to encapsulate these structures and logic?
+    def data
+      unless @data
+        @data = []
+        type_names = []
+        for module_filename in Dir[File.join(@module_path, "lib/puppet/type/*.rb")]
+          require module_filename
+          type_name = File.basename(module_filename, ".rb")
+          type_names << type_name
+
+          for provider_filename in Dir[File.join(@module_path, "lib/puppet/provider/#{type_name}/*.rb")]
+            require provider_filename
+          end
+        end
+
+        type_names.each do |type_name|
+          if type = Puppet::Type.type(type_name.to_sym)
+            type_hash = {:name => type_name, :doc => type.doc}
+            type_hash[:properties] = attr_doc(type, :property)
+            type_hash[:parameters] = attr_doc(type, :param)
+            if type.providers.size > 0
+              type_hash[:providers] = provider_doc(type)
+            end
+            @data << type_hash
+          else
+            Puppet.warning "Could not find/load type: #{type_name}"
+          end
+        end
+      end
+      @data
+    end
+
+    # Return an array of hashes representing this +type+'s attrs of +kind+
+    # (e.g. :param or :property), each containing :name and :doc.
+    def attr_doc(type, kind)
+      [].tap do |attrs|
+        type.allattrs.each do |name|
+          if type.attrtype(name) == kind && name != :provider
+            attrs.push(:name => name, :doc => type.attrclass(name).doc)
+          end
+        end
+      end
+    end
+
+    # Return an array of hashes representing this +type+'s providers, each
+    # containing :name and :doc.
+    def provider_doc(type)
+      [].tap do |providers|
+        type.providers.sort_by{ |o| o.to_s }.each do |prov|
+          providers.push(:name => prov, :doc => type.provider(prov).doc)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/dependency.rb b/lib/puppet/module_tool/dependency.rb
new file mode 100644
index 0000000..bb55f59
--- /dev/null
+++ b/lib/puppet/module_tool/dependency.rb
@@ -0,0 +1,24 @@
+module Puppet::Module::Tool
+
+  class Dependency
+
+    # Instantiates a new module dependency with a +full_module_name+ (e.g.
+    # "myuser-mymodule"), and optional +version_requirement+ (e.g. "0.0.1") and
+    # optional repository (a URL string).
+    def initialize(full_module_name, version_requirement = nil, repository = nil)
+      @full_module_name = full_module_name
+      # TODO: add error checking, the next line raises ArgumentError when +full_module_name+ is invalid
+      @username, @name = Puppet::Module::Tool.username_and_modname_from(full_module_name)
+      @version_requirement = version_requirement
+      @repository = repository ? Repository.new(repository) : nil
+    end
+
+    # Return PSON representation of this data.
+    def to_pson(*args)
+      result = { :name => @full_module_name }
+      result[:version_requirement] = @version_requirement if @version_requirement && ! @version_requirement.nil?
+      result[:repository] = @repository.to_s if @repository && ! @repository.nil?
+      result.to_pson(*args)
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/metadata.rb b/lib/puppet/module_tool/metadata.rb
new file mode 100644
index 0000000..a84100a
--- /dev/null
+++ b/lib/puppet/module_tool/metadata.rb
@@ -0,0 +1,141 @@
+module Puppet::Module::Tool
+
+  # = Metadata
+  #
+  # This class provides a data structure representing a module's metadata.
+  # It provides some basic parsing, but other data is injected into it using
+  # +annotate+ methods in other classes.
+  class Metadata
+
+    # The full name of the module, which is a dash-separated combination of the
+    # +username+ and module +name+.
+    attr_reader :full_module_name
+
+    # The name of the user that owns this module.
+    attr_reader :username
+
+    # The name of this module. See also +full_module_name+.
+    attr_reader :name
+
+    # The version of this module.
+    attr_reader :version
+
+    # Instantiate from a hash, whose keys are setters in this class.
+    def initialize(settings={})
+      settings.each do |key, value|
+        send("#{key}=", value)
+      end
+    end
+
+    # Set the full name of this module, and from it, the +username+ and
+    # module +name+.
+    def full_module_name=(full_module_name)
+      @full_module_name = full_module_name
+      @username, @name = Puppet::Module::Tool::username_and_modname_from(full_module_name)
+    end
+
+    # Return an array of the module's Dependency objects.
+    def dependencies
+      return @dependencies ||= []
+    end
+
+    def author
+      @author || @username
+    end
+
+    def author=(author)
+      @author = author
+    end
+
+    def source
+      @source || 'UNKNOWN'
+    end
+
+    def source=(source)
+      @source = source
+    end
+
+    def license
+      @license || 'Apache License, Version 2.0'
+    end
+
+    def license=(license)
+      @license = license
+    end
+
+    def summary
+      @summary || 'UNKNOWN'
+    end
+
+    def summary=(summary)
+      @summary = summary
+    end
+
+    def description
+      @description || 'UNKNOWN'
+    end
+
+    def description=(description)
+      @description = description
+    end
+
+    def project_page
+      @project_page || 'UNKNOWN'
+    end
+
+    def project_page=(project_page)
+      @project_page = project_page
+    end
+
+    # Return an array of the module's Puppet types, each one is a hash
+    # containing :name and :doc.
+    def types
+      return @types ||= []
+    end
+
+    # Return module's file checksums.
+    def checksums
+      return @checksums ||= {}
+    end
+
+    # Return the dashed name of the module, which may either be the
+    # dash-separated combination of the +username+ and module +name+, or just
+    # the module +name+.
+    def dashed_name
+      return [@username, @name].compact.join('-')
+    end
+
+    # Return the release name, which is the combination of the +dashed_name+
+    # of the module and its +version+ number.
+    def release_name
+      return [dashed_name, @version].join('-')
+    end
+
+    # Set the version of this module, ensure a string like '0.1.0' see the
+    # Semantic Versions here: http://semver.org
+    def version=(version)
+      if SemVer.valid?(version)
+        @version = version
+      else
+        raise ArgumentError, "Invalid version format: #{@version} (Semantic Versions are acceptable: http://semver.org)"
+      end
+    end
+
+    # Return the PSON record representing this instance.
+    def to_pson(*args)
+      return {
+        :name         => @full_module_name,
+        :version      => @version,
+        :source       => source,
+        :author       => author,
+        :license      => license,
+        :summary      => summary,
+        :description  => description,
+        :project_page => project_page,
+        :dependencies => dependencies,
+        :types        => types,
+        :checksums    => checksums
+      }.to_pson(*args)
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/modulefile.rb b/lib/puppet/module_tool/modulefile.rb
new file mode 100644
index 0000000..35c1e99
--- /dev/null
+++ b/lib/puppet/module_tool/modulefile.rb
@@ -0,0 +1,75 @@
+module Puppet::Module::Tool
+
+  # = Modulefile
+  #
+  # This class provides the DSL used for evaluating the module's 'Modulefile'.
+  # These methods are used to concisely define this module's attributes, which
+  # are later rendered as PSON into a 'metadata.json' file.
+  class ModulefileReader
+
+    # Read the +filename+ and eval its Ruby code to set values in the Metadata
+    # +metadata+ instance.
+    def self.evaluate(metadata, filename)
+      returning(new(metadata)) do |builder|
+        if File.file?(filename)
+          builder.instance_eval(File.read(filename.to_s), filename.to_s, 1)
+        else
+          Puppet.warning "No Modulefile: #{filename}"
+        end
+      end
+    end
+
+    # Instantiate with the Metadata +metadata+ instance.
+    def initialize(metadata)
+      @metadata = metadata
+    end
+
+    # Set the +full_module_name+ (e.g. "myuser-mymodule"), which will also set the
+    # +username+ and module +name+. Required.
+    def name(name)
+      @metadata.full_module_name = name
+    end
+
+    # Set the module +version+ (e.g., "0.0.1"). Required.
+    def version(version)
+      @metadata.version = version
+    end
+
+    # Add a dependency with the full_module_name +name+ (e.g. "myuser-mymodule"), an
+    # optional +version_requirement+ (e.g. "0.0.1") and +repository+ (a URL
+    # string). Optional. Can be called multiple times to add many dependencies.
+    def dependency(name, version_requirement = nil, repository = nil)
+      @metadata.dependencies << Dependency.new(name, version_requirement, repository)
+    end
+
+    # Set the source
+    def source(source)
+      @metadata.source = source
+    end
+
+    # Set the author or default to +username+
+    def author(author)
+        @metadata.author = author
+    end
+
+    # Set the license
+    def license(license)
+      @metadata.license = license
+    end
+
+   # Set the summary
+   def summary(summary)
+      @metadata.summary = summary
+    end
+
+   # Set the description
+   def description(description)
+      @metadata.description = description
+   end
+
+   # Set the project page
+   def project_page(project_page)
+      @metadata.project_page = project_page
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/repository.rb b/lib/puppet/module_tool/repository.rb
new file mode 100644
index 0000000..7f0ad84
--- /dev/null
+++ b/lib/puppet/module_tool/repository.rb
@@ -0,0 +1,79 @@
+require 'net/http'
+require 'digest/sha1'
+require 'uri'
+
+module Puppet::Module::Tool
+
+  # = Repository
+  #
+  # This class is a file for accessing remote repositories with modules.
+  class Repository
+    include Utils::Interrogation
+
+    attr_reader :uri, :cache
+
+    # Instantiate a new repository instance rooted at the optional string
+    # +url+, else an instance of the default Puppet modules repository.
+    def initialize(url=Puppet[:module_repository])
+      @uri = url.is_a?(::URI) ? url : ::URI.parse(url)
+      @cache = Cache.new(self)
+    end
+
+    # Return a Net::HTTPResponse read for this +request+.
+    #
+    # Options:
+    # * :authenticate => Request authentication on the terminal. Defaults to false.
+    def make_http_request(request, options = {})
+      if options[:authenticate]
+        authenticate(request)
+      end
+      if ! @uri.user.nil? && ! @uri.password.nil?
+        request.basic_auth(@uri.user, @uri.password)
+      end
+      return read_response(request)
+    end
+
+    # Return a Net::HTTPResponse read from this HTTPRequest +request+.
+    def read_response(request)
+      begin
+        Net::HTTP::Proxy(
+            Puppet::Module::Tool::http_proxy_host,
+            Puppet::Module::Tool::http_proxy_port
+            ).start(@uri.host, @uri.port) do |http|
+          http.request(request)
+        end
+      rescue Errno::ECONNREFUSED, SocketError
+        raise RuntimeError, "Could not reach remote repository"
+      end
+    end
+
+    # Set the HTTP Basic Authentication parameters for the Net::HTTPRequest
+    # +request+ by asking the user for input on the console.
+    def authenticate(request)
+      Puppet.notice "Authenticating for #{@uri}"
+      email = prompt('Email Address')
+      password = prompt('Password', true)
+      request.basic_auth(email, password)
+    end
+
+    # Return the local file name containing the data downloaded from the
+    # repository at +release+ (e.g. "myuser-mymodule").
+    def retrieve(release)
+      return cache.retrieve(@uri + release)
+    end
+
+    # Return the URI string for this repository.
+    def to_s
+      return @uri.to_s
+    end
+
+    # Return the cache key for this repository, this a hashed string based on
+    # the URI.
+    def cache_key
+      return @cache_key ||= [
+        @uri.to_s.gsub(/[^[:alnum:]]+/, '_').sub(/_$/, ''),
+        Digest::SHA1.hexdigest(@uri.to_s)
+      ].join('-')
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/skeleton.rb b/lib/puppet/module_tool/skeleton.rb
new file mode 100644
index 0000000..4c41c76
--- /dev/null
+++ b/lib/puppet/module_tool/skeleton.rb
@@ -0,0 +1,34 @@
+module Puppet::Module::Tool
+
+  # = Skeleton
+  #
+  # This class provides methods for finding templates for the 'generate' action.
+  class Skeleton
+
+    # TODO Review whether the 'freeze' feature should be fixed or deleted.
+    # def freeze!
+    #   FileUtils.rm_fr custom_path rescue nil
+    #   FileUtils.cp_r default_path, custom_path
+    # end
+
+    # Return Pathname with 'generate' templates.
+    def path
+      paths.detect { |path| path.directory? }
+    end
+
+    # Return Pathnames to look for 'generate' templates.
+    def paths
+      @paths ||= [ custom_path, default_path ]
+    end
+
+    # Return Pathname of custom templates directory.
+    def custom_path
+      Pathname(Puppet.settings[:module_working_dir]) + 'skeleton'
+    end
+
+    # Return Pathname of default template directory.
+    def default_path
+      Pathname(__FILE__).dirname + 'skeleton/templates/generator'
+    end
+  end
+end
diff --git a/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb b/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb
new file mode 100644
index 0000000..845102d
--- /dev/null
+++ b/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb
@@ -0,0 +1,11 @@
+name    '<%= metadata.full_module_name %>'
+version '0.0.1'
+source '<%= metadata.source %>'
+author '<%= metadata.author %>'
+license '<%= metadata.license %>'
+summary '<%= metadata.summary %>'
+description '<%= metadata.description %>'
+project_page '<%= metadata.project_page %>'
+
+## Add dependencies, if any:
+# dependency 'username/name', '>= 1.2.0'
diff --git a/lib/puppet/module_tool/skeleton/templates/generator/README.erb b/lib/puppet/module_tool/skeleton/templates/generator/README.erb
new file mode 100644
index 0000000..95a6cc4
--- /dev/null
+++ b/lib/puppet/module_tool/skeleton/templates/generator/README.erb
@@ -0,0 +1,16 @@
+<%= metadata.name %>
+
+This is the <%= metadata.name %> module.
+
+License
+-------
+
+
+Contact
+-------
+
+
+Support
+-------
+
+Please log tickets and issues at our [Projects site](http://projects.example.com)
diff --git a/lib/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb b/lib/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb
new file mode 100644
index 0000000..04dd525
--- /dev/null
+++ b/lib/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb
@@ -0,0 +1,41 @@
+# == Class: <%= metadata.name %>
+#
+# Full description of class <%= metadata.name %> here.
+#
+# === Parameters
+#
+# Document parameters here.
+#
+# [*sample_parameter*]
+#   Explanation of what this parameter affects and what it defaults to.
+#   e.g. "Specify one or more upstream ntp servers as an array."
+#
+# === Variables
+#
+# Here you should define a list of variables that this module would require.
+#
+# [*sample_variable*]
+#   Explanation of how this variable affects the funtion of this class and if it
+#   has a default. e.g. "The parameter enc_ntp_servers must be set by the
+#   External Node Classifier as a comma separated list of hostnames." (Note,
+#   global variables should not be used in preference to class parameters  as of
+#   Puppet 2.6.)
+#
+# === Examples
+#
+#  class { <%= metadata.name %>:
+#    servers => [ 'pool.ntp.org', 'ntp.local.company.com' ]
+#  }
+#
+# === Authors
+#
+# Author Name <aut...@domain.com>
+#
+# === Copyright
+#
+# Copyright 2011 Your name here, unless otherwise noted.
+#
+class <%= metadata.name %> {
+
+
+}
diff --git a/lib/puppet/module_tool/skeleton/templates/generator/metadata.json b/lib/puppet/module_tool/skeleton/templates/generator/metadata.json
new file mode 100644
index 0000000..8ce7797
--- /dev/null
+++ b/lib/puppet/module_tool/skeleton/templates/generator/metadata.json
@@ -0,0 +1,12 @@
+/*
++-----------------------------------------------------------------------+
+|                                                                       |
+|                    ==> DO NOT EDIT THIS FILE! <==                     |
+|                                                                       |
+|   You should edit the `Modulefile` and run `puppet-module build`      |
+|   to generate the `metadata.json` file for your releases.             |
+|                                                                       |
++-----------------------------------------------------------------------+
+*/
+
+{}
diff --git a/lib/puppet/module_tool/skeleton/templates/generator/spec/spec_helper.rb b/lib/puppet/module_tool/skeleton/templates/generator/spec/spec_helper.rb
new file mode 100644
index 0000000..5fda588
--- /dev/null
+++ b/lib/puppet/module_tool/skeleton/templates/generator/spec/spec_helper.rb
@@ -0,0 +1,17 @@
+dir = File.expand_path(File.dirname(__FILE__))
+$LOAD_PATH.unshift File.join(dir, 'lib')
+
+require 'mocha'
+require 'puppet'
+require 'rspec'
+require 'spec/autorun'
+
+Spec::Runner.configure do |config|
+    config.mock_with :mocha
+end
+
+# We need this because the RAL uses 'should' as a method.  This
+# allows us the same behaviour but with a different method name.
+class Object
+    alias :must :should
+end
diff --git a/lib/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb b/lib/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb
new file mode 100644
index 0000000..ba44563
--- /dev/null
+++ b/lib/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb
@@ -0,0 +1,11 @@
+# The baseline for module testing used by Puppet Labs is that each manifest
+# should have a corresponding test manifest that declares that class or defined
+# type.
+#
+# Tests are then run by using puppet apply --noop (to check for compilation errors
+# and view a log of events) or by fully applying the test in a virtual environment
+# (to compare the resulting system state to the desired state).
+#
+# Learn more about module testing here: http://docs.puppetlabs.com/guides/tests_smoke.html
+#
+include <%= metadata.name %>
diff --git a/lib/puppet/module_tool/utils.rb b/lib/puppet/module_tool/utils.rb
new file mode 100644
index 0000000..85f57c9
--- /dev/null
+++ b/lib/puppet/module_tool/utils.rb
@@ -0,0 +1,5 @@
+module Puppet::Module::Tool
+  module Utils
+    require 'puppet/module_tool/utils/interrogation'
+  end
+end
diff --git a/lib/puppet/module_tool/utils/interrogation.rb b/lib/puppet/module_tool/utils/interrogation.rb
new file mode 100644
index 0000000..19450de
--- /dev/null
+++ b/lib/puppet/module_tool/utils/interrogation.rb
@@ -0,0 +1,25 @@
+module Puppet::Module::Tool
+  module Utils
+
+    # = Interrogation
+    #
+    # This module contains methods to emit questions to the console.
+    module Interrogation
+      def confirms?(question)
+        $stderr.print "#{question} [y/N]: "
+        $stdin.gets =~ /y/i
+      end
+
+      def prompt(question, quiet = false)
+        $stderr.print "#{question}: "
+        system 'stty -echo' if quiet
+        $stdin.gets.strip
+      ensure
+        if quiet
+          system 'stty echo'
+          say "\n---------"
+        end
+      end
+    end
+  end
+end
diff --git a/lib/puppet/network/handler.rb b/lib/puppet/network/handler.rb
deleted file mode 100644
index 3cad387..0000000
--- a/lib/puppet/network/handler.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-require 'puppet/util/docs'
-require 'puppet/util/subclass_loader'
-
-module Puppet::Network
-  # The base class for the different handlers.  The handlers are each responsible
-  # for separate xmlrpc namespaces.
-  class Handler
-    extend Puppet::Util::Docs
-
-    # This is so that the handlers can subclass just 'Handler', rather
-    # then having to specify the full class path.
-    Handler = self
-    attr_accessor :server, :local
-
-    extend Puppet::Util::SubclassLoader
-    extend Puppet::Util
-
-    handle_subclasses :handler, "puppet/network/handler"
-
-    # Return the xmlrpc interface.
-    def self.interface
-      if defined?(@interface)
-        return @interface
-      else
-        raise Puppet::DevError, "Handler #{self} has no defined interface"
-      end
-    end
-
-    # Set/Determine whether we're a client- or server-side handler.
-    def self.side(side = nil)
-      if side
-        side = side.intern if side.is_a?(String)
-        raise ArgumentError, "Invalid side registration '#{side}' for #{self.name}" unless [:client, :server].include?(side)
-        @side = side
-      else
-        @side ||= :server
-        return @side
-      end
-    end
-
-    # Create an empty init method with the same signature.
-    def initialize(hash = {})
-    end
-
-    def local?
-      self.local
-    end
-  end
-end
-
diff --git a/lib/puppet/network/handler/ca.rb b/lib/puppet/network/handler/ca.rb
deleted file mode 100644
index a61f62f..0000000
--- a/lib/puppet/network/handler/ca.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require 'openssl'
-require 'puppet'
-require 'xmlrpc/server'
-require 'puppet/network/handler'
-
-class Puppet::Network::Handler
-  class CA < Handler
-    attr_reader :ca
-
-    desc "Provides an interface for signing CSRs.  Accepts a CSR and returns
-    the CA certificate and the signed certificate, or returns nil if
-    the cert is not signed."
-
-    @interface = XMLRPC::Service::Interface.new("puppetca") { |iface|
-      iface.add_method("array getcert(csr)")
-    }
-
-    def initialize(hash = {})
-      Puppet.settings.use(:main, :ssl, :ca)
-
-      @ca = Puppet::SSL::CertificateAuthority.instance
-    end
-
-    # our client sends us a csr, and we either store it for later signing,
-    # or we sign it right away
-    def getcert(csrtext, client = nil, clientip = nil)
-      csr = Puppet::SSL::CertificateRequest.from_s(csrtext)
-      hostname = csr.name
-
-      unless @ca
-        Puppet.notice "Host #{hostname} asked for signing from non-CA master"
-        return ""
-      end
-
-      # We used to save the public key, but it's basically unnecessary
-      # and it mucks with the permissions requirements.
-
-      # first check to see if we already have a signed cert for the host
-      cert = Puppet::SSL::Certificate.indirection.find(hostname)
-      cacert = Puppet::SSL::Certificate.indirection.find(@ca.host.name)
-
-      if cert
-        Puppet.info "Retrieving existing certificate for #{hostname}"
-        unless csr.content.public_key.to_s == cert.content.public_key.to_s
-          raise Puppet::Error, "Certificate request does not match existing certificate; run 'puppetca --clean #{hostname}'."
-        end
-        [cert.to_s, cacert.to_s]
-      else
-        Puppet::SSL::CertificateRequest.indirection.save(csr)
-
-        # We determine whether we signed the csr by checking if there's a certificate for it
-        if cert = Puppet::SSL::Certificate.indirection.find(hostname)
-          [cert.to_s, cacert.to_s]
-        else
-          nil
-        end
-      end
-    end
-  end
-end
-
diff --git a/lib/puppet/network/handler/filebucket.rb b/lib/puppet/network/handler/filebucket.rb
deleted file mode 100755
index 0ca467f..0000000
--- a/lib/puppet/network/handler/filebucket.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require 'fileutils'
-require 'digest/md5'
-require 'puppet/external/base64'
-require 'puppet/network/handler'
-require 'xmlrpc/server'
-
-class Puppet::Network::Handler # :nodoc:
-  # Accept files and store them by md5 sum, returning the md5 sum back
-  # to the client.  Alternatively, accept an md5 sum and return the
-  # associated content.
-  class FileBucket < Handler
-    desc "The interface to Puppet's FileBucket system.  Can be used to store
-    files in and retrieve files from a filebucket."
-
-    @interface = XMLRPC::Service::Interface.new("puppetbucket") { |iface|
-      iface.add_method("string addfile(string, string)")
-      iface.add_method("string getfile(string)")
-    }
-
-    Puppet::Util.logmethods(self, true)
-    attr_reader :name, :path
-
-    def initialize(hash)
-      @path = hash[:Path] || Puppet[:bucketdir]
-      @name = "Filebucket[#{@path}]"
-    end
-
-    # Accept a file from a client and store it by md5 sum, returning
-    # the sum.
-    def addfile(contents, path, client = nil, clientip = nil)
-      contents = Base64.decode64(contents) if client
-      bucket = Puppet::FileBucket::File.new(contents)
-      Puppet::FileBucket::File.indirection.save(bucket)
-    end
-
-    # Return the contents associated with a given md5 sum.
-    def getfile(md5, client = nil, clientip = nil)
-      bucket = Puppet::FileBucket::File.indirection.find("md5:#{md5}")
-      contents = bucket.contents
-
-      if client
-        return Base64.encode64(contents)
-      else
-        return contents
-      end
-    end
-
-    def to_s
-      self.name
-    end
-  end
-end
-
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb
deleted file mode 100755
index 8fe3da2..0000000
--- a/lib/puppet/network/handler/fileserver.rb
+++ /dev/null
@@ -1,732 +0,0 @@
-require 'puppet'
-require 'puppet/network/authstore'
-require 'webrick/httpstatus'
-require 'cgi'
-require 'delegate'
-require 'sync'
-require 'puppet/network/handler'
-
-require 'puppet/network/handler'
-require 'puppet/network/xmlrpc/server'
-require 'puppet/file_serving'
-require 'puppet/file_serving/metadata'
-require 'puppet/network/handler'
-
-class Puppet::Network::Handler
-  AuthStoreError = Puppet::AuthStoreError
-  class FileServerError < Puppet::Error; end
-  class FileServer < Handler
-    desc "The interface to Puppet's fileserving abilities."
-
-    attr_accessor :local
-
-    CHECKPARAMS = [:mode, :type, :owner, :group, :checksum]
-
-    # Special filserver module for puppet's module system
-    MODULES = "modules"
-    PLUGINS = "plugins"
-
-    @interface = XMLRPC::Service::Interface.new("fileserver") { |iface|
-      iface.add_method("string describe(string, string)")
-      iface.add_method("string list(string, string, boolean, array)")
-      iface.add_method("string retrieve(string, string)")
-    }
-
-    def self.params
-      CHECKPARAMS.dup
-    end
-
-    # If the configuration file exists, then create (if necessary) a LoadedFile
-    # object to manage it; else, return nil.
-    def configuration
-      # Short-circuit the default case.
-      return @configuration if defined?(@configuration)
-
-      config_path = @passed_configuration_path || Puppet[:fileserverconfig]
-      return nil unless FileTest.exist?(config_path)
-
-      # The file exists but we don't have a LoadedFile instance for it.
-      @configuration = Puppet::Util::LoadedFile.new(config_path)
-    end
-
-    # Create our default mounts for modules and plugins.  This is duplicated code,
-    # but I'm not really worried about that.
-    def create_default_mounts
-      @mounts = {}
-      Puppet.debug "No file server configuration file; autocreating #{MODULES} mount with default permissions"
-      mount = Mount.new(MODULES)
-      mount.allow("*")
-      @mounts[MODULES] = mount
-
-      Puppet.debug "No file server configuration file; autocreating #{PLUGINS} mount with default permissions"
-      mount = PluginMount.new(PLUGINS)
-      mount.allow("*")
-      @mounts[PLUGINS] = mount
-    end
-
-    # Describe a given file.  This returns all of the manageable aspects
-    # of that file.
-    def describe(url, links = :follow, client = nil, clientip = nil)
-      links = links.intern if links.is_a? String
-
-      mount, path = convert(url, client, clientip)
-
-      mount.debug("Describing #{url} for #{client}") if client
-
-      # use the mount to resolve the path for us.
-      return "" unless full_path = mount.file_path(path, client)
-
-      metadata = Puppet::FileServing::Metadata.new(url, :path => full_path, :links => links)
-
-      return "" unless metadata.exist?
-
-      begin
-        metadata.collect
-      rescue => detail
-        puts detail.backtrace if Puppet[:trace]
-        Puppet.err detail
-        return ""
-      end
-
-      metadata.attributes_with_tabs
-    end
-
-    # Create a new fileserving module.
-    def initialize(hash = {})
-      @mounts = {}
-      @files = {}
-
-      @local = hash[:Local]
-
-      @noreadconfig = true if hash[:Config] == false
-
-      @passed_configuration_path = hash[:Config]
-
-      if hash.include?(:Mount)
-        @passedconfig = true
-        raise Puppet::DevError, "Invalid mount hash #{hash[:Mount].inspect}" unless hash[:Mount].is_a?(Hash)
-
-        hash[:Mount].each { |dir, name|
-          self.mount(dir, name) if FileTest.exists?(dir)
-        }
-        self.mount(nil, MODULES)
-        self.mount(nil, PLUGINS)
-      else
-        @passedconfig = false
-        if configuration
-          readconfig(false) # don't check the file the first time.
-        else
-          create_default_mounts
-        end
-      end
-    end
-
-    # List a specific directory's contents.
-    def list(url, links = :ignore, recurse = false, ignore = false, client = nil, clientip = nil)
-      mount, path = convert(url, client, clientip)
-
-      mount.debug "Listing #{url} for #{client}" if client
-
-      return "" unless mount.path_exists?(path, client)
-
-      desc = mount.list(path, recurse, ignore, client)
-
-      if desc.length == 0
-        mount.notice "Got no information on //#{mount}/#{path}"
-        return ""
-      end
-
-      desc.collect { |sub| sub.join("\t") }.join("\n")
-    end
-
-    def local?
-      self.local
-    end
-
-    # Is a given mount available?
-    def mounted?(name)
-      @mounts.include?(name)
-    end
-
-    # Mount a new directory with a name.
-    def mount(path, name)
-      if @mounts.include?(name)
-        if @mounts[name] != path
-          raise FileServerError, "#{@mounts[name].path} is already mounted at #{name}"
-        else
-          # it's already mounted; no problem
-          return
-        end
-      end
-
-      # Let the mounts do their own error-checking.
-      @mounts[name] = Mount.new(name, path)
-      @mounts[name].info "Mounted #{path}"
-
-      @mounts[name]
-    end
-
-    # Retrieve a file from the local disk and pass it to the remote
-    # client.
-    def retrieve(url, links = :ignore, client = nil, clientip = nil)
-      links = links.intern if links.is_a? String
-
-      mount, path = convert(url, client, clientip)
-
-      mount.info "Sending #{url} to #{client}" if client
-
-      unless mount.path_exists?(path, client)
-        mount.debug "#{mount} reported that #{path} does not exist"
-        return ""
-      end
-
-      links = links.intern if links.is_a? String
-
-      if links == :ignore and FileTest.symlink?(path)
-        mount.debug "I think that #{path} is a symlink and we're ignoring them"
-        return ""
-      end
-
-      str = mount.read_file(path, client)
-
-      if @local
-        return str
-      else
-        return CGI.escape(str)
-      end
-    end
-
-    def umount(name)
-      @mounts.delete(name) if @mounts.include? name
-    end
-
-    private
-
-    def authcheck(file, mount, client, clientip)
-      # If we're local, don't bother passing in information.
-      if local?
-        client = nil
-        clientip = nil
-      end
-      unless mount.allowed?(client, clientip)
-        mount.warning "#{client} cannot access #{file}"
-        raise Puppet::AuthorizationError, "Cannot access #{mount}"
-      end
-    end
-
-    # Take a URL and some client info and return a mount and relative
-    # path pair.
-    #
-    def convert(url, client, clientip)
-      readconfig
-
-      url = URI.unescape(url)
-
-      mount, stub = splitpath(url, client)
-
-      authcheck(url, mount, client, clientip)
-
-      return mount, stub
-    end
-
-    # Return the mount for the Puppet modules; allows file copying from
-    # the modules.
-    def modules_mount(module_name, client)
-      # Find our environment, if we have one.
-      unless hostname = (client || Facter.value("hostname"))
-        raise ArgumentError, "Could not find hostname"
-      end
-      env = (node = Puppet::Node.indirection.find(hostname)) ? node.environment : nil
-
-      # And use the environment to look up the module.
-      (mod = Puppet::Node::Environment.new(env).module(module_name) and mod.files?) ? @mounts[MODULES].copy(mod.name, mod.file_directory) : nil
-    end
-
-    # Read the configuration file.
-    def readconfig(check = true)
-      return if @noreadconfig
-
-      return unless configuration
-
-      return if check and ! @configuration.changed?
-
-      newmounts = {}
-      begin
-        File.open(@configuration.file) { |f|
-          mount = nil
-          count = 1
-          f.each { |line|
-            case line
-            when /^\s*#/; next # skip comments
-            when /^\s*$/; next # skip blank lines
-            when /\[([-\w]+)\]/
-              name = $1
-              raise FileServerError, "#{newmounts[name]} is already mounted as #{name} in #{@configuration.file}" if newmounts.include?(name)
-              mount = Mount.new(name)
-              newmounts[name] = mount
-            when /^\s*(\w+)\s+(.+)$/
-              var = $1
-              value = $2
-              case var
-              when "path"
-                raise FileServerError.new("No mount specified for argument #{var} #{value}") unless mount
-                if mount.name == MODULES
-                  Puppet.warning "The '#{mount.name}' module can not have a path. Ignoring attempt to set it"
-                else
-                  begin
-                    mount.path = value
-                  rescue FileServerError => detail
-                    Puppet.err "Removing mount #{mount.name}: #{detail}"
-                    newmounts.delete(mount.name)
-                  end
-                end
-              when "allow"
-                raise FileServerError.new("No mount specified for argument #{var} #{value}") unless mount
-                value.split(/\s*,\s*/).each { |val|
-                  begin
-                    mount.info "allowing #{val} access"
-                    mount.allow(val)
-                  rescue AuthStoreError => detail
-                    puts detail.backtrace if Puppet[:trace]
-
-                      raise FileServerError.new(
-                        detail.to_s,
-
-                      count, @configuration.file)
-                  end
-                }
-              when "deny"
-                raise FileServerError.new("No mount specified for argument #{var} #{value}") unless mount
-                value.split(/\s*,\s*/).each { |val|
-                  begin
-                    mount.info "denying #{val} access"
-                    mount.deny(val)
-                  rescue AuthStoreError => detail
-
-                    raise FileServerError.new(
-                      detail.to_s,
-
-                      count, @configuration.file)
-                  end
-                }
-              else
-                raise FileServerError.new("Invalid argument '#{var}'", count, @configuration.file)
-              end
-            else
-              raise FileServerError.new("Invalid line '#{line.chomp}'", count, @configuration.file)
-            end
-            count += 1
-          }
-        }
-      rescue Errno::EACCES => detail
-        Puppet.err "FileServer error: Cannot read #{@configuration}; cannot serve"
-        #raise Puppet::Error, "Cannot read #{@configuration}"
-      rescue Errno::ENOENT => detail
-        Puppet.err "FileServer error: '#{@configuration}' does not exist; cannot serve"
-      end
-
-      unless newmounts[MODULES]
-        Puppet.debug "No #{MODULES} mount given; autocreating with default permissions"
-        mount = Mount.new(MODULES)
-        mount.allow("*")
-        newmounts[MODULES] = mount
-      end
-
-      unless newmounts[PLUGINS]
-        Puppet.debug "No #{PLUGINS} mount given; autocreating with default permissions"
-        mount = PluginMount.new(PLUGINS)
-        mount.allow("*")
-        newmounts[PLUGINS] = mount
-      end
-
-      unless newmounts[PLUGINS].valid?
-        Puppet.debug "No path given for #{PLUGINS} mount; creating a special PluginMount"
-        # We end up here if the user has specified access rules for
-        # the plugins mount, without specifying a path (which means
-        # they want to have the default behaviour for the mount, but
-        # special access control).  So we need to move all the
-        # user-specified access controls into the new PluginMount
-        # object...
-        mount = PluginMount.new(PLUGINS)
-        # Yes, you're allowed to hate me for this.
-
-          mount.instance_variable_set(
-            :@declarations,
-
-              newmounts[PLUGINS].instance_variable_get(:@declarations)
-              )
-        newmounts[PLUGINS] = mount
-      end
-
-      # Verify each of the mounts are valid.
-      # We let the check raise an error, so that it can raise an error
-      # pointing to the specific problem.
-      newmounts.each { |name, mount|
-        raise FileServerError, "Invalid mount #{name}" unless mount.valid?
-      }
-      @mounts = newmounts
-    end
-
-    # Split the path into the separate mount point and path.
-    def splitpath(dir, client)
-      # the dir is based on one of the mounts
-      # so first retrieve the mount path
-      mount = nil
-      path = nil
-      if dir =~ %r{/([-\w]+)}
-        # Strip off the mount name.
-        mount_name, path = dir.sub(%r{^/}, '').split(File::Separator, 2)
-
-        unless mount = modules_mount(mount_name, client)
-          unless mount = @mounts[mount_name]
-            raise FileServerError, "Fileserver module '#{mount_name}' not mounted"
-          end
-        end
-      else
-        raise FileServerError, "Fileserver error: Invalid path '#{dir}'"
-      end
-
-      if path.nil? or path == ''
-        path = '/'
-      elsif path
-        # Remove any double slashes that might have occurred
-        path = URI.unescape(path.gsub(/\/\//, "/"))
-      end
-
-      return mount, path
-    end
-
-    def to_s
-      "fileserver"
-    end
-
-    # A simple class for wrapping mount points.  Instances of this class
-    # don't know about the enclosing object; they're mainly just used for
-    # authorization.
-    class Mount < Puppet::Network::AuthStore
-      attr_reader :name
-
-      @@syncs = {}
-
-      @@files = {}
-
-      Puppet::Util.logmethods(self, true)
-
-      # Create a map for a specific client.
-      def clientmap(client)
-        {
-          "h" => client.sub(/\..*$/, ""),
-          "H" => client,
-          "d" => client.sub(/[^.]+\./, "") # domain name
-        }
-      end
-
-      # Replace % patterns as appropriate.
-      def expand(path, client = nil)
-        # This map should probably be moved into a method.
-        map = nil
-
-        if client
-          map = clientmap(client)
-        else
-          Puppet.notice "No client; expanding '#{path}' with local host"
-          # Else, use the local information
-          map = localmap
-        end
-        path.gsub(/%(.)/) do |v|
-          key = $1
-          if key == "%"
-            "%"
-          else
-            map[key] || v
-          end
-        end
-      end
-
-      # Do we have any patterns in our path, yo?
-      def expandable?
-        if defined?(@expandable)
-          @expandable
-        else
-          false
-        end
-      end
-
-      # Return a fully qualified path, given a short path and
-      # possibly a client name.
-      def file_path(relative_path, node = nil)
-        full_path = path(node)
-
-        unless full_path
-          p self
-          raise ArgumentError.new("Mounts without paths are not usable") unless full_path
-        end
-
-        # If there's no relative path name, then we're serving the mount itself.
-        return full_path unless relative_path and relative_path != "/"
-
-        File.join(full_path, relative_path)
-      end
-
-      # Create out object.  It must have a name.
-      def initialize(name, path = nil)
-        unless name =~ %r{^[-\w]+$}
-          raise FileServerError, "Invalid name format '#{name}'"
-        end
-        @name = name
-
-        if path
-          self.path = path
-        else
-          @path = nil
-        end
-
-        @files = {}
-
-        super()
-      end
-
-      def fileobj(path, links, client)
-        obj = nil
-        if obj = @files[file_path(path, client)]
-          # This can only happen in local fileserving, but it's an
-          # important one.  It'd be nice if we didn't just set
-          # the check params every time, but I'm not sure it's worth
-          # the effort.
-          obj[:audit] = CHECKPARAMS
-        else
-
-          obj = Puppet::Type.type(:file).new(
-
-            :name => file_path(path, client),
-
-            :audit => CHECKPARAMS
-          )
-          @files[file_path(path, client)] = obj
-        end
-
-        if links == :manage
-          links = :follow
-        end
-
-        # This, ah, might be completely redundant
-        obj[:links] = links unless obj[:links] == links
-
-        obj
-      end
-
-      # Read the contents of the file at the relative path given.
-      def read_file(relpath, client)
-        File.read(file_path(relpath, client))
-      end
-
-      # Cache this manufactured map, since if it's used it's likely
-      # to get used a lot.
-      def localmap
-        unless defined?(@@localmap)
-          @@localmap = {
-            "h" =>  Facter.value("hostname"),
-            "H" => [Facter.value("hostname"),
-              Facter.value("domain")].join("."),
-            "d" =>  Facter.value("domain")
-          }
-        end
-        @@localmap
-      end
-
-      # Return the path as appropriate, expanding as necessary.
-      def path(client = nil)
-        if expandable?
-          return expand(@path, client)
-        else
-          return @path
-        end
-      end
-
-      # Set the path.
-      def path=(path)
-        # FIXME: For now, just don't validate paths with replacement
-        # patterns in them.
-        if path =~ /%./
-          # Mark that we're expandable.
-          @expandable = true
-        else
-          raise FileServerError, "#{path} does not exist" unless FileTest.exists?(path)
-          raise FileServerError, "#{path} is not a directory" unless FileTest.directory?(path)
-          raise FileServerError, "#{path} is not readable" unless FileTest.readable?(path)
-          @expandable = false
-        end
-        @path = path
-      end
-
-      # Verify that the path given exists within this mount's subtree.
-      #
-      def path_exists?(relpath, client = nil)
-        File.exists?(file_path(relpath, client))
-      end
-
-      # Return the current values for the object.
-      def properties(obj)
-        obj.retrieve.inject({}) { |props, ary| props[ary[0].name] = ary[1]; props }
-      end
-
-      # Retrieve a specific directory relative to a mount point.
-      # If they pass in a client, then expand as necessary.
-      def subdir(dir = nil, client = nil)
-        basedir = self.path(client)
-
-        dirname = if dir
-          File.join(basedir, *dir.split("/"))
-        else
-          basedir
-        end
-
-        dirname
-      end
-
-      def sync(path)
-        @@syncs[path] ||= Sync.new
-        @@syncs[path]
-      end
-
-      def to_s
-        "mount[#{@name}]"
-      end
-
-      # Verify our configuration is valid.  This should really check to
-      # make sure at least someone will be allowed, but, eh.
-      def valid?
-        if name == MODULES
-          return @path.nil?
-        else
-          return ! @path.nil?
-        end
-      end
-
-      # Return a new mount with the same properties as +self+, except
-      # with a different name and path.
-      def copy(name, path)
-        result = self.clone
-        result.path = path
-        result.instance_variable_set(:@name, name)
-        result
-      end
-
-      # List the contents of the relative path +relpath+ of this mount.
-      #
-      # +recurse+ is the number of levels to recurse into the tree,
-      # or false to provide no recursion or true if you just want to
-      # go for broke.
-      #
-      # +ignore+ is an array of filenames to ignore when traversing
-      # the list.
-      #
-      # The return value of this method is a complex nest of arrays,
-      # which describes a directory tree.  Each file or directory is
-      # represented by an array, where the first element is the path
-      # of the file (relative to the root of the mount), and the
-      # second element is the type.  A directory is represented by an
-      # array as well, where the first element is a "directory" array,
-      # while the remaining elements are other file or directory
-      # arrays.  Confusing?  Hell yes.  As an added bonus, all names
-      # must start with a slash, because... well, I'm fairly certain
-      # a complete explanation would involve the words "crack pipe"
-      # and "bad batch".
-      #
-      def list(relpath, recurse, ignore, client = nil)
-        abspath = file_path(relpath, client)
-        if FileTest.exists?(abspath)
-          if FileTest.directory?(abspath) and recurse
-            return reclist(abspath, recurse, ignore)
-          else
-            return [["/", File.stat(abspath).ftype]]
-          end
-        end
-        nil
-      end
-
-      def reclist(abspath, recurse, ignore)
-        require 'puppet/file_serving'
-        require 'puppet/file_serving/fileset'
-        if recurse.is_a?(Fixnum)
-          args = { :recurse => true, :recurselimit => recurse, :links => :follow }
-        else
-          args = { :recurse => recurse, :links => :follow }
-        end
-        args[:ignore] = ignore if ignore
-        fs = Puppet::FileServing::Fileset.new(abspath, args)
-        ary = fs.files.collect do |file|
-          if file == "."
-            file = "/"
-          else
-            file = File.join("/", file )
-          end
-          stat = fs.stat(File.join(abspath, file))
-          next if stat.nil?
-          [ file, stat.ftype ]
-        end
-
-        ary.compact
-      end
-
-    end
-
-    # A special mount class specifically for the plugins mount -- just
-    # has some magic to effectively do a union mount of the 'plugins'
-    # directory of all modules.
-    #
-    class PluginMount < Mount
-      def path(client)
-        ''
-      end
-
-      def mod_path_exists?(mod, relpath, client = nil)
-        ! mod.plugin(relpath).nil?
-      end
-
-      def path_exists?(relpath, client = nil)
-        !valid_modules(client).find { |mod| mod.plugin(relpath) }.nil?
-      end
-
-      def valid?
-        true
-      end
-
-      def mod_file_path(mod, relpath, client = nil)
-        File.join(mod, PLUGINS, relpath)
-      end
-
-      def file_path(relpath, client = nil)
-        return nil unless mod = valid_modules(client).find { |m| m.plugin(relpath) }
-        mod.plugin(relpath)
-      end
-
-      # create a list of files by merging all modules
-      def list(relpath, recurse, ignore, client = nil)
-        result = []
-        valid_modules(client).each do |mod|
-          if modpath = mod.plugin(relpath)
-            if FileTest.directory?(modpath) and recurse
-              ary = reclist(modpath, recurse, ignore)
-              ary ||= []
-              result += ary
-            else
-              result += [["/", File.stat(modpath).ftype]]
-            end
-          end
-        end
-        result
-      end
-
-      private
-      def valid_modules(client)
-        Puppet::Node::Environment.new.modules.find_all { |mod| mod.exist? }
-      end
-
-      def add_to_filetree(f, filetree)
-        first, rest = f.split(File::SEPARATOR, 2)
-      end
-    end
-  end
-end
-
diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb
deleted file mode 100644
index fd2bb95..0000000
--- a/lib/puppet/network/handler/master.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-require 'openssl'
-require 'puppet'
-require 'xmlrpc/server'
-require 'yaml'
-require 'puppet/network/handler'
-
-class Puppet::Network::Handler
-  class MasterError < Puppet::Error; end
-  class Master < Handler
-    desc "Puppet's configuration interface.  Used for all interactions related to
-    generating client configurations."
-
-    include Puppet::Util
-
-    attr_accessor :ast
-    attr_reader :ca
-
-    @interface = XMLRPC::Service::Interface.new("puppetmaster") { |iface|
-        iface.add_method("string getconfig(string)")
-        iface.add_method("int freshness()")
-    }
-
-    # Tell a client whether there's a fresh config for it
-    def freshness(client = nil, clientip = nil)
-      # Always force a recompile.  Newer clients shouldn't do this (as of April 2008).
-      Time.now.to_i
-    end
-
-    def initialize(hash = {})
-      args = {}
-
-      @local = hash[:Local]
-
-      args[:Local] = true
-
-      # This is only used by the cfengine module, or if --loadclasses was
-      # specified in +puppet+.
-      args[:Classes] = hash[:Classes] if hash.include?(:Classes)
-    end
-
-    # Call our various handlers; this handler is getting deprecated.
-    def getconfig(facts, format = "marshal", client = nil, clientip = nil)
-      facts = decode_facts(facts)
-
-      client ||= facts["hostname"]
-
-      # Pass the facts to the fact handler
-      Puppet::Node::Facts.indirection.save(Puppet::Node::Facts.new(client, facts)) unless local?
-
-      catalog = Puppet::Resource::Catalog.indirection.find(client)
-
-      case format
-      when "yaml"
-        return CGI.escape(catalog.extract.to_yaml)
-      when "marshal"
-        return CGI.escape(Marshal.dump(catalog.extract))
-      else
-        raise "Invalid markup format '#{format}'"
-      end
-    end
-
-    #
-    def decode_facts(facts)
-      if @local
-        # we don't need to do anything, since we should already
-        # have raw objects
-        Puppet.debug "Our client is local"
-      else
-        Puppet.debug "Our client is remote"
-
-        begin
-          facts = YAML.load(CGI.unescape(facts))
-        rescue => detail
-          raise XMLRPC::FaultException.new(
-            1, "Could not rebuild facts"
-          )
-        end
-      end
-
-      facts
-    end
-
-    # Translate our configuration appropriately for sending back to a client.
-    def translate(config)
-    end
-  end
-end
diff --git a/lib/puppet/network/handler/report.rb b/lib/puppet/network/handler/report.rb
deleted file mode 100755
index 5e3ee26..0000000
--- a/lib/puppet/network/handler/report.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-require 'puppet/util/instance_loader'
-require 'puppet/reports'
-require 'puppet/network/handler'
-require 'xmlrpc/server'
-
-# A simple server for triggering a new run on a Puppet client.
-class Puppet::Network::Handler
-  class Report < Handler
-    desc "Accepts a Puppet transaction report and processes it."
-
-    @interface = XMLRPC::Service::Interface.new("puppetreports") { |iface|
-      iface.add_method("string report(array)")
-    }
-
-    # Add a new report type.
-    def self.newreport(name, options = {}, &block)
-      Puppet.warning "The interface for registering report types has changed; use Puppet::Reports.register_report for report type #{name}"
-      Puppet::Reports.register_report(name, options, &block)
-    end
-
-    def initialize(*args)
-      super
-      Puppet.settings.use(:main, :reporting, :metrics)
-    end
-
-    # Accept a report from a client.
-    def report(report, client = nil, clientip = nil)
-      # Unescape the report
-      report = CGI.unescape(report) unless @local
-
-      Puppet.info "Processing reports #{reports().join(", ")} for #{client}"
-      begin
-        process(report)
-      rescue => detail
-        Puppet.err "Could not process report for #{client}: #{detail}"
-        puts detail.backtrace if Puppet[:trace]
-      end
-    end
-
-    private
-
-    # Process the report using all of the existing hooks.
-    def process(yaml)
-      return if Puppet[:reports] == "none"
-
-      # First convert the report to real objects
-      begin
-        report = YAML.load(yaml)
-      rescue => detail
-        Puppet.warning "Could not load report: #{detail}"
-        return
-      end
-
-      # Used for those reports that accept yaml
-      client = report.host
-
-      reports.each do |name|
-        if mod = Puppet::Reports.report(name)
-          # We have to use a dup because we're including a module in the
-          # report.
-          newrep = report.dup
-          begin
-            newrep.extend(mod)
-            newrep.process
-          rescue => detail
-            puts detail.backtrace if Puppet[:trace]
-            Puppet.err "Report #{name} failed: #{detail}"
-          end
-        else
-          Puppet.warning "No report named '#{name}'"
-        end
-      end
-    end
-
-    # Handle the parsing of the reports attribute.
-    def reports
-      # LAK:NOTE See http://snurl.com/21zf8  [groups_google_com]
-      x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
-    end
-  end
-end
-
diff --git a/lib/puppet/network/handler/runner.rb b/lib/puppet/network/handler/runner.rb
deleted file mode 100755
index 1bc62bc..0000000
--- a/lib/puppet/network/handler/runner.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require 'puppet/run'
-require 'puppet/network/handler'
-require 'xmlrpc/server'
-
-class Puppet::Network::Handler
-  class MissingMasterError < RuntimeError; end # Cannot find the master client
-  # A simple server for triggering a new run on a Puppet client.
-  class Runner < Handler
-    desc "An interface for triggering client configuration runs."
-
-    @interface = XMLRPC::Service::Interface.new("puppetrunner") { |iface|
-      iface.add_method("string run(string, string)")
-    }
-
-    side :client
-
-    # Run the client configuration right now, optionally specifying
-    # tags and whether to ignore schedules
-    def run(tags = nil, ignoreschedules = false, fg = true, client = nil, clientip = nil)
-      options = {}
-      options[:tags] = tags if tags
-      options[:ignoreschedules] = ignoreschedules if ignoreschedules
-      options[:background] = !fg
-
-      runner = Puppet::Run.new(options)
-
-      runner.run
-
-      runner.status
-    end
-  end
-end
-
diff --git a/lib/puppet/network/handler/status.rb b/lib/puppet/network/handler/status.rb
deleted file mode 100644
index df6215f..0000000
--- a/lib/puppet/network/handler/status.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require 'puppet/network/handler'
-require 'xmlrpc/server'
-class Puppet::Network::Handler
-  class Status < Handler
-    desc "A simple interface for testing Puppet connectivity."
-
-    side :client
-
-    @interface = XMLRPC::Service::Interface.new("status") { |iface|
-      iface.add_method("int status()")
-    }
-
-    def status(client = nil, clientip = nil)
-      1
-    end
-  end
-end
-
diff --git a/lib/puppet/network/http/api/v1.rb b/lib/puppet/network/http/api/v1.rb
index 388d549..852568a 100644
--- a/lib/puppet/network/http/api/v1.rb
+++ b/lib/puppet/network/http/api/v1.rb
@@ -74,7 +74,8 @@ def plurality(indirection)
 
     result = (indirection =~ /s$|_search$/) ? :plural : :singular
 
-    indirection.sub!(/s$|_search$|es$/, '')
+    indirection.sub!(/s$|_search$/, '')
+    indirection.sub!(/statuse$/, 'status')
 
     result
   end
diff --git a/lib/puppet/network/http/mongrel.rb b/lib/puppet/network/http/mongrel.rb
index 2a638b2..ee103b5 100644
--- a/lib/puppet/network/http/mongrel.rb
+++ b/lib/puppet/network/http/mongrel.rb
@@ -8,15 +8,12 @@ def initialize(args = {})
   end
 
   def listen(args = {})
-    raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
     raise ArgumentError, ":address must be specified." unless args[:address]
     raise ArgumentError, ":port must be specified." unless args[:port]
     raise "Mongrel server is already listening" if listening?
 
-    @protocols = args[:protocols]
-    @xmlrpc_handlers = args[:xmlrpc_handlers]
     @server = Mongrel::HttpServer.new(args[:address], args[:port])
-    setup_handlers
+    @server.register('/', Puppet::Network::HTTP::MongrelREST.new(:server => @server))
 
     @listening = true
     @server.run
@@ -32,24 +29,4 @@ def unlisten
   def listening?
     @listening
   end
-
-  private
-
-  def setup_handlers
-    # Register our REST support at /
-    klass = class_for_protocol(:rest)
-    @server.register('/', klass.new(:server => @server))
-
-    setup_xmlrpc_handlers if @protocols.include?(:xmlrpc) and ! @xmlrpc_handlers.empty?
-  end
-
-  # Use our existing code to provide the xmlrpc backward compatibility.
-  def setup_xmlrpc_handlers
-    @server.register('/RPC2', Puppet::Network::HTTPServer::Mongrel.new(@xmlrpc_handlers))
-  end
-
-  def class_for_protocol(protocol)
-    return Puppet::Network::HTTP::MongrelREST if protocol.to_sym == :rest
-    raise ArgumentError, "Unknown protocol [#{protocol}]."
-  end
 end
diff --git a/lib/puppet/network/http/rack.rb b/lib/puppet/network/http/rack.rb
index 5b4ef7e..63b6119 100644
--- a/lib/puppet/network/http/rack.rb
+++ b/lib/puppet/network/http/rack.rb
@@ -4,31 +4,9 @@
 
 require 'puppet/network/http'
 require 'puppet/network/http/rack/rest'
-require 'puppet/network/http/rack/xmlrpc'
 
 # An rack application, for running the Puppet HTTP Server.
 class Puppet::Network::HTTP::Rack
-
-  def initialize(args)
-    raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
-    protocols = args[:protocols]
-
-    # Always prepare a REST handler
-    @rest_http_handler = Puppet::Network::HTTP::RackREST.new
-    protocols.delete :rest
-
-    # Prepare the XMLRPC handler, for backward compatibility (if requested)
-    @xmlrpc_path = '/RPC2'
-    if args[:protocols].include?(:xmlrpc)
-      raise ArgumentError, "XMLRPC was requested, but no handlers were given" if !args.include?(:xmlrpc_handlers)
-
-      @xmlrpc_http_handler = Puppet::Network::HTTP::RackXMLRPC.new(args[:xmlrpc_handlers])
-      protocols.delete :xmlrpc
-    end
-
-    raise ArgumentError, "there were unknown :protocols specified." if !protocols.empty?
-  end
-
   # The real rack application (which needs to respond to call).
   # The work we need to do, roughly is:
   # * Read request (from env) and prepare a response
@@ -39,16 +17,8 @@ def call(env)
     response = Rack::Response.new
     Puppet.debug 'Handling request: %s %s' % [request.request_method, request.fullpath]
 
-    # if we shall serve XMLRPC, have /RPC2 go to the xmlrpc handler
-    if @xmlrpc_http_handler and @xmlrpc_path == request.path_info[0, @xmlrpc_path.size]
-      handler = @xmlrpc_http_handler
-    else
-      # everything else is handled by the new REST handler
-      handler = @rest_http_handler
-    end
-
     begin
-      handler.process(request, response)
+      Puppet::Network::HTTP::RackREST.new.process(request, response)
     rescue => detail
       # Send a Status 500 Error on unhandled exceptions.
       response.status = 500
diff --git a/lib/puppet/network/http/rack/httphandler.rb b/lib/puppet/network/http/rack/httphandler.rb
index c540623..e4fa93a 100644
--- a/lib/puppet/network/http/rack/httphandler.rb
+++ b/lib/puppet/network/http/rack/httphandler.rb
@@ -3,9 +3,6 @@
 
 class Puppet::Network::HTTP::RackHttpHandler
 
-  def initialize
-  end
-
   # do something useful with request (a Rack::Request) and use
   # response to fill your Rack::Response
   def process(request, response)
diff --git a/lib/puppet/network/http/rack/xmlrpc.rb b/lib/puppet/network/http/rack/xmlrpc.rb
deleted file mode 100644
index f753427..0000000
--- a/lib/puppet/network/http/rack/xmlrpc.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require 'puppet/network/http/rack/httphandler'
-require 'puppet/network/xmlrpc/server'
-require 'resolv'
-
-class Puppet::Network::HTTP::RackXMLRPC < Puppet::Network::HTTP::RackHttpHandler
-  def initialize(handlers)
-    @xmlrpc_server = Puppet::Network::XMLRPCServer.new
-    handlers.each do |name|
-      Puppet.debug "  -> register xmlrpc namespace #{name}"
-      unless handler = Puppet::Network::Handler.handler(name)
-        raise ArgumentError, "Invalid XMLRPC handler #{name}"
-      end
-      @xmlrpc_server.add_handler(handler.interface, handler.new({}))
-    end
-    super()
-  end
-
-  def process(request, response)
-    # errors are sent as text/plain
-    response['Content-Type'] = 'text/plain'
-    if not request.post?
-      response.status = 405
-      response.write 'Method Not Allowed'
-      return
-    end
-    if request.media_type != "text/xml"
-      response.status = 400
-      response.write 'Bad Request'
-      return
-    end
-
-    # get auth/certificate data
-    client_request = build_client_request(request)
-
-    response_body = @xmlrpc_server.process(request.body.read, client_request)
-
-    response.status = 200
-    response['Content-Type'] =  'text/xml; charset=utf-8'
-    response.write response_body
-  end
-
-  def build_client_request(request)
-    ip = request.ip
-
-    # if we find SSL info in the headers, use them to get a hostname.
-    # try this with :ssl_client_header, which defaults should work for
-    # Apache with StdEnvVars.
-    if dn = request.env[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
-      node = dn_matchdata[1].to_str
-      authenticated = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
-    else
-      begin
-        node = Resolv.getname(ip)
-      rescue => detail
-        Puppet.err "Could not resolve #{ip}: #{detail}"
-        node = "unknown"
-      end
-      authenticated = false
-    end
-
-    Puppet::Network::ClientRequest.new(node, ip, authenticated)
-  end
-
-end
-
diff --git a/lib/puppet/network/http/webrick.rb b/lib/puppet/network/http/webrick.rb
index 52aec1b..6cbc7a8 100644
--- a/lib/puppet/network/http/webrick.rb
+++ b/lib/puppet/network/http/webrick.rb
@@ -1,7 +1,6 @@
 require 'webrick'
 require 'webrick/https'
 require 'puppet/network/http/webrick/rest'
-require 'puppet/network/xmlrpc/webrick_servlet'
 require 'thread'
 
 require 'puppet/ssl/certificate'
@@ -13,19 +12,10 @@ def initialize(args = {})
     @mutex = Mutex.new
   end
 
-  def self.class_for_protocol(protocol)
-    return Puppet::Network::HTTP::WEBrickREST if protocol.to_sym == :rest
-    raise "Unknown protocol [#{protocol}]."
-  end
-
   def listen(args = {})
-    raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
     raise ArgumentError, ":address must be specified." unless args[:address]
     raise ArgumentError, ":port must be specified." unless args[:port]
 
-    @protocols = args[:protocols]
-    @xmlrpc_handlers = args[:xmlrpc_handlers]
-
     arguments = {:BindAddress => args[:address], :Port => args[:port]}
     arguments.merge!(setup_logger)
     arguments.merge!(setup_ssl)
@@ -33,7 +23,7 @@ def listen(args = {})
     @server = WEBrick::HTTPServer.new(arguments)
     @server.listeners.each { |l| l.start_immediately = false }
 
-    setup_handlers
+    @server.mount('/', Puppet::Network::HTTP::WEBrickREST, :this_value_is_apparently_necessary_but_unused)
 
     @mutex.synchronize do
       raise "WEBrick server is already listening" if @listening
@@ -114,26 +104,4 @@ def setup_ssl
 
     results
   end
-
-  private
-
-  def setup_handlers
-    # Set up the new-style protocols.
-    klass = self.class.class_for_protocol(:rest)
-    @server.mount('/', klass, :this_value_is_apparently_necessary_but_unused)
-
-    # And then set up xmlrpc, if configured.
-    @server.mount("/RPC2", xmlrpc_servlet) if @protocols.include?(:xmlrpc) and ! @xmlrpc_handlers.empty?
-  end
-
-  # Create our xmlrpc servlet, which provides backward compatibility.
-  def xmlrpc_servlet
-    handlers = @xmlrpc_handlers.collect { |handler|
-      unless hclass = Puppet::Network::Handler.handler(handler)
-        raise "Invalid xmlrpc handler #{handler}"
-      end
-      hclass.new({})
-    }
-    Puppet::Network::XMLRPC::WEBrickServlet.new handlers
-  end
 end
diff --git a/lib/puppet/network/http_server.rb b/lib/puppet/network/http_server.rb
deleted file mode 100644
index e3826a6..0000000
--- a/lib/puppet/network/http_server.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# Just a stub, so we can correctly scope other classes.
-module Puppet::Network::HTTPServer # :nodoc:
-end
diff --git a/lib/puppet/network/http_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb
deleted file mode 100644
index fb95164..0000000
--- a/lib/puppet/network/http_server/mongrel.rb
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/usr/bin/env ruby
-# File:       06-11-14-mongrel_xmlrpc.rb
-# Author:     Manuel Holtgrewe <purestorm at ggnore.net>
-#
-# Copyright (c) 2006 Manuel Holtgrewe, 2007 Luke Kanies
-#
-# This file is based heavily on a file retrieved from
-# http://ttt.ggnore.net/2006/11/15/xmlrpc-with-mongrel-and-ruby-off-rails/
-
-require 'rubygems'
-require 'mongrel'
-require 'xmlrpc/server'
-require 'puppet/network/xmlrpc/server'
-require 'puppet/network/http_server'
-require 'puppet/network/client_request'
-require 'puppet/network/handler'
-
-require 'resolv'
-
-# This handler can be hooked into Mongrel to accept HTTP requests. After
-# checking whether the request itself is sane, the handler forwards it
-# to an internal instance of XMLRPC::BasicServer to process it.
-#
-# You can access the server by calling the Handler's "xmlrpc_server"
-# attribute accessor method and add XMLRPC handlers there. For example:
-#
-# <pre>
-# handler = XmlRpcHandler.new
-# handler.xmlrpc_server.add_handler("my.add") { |a, b| a.to_i + b.to_i }
-# </pre>
-module Puppet::Network
-  class HTTPServer::Mongrel < ::Mongrel::HttpHandler
-    attr_reader :xmlrpc_server
-
-    def initialize(handlers)
-      if Puppet[:debug]
-        $mongrel_debug_client = true
-        Puppet.debug 'Mongrel client debugging enabled. [$mongrel_debug_client = true].'
-      end
-      # Create a new instance of BasicServer. We are supposed to subclass it
-      # but that does not make sense since we would not introduce any new
-      # behaviour and we have to subclass Mongrel::HttpHandler so our handler
-      # works for Mongrel.
-      @xmlrpc_server = Puppet::Network::XMLRPCServer.new
-      handlers.each do |name|
-        unless handler = Puppet::Network::Handler.handler(name)
-          raise ArgumentError, "Invalid handler #{name}"
-        end
-        @xmlrpc_server.add_handler(handler.interface, handler.new({}))
-      end
-    end
-
-    # This method produces the same results as XMLRPC::CGIServer.serve
-    # from Ruby's stdlib XMLRPC implementation.
-    def process(request, response)
-      # Make sure this has been a POST as required for XMLRPC.
-      request_method = request.params[Mongrel::Const::REQUEST_METHOD] || Mongrel::Const::GET
-      if request_method != "POST"
-        response.start(405) { |head, out| out.write("Method Not Allowed") }
-        return
-      end
-
-      # Make sure the user has sent text/xml data.
-      request_mime = request.params["CONTENT_TYPE"] || "text/plain"
-      if parse_content_type(request_mime).first != "text/xml"
-        response.start(400) { |head, out| out.write("Bad Request") }
-        return
-      end
-
-      # Make sure there is data in the body at all.
-      length = request.params[Mongrel::Const::CONTENT_LENGTH].to_i
-      if length <= 0
-        response.start(411) { |head, out| out.write("Length Required") }
-        return
-      end
-
-      # Check the body to be valid.
-      if request.body.nil? or request.body.size != length
-        response.start(400) { |head, out| out.write("Bad Request") }
-        return
-      end
-
-      info = client_info(request)
-
-      # All checks above passed through
-      response.start(200) do |head, out|
-        head["Content-Type"] = "text/xml; charset=utf-8"
-        begin
-          out.write(@xmlrpc_server.process(request.body, info))
-        rescue => detail
-          puts detail.backtrace
-          raise
-        end
-      end
-    end
-
-    private
-
-    def client_info(request)
-      params = request.params
-      ip = params["HTTP_X_FORWARDED_FOR"] ? params["HTTP_X_FORWARDED_FOR"].split(',').last.strip : params["REMOTE_ADDR"]
-      # JJM #906 The following dn.match regular expression is forgiving
-      # enough to match the two Distinguished Name string contents
-      # coming from Apache, Pound or other reverse SSL proxies.
-      if dn = params[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
-        client = dn_matchdata[1].to_str
-        valid = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
-      else
-        begin
-          client = Resolv.getname(ip)
-        rescue => detail
-          Puppet.err "Could not resolve #{ip}: #{detail}"
-          client = "unknown"
-        end
-        valid = false
-      end
-
-      info = Puppet::Network::ClientRequest.new(client, ip, valid)
-
-      info
-    end
-
-    # Taken from XMLRPC::ParseContentType
-    def parse_content_type(str)
-      a, *b = str.split(";")
-      return a.strip, *b
-    end
-  end
-end
diff --git a/lib/puppet/network/resolver.rb b/lib/puppet/network/resolver.rb
new file mode 100644
index 0000000..0e0460e
--- /dev/null
+++ b/lib/puppet/network/resolver.rb
@@ -0,0 +1,85 @@
+require 'resolv'
+module Puppet::Network; end
+
+module Puppet::Network::Resolver
+  # Iterate through the list of servers that service this hostname
+  # and yield each server/port since SRV records have ports in them
+  # It will override whatever masterport setting is already set.
+  def self.each_srv_record(domain, service_name = :puppet, &block)
+    if (domain.nil? or domain.empty?)
+      Puppet.debug "Domain not known; skipping SRV lookup"
+      return
+    end
+
+    Puppet.debug "Searching for SRV records for domain: #{domain}"
+
+    case service_name
+      when :puppet then service = '_x-puppet'
+      when :ca     then service = '_x-puppet-ca'
+      when :report then service = '_x-puppet-report'
+      when :file   then service = '_x-puppet-fileserver'
+    end
+    srv_record = "#{service}._tcp.#{domain}"
+
+    resolver = Resolv::DNS.new
+    records = resolver.getresources(srv_record, Resolv::DNS::Resource::IN::SRV)
+    Puppet.debug "Found #{records.size} SRV records for: #{srv_record}"
+
+    if records.size == 0 && service_name != :puppet
+      # Try the generic :puppet service if no SRV records were found
+      # for the specific service.
+      each_srv_record(domain, :puppet, &block)
+    else
+      each_priority(records) do |priority, records|
+        while next_rr = records.delete(find_weighted_server(records))
+          Puppet.debug "Yielding next server of #{next_rr.target.to_s}:#{next_rr.port}"
+          yield next_rr.target.to_s, next_rr.port
+        end
+      end
+    end
+  end
+
+  private
+
+  def self.each_priority(records)
+    pri_hash = records.inject({}) do |groups, element|
+      groups[element.priority] ||= []
+      groups[element.priority] << element
+      groups
+    end
+
+    pri_hash.keys.sort.each do |key|
+      yield key, pri_hash[key]
+    end
+  end
+
+  def self.find_weighted_server(records)
+    return nil if records.nil? || records.empty?
+    return records.first if records.size == 1
+
+    # Calculate the sum of all weights in the list of resource records,
+    # This is used to then select hosts until the weight exceeds what
+    # random number we selected.  For example, if we have weights of 1 8 and 3:
+    #
+    # |-|---|--------|
+    #        ^
+    # We generate a random number 5, and iterate through the records, adding
+    # the current record's weight to the accumulator until the weight of the
+    # current record plus previous records is greater than the random number.
+
+    total_weight = records.inject(0) { |sum,record|
+      sum + weight(record)
+    }
+    current_weight = 0
+    chosen_weight  = 1 + Kernel.rand(total_weight)
+
+    records.each do |record|
+      current_weight += weight(record)
+      return record if current_weight >= chosen_weight
+    end
+  end
+
+  def self.weight(record)
+    record.weight == 0 ? 1 : record.weight * 10
+  end
+end
diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb
index 8016710..94bc60d 100644
--- a/lib/puppet/network/rest_authconfig.rb
+++ b/lib/puppet/network/rest_authconfig.rb
@@ -42,10 +42,6 @@ def allowed?(request)
     def check_authorization(indirection, method, key, params)
       read
 
-      # we're splitting the request in part because
-      # fail_on_deny could as well be called in the XMLRPC context
-      # with a ClientRequest.
-
       if authorization_failure_exception = @rights.is_request_forbidden_and_why?(indirection, method, key, params)
         Puppet.warning("Denying access: #{authorization_failure_exception}")
         raise authorization_failure_exception
diff --git a/lib/puppet/network/rights.rb b/lib/puppet/network/rights.rb
index 6fde181..086ac74 100755
--- a/lib/puppet/network/rights.rb
+++ b/lib/puppet/network/rights.rb
@@ -190,7 +190,7 @@ def regex?
     def allowed?(name, ip, args = {})
       return :dunno if acl_type == :regex and not @methods.include?(args[:method])
       return :dunno if acl_type == :regex and @environment.size > 0 and not @environment.include?(args[:environment])
-      return :dunno if acl_type == :regex and not @authentication.nil? and args[:authenticated] != @authentication
+      return :dunno if acl_type == :regex and (@authentication and not args[:authenticated])
 
       begin
         # make sure any capture are replaced if needed
@@ -229,10 +229,8 @@ def restrict_authenticated(authentication)
       case authentication
       when "yes", "on", "true", true
         authentication = true
-      when "no", "off", "false", false
+      when "no", "off", "false", false, "all" ,"any", :all, :any
         authentication = false
-      when "all","any", :all, :any
-        authentication = nil
       else
         raise ArgumentError, "'#{name}' incorrect authenticated value: #{authentication}"
       end
diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb
index e4de07d..87952f9 100644
--- a/lib/puppet/network/server.rb
+++ b/lib/puppet/network/server.rb
@@ -2,7 +2,7 @@
 require 'puppet/util/pidlock'
 
 class Puppet::Network::Server
-  attr_reader :server_type, :protocols, :address, :port
+  attr_reader :server_type, :address, :port
 
   # Put the daemon into the background.
   def daemonize
@@ -51,7 +51,7 @@ def pidfile
   end
 
   def initialize(args = {})
-    valid_args = [:handlers, :xmlrpc_handlers, :port]
+    valid_args = [:handlers, :port]
     bad_args = args.keys.find_all { |p| ! valid_args.include?(p) }.collect { |p| p.to_s }.join(",")
     raise ArgumentError, "Invalid argument(s) #{bad_args}" unless bad_args == ""
     @server_type = Puppet[:servertype] or raise "No servertype configuration found."  # e.g.,  WEBrick, Mongrel, etc.
@@ -60,12 +60,9 @@ def initialize(args = {})
     @port = args[:port] || Puppet[:masterport] || raise(ArgumentError, "Must specify :port or configure Puppet :masterport")
     @address = determine_bind_address
 
-    @protocols = [ :rest, :xmlrpc ]
     @listening = false
     @routes = {}
-    @xmlrpc_routes = {}
     self.register(args[:handlers]) if args[:handlers]
-    self.register_xmlrpc(args[:xmlrpc_handlers]) if args[:xmlrpc_handlers]
 
     # Make sure we have all of the directories we need to function.
     Puppet.settings.use(:main, :ssl, Puppet[:name])
@@ -94,29 +91,6 @@ def unregister(*indirections)
     end
   end
 
-  # Register xmlrpc handlers for backward compatibility.
-  def register_xmlrpc(*namespaces)
-    raise ArgumentError, "XMLRPC namespaces are required." if namespaces.empty?
-    namespaces.flatten.each do |name|
-      Puppet::Network::Handler.handler(name) || raise(ArgumentError, "Cannot locate XMLRPC handler for namespace '#{name}'.")
-      @xmlrpc_routes[name.to_sym] = true
-    end
-  end
-
-  # Unregister xmlrpc handlers.
-  def unregister_xmlrpc(*namespaces)
-    raise "Cannot unregister xmlrpc handlers while server is listening." if listening?
-    namespaces = @xmlrpc_routes.keys if namespaces.empty?
-
-    namespaces.flatten.each do |i|
-      raise(ArgumentError, "XMLRPC handler '#{i}' is unknown.") unless @xmlrpc_routes[i.to_sym]
-    end
-
-    namespaces.flatten.each do |i|
-      @xmlrpc_routes.delete(i.to_sym)
-    end
-  end
-
   def listening?
     @listening
   end
@@ -124,7 +98,7 @@ def listening?
   def listen
     raise "Cannot listen -- already listening." if listening?
     @listening = true
-    http_server.listen(:address => address, :port => port, :handlers => @routes.keys, :xmlrpc_handlers => @xmlrpc_routes.keys, :protocols => protocols)
+    http_server.listen(:address => address, :port => port, :handlers => @routes.keys)
   end
 
   def unlisten
diff --git a/lib/puppet/network/xmlrpc/processor.rb b/lib/puppet/network/xmlrpc/processor.rb
deleted file mode 100644
index dea8a02..0000000
--- a/lib/puppet/network/xmlrpc/processor.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-require 'puppet/network/authorization'
-require 'xmlrpc/server'
-
-# Just silly.
-class ::XMLRPC::FaultException
-  def to_s
-    self.message
-  end
-end
-
-module Puppet::Network
-  # Most of our subclassing is just so that we can get
-  # access to information from the request object, like
-  # the client name and IP address.
-  module XMLRPCProcessor
-    include Puppet::Network::Authorization
-
-    ERR_UNAUTHORIZED = 30
-
-    def add_handler(interface, handler)
-      @loadedhandlers << interface.prefix
-      super(interface, handler)
-    end
-
-    def handler_loaded?(handler)
-      @loadedhandlers.include?(handler.to_s)
-    end
-
-    # Convert our data and client request into xmlrpc calls, and verify
-    # they're authorized and such-like.  This method differs from the
-    # default in that it expects a ClientRequest object in addition to the
-    # data.
-    def process(data, request)
-      call, params = parser.parseMethodCall(data)
-      params << request.name << request.ip
-      handler, method = call.split(".")
-      request.handler = handler
-      request.method = method
-      begin
-        verify(request)
-      rescue InvalidClientRequest => detail
-        raise ::XMLRPC::FaultException.new(ERR_UNAUTHORIZED, detail.to_s)
-      end
-      handle(request.call, *params)
-    end
-
-    private
-
-    # Provide error handling for method calls.
-    def protect_service(obj, *args)
-      begin
-        obj.call(*args)
-      rescue ::XMLRPC::FaultException
-        raise
-      rescue Puppet::AuthorizationError => detail
-        Puppet.err "Permission denied: #{detail}"
-        raise ::XMLRPC::FaultException.new(
-          1, detail.to_s
-        )
-      rescue Puppet::Error => detail
-        puts detail.backtrace if Puppet[:trace]
-        Puppet.err detail.to_s
-        error = ::XMLRPC::FaultException.new(
-          1, detail.to_s
-        )
-        error.set_backtrace detail.backtrace
-        raise error
-      rescue => detail
-        puts detail.backtrace if Puppet[:trace]
-        Puppet.err "Could not call: #{detail}"
-        error = ::XMLRPC::FaultException.new(1, detail.to_s)
-        error.set_backtrace detail.backtrace
-        raise error
-      end
-    end
-
-    # Set up our service hook and init our handler list.
-    def setup_processor
-      @loadedhandlers = []
-      self.set_service_hook do |obj, *args|
-        protect_service(obj, *args)
-      end
-    end
-  end
-end
-
diff --git a/lib/puppet/network/xmlrpc/server.rb b/lib/puppet/network/xmlrpc/server.rb
deleted file mode 100644
index e548817..0000000
--- a/lib/puppet/network/xmlrpc/server.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'xmlrpc/server'
-require 'puppet/network/authorization'
-require 'puppet/network/xmlrpc/processor'
-
-module Puppet::Network
-  # Most of our subclassing is just so that we can get
-  # access to information from the request object, like
-  # the client name and IP address.
-  class XMLRPCServer < ::XMLRPC::BasicServer
-    include Puppet::Util
-    include Puppet::Network::XMLRPCProcessor
-
-    def initialize
-      super()
-      setup_processor
-    end
-  end
-end
-
diff --git a/lib/puppet/network/xmlrpc/webrick_servlet.rb b/lib/puppet/network/xmlrpc/webrick_servlet.rb
deleted file mode 100644
index c538cf7..0000000
--- a/lib/puppet/network/xmlrpc/webrick_servlet.rb
+++ /dev/null
@@ -1,114 +0,0 @@
-require 'xmlrpc/server'
-require 'puppet/network/authorization'
-require 'puppet/network/xmlrpc/processor'
-
-module Puppet::Network::XMLRPC
-  class ServletError < RuntimeError; end
-  class WEBrickServlet < ::XMLRPC::WEBrickServlet
-    include Puppet::Network::XMLRPCProcessor
-
-    # This is a hackish way to avoid an auth message every time we have a
-    # normal operation
-    def self.log(msg)
-      @logs ||= {}
-      if @logs.include?(msg)
-        @logs[msg] += 1
-      else
-        Puppet.info msg
-        @logs[msg] = 1
-      end
-    end
-
-    # Accept a list of handlers and register them all.
-    def initialize(handlers)
-      # the servlet base class does not consume any arguments
-      # and its BasicServer base class only accepts a 'class_delim'
-      # option which won't change in Puppet at all
-      # thus, we don't need to pass any args to our base class,
-      # and we can consume them all ourselves
-      super()
-
-      setup_processor
-
-      # Set up each of the passed handlers.
-      handlers.each do |handler|
-        add_handler(handler.class.interface, handler)
-      end
-    end
-
-    # Handle the actual request.  We can't use the super() method, because
-    # we need to pass a ClientRequest object to process so we can do
-    # authorization.  It's the only way to stay thread-safe.
-    def service(request, response)
-      if @valid_ip
-        raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
-      end
-
-      if request.request_method != "POST"
-        raise WEBrick::HTTPStatus::MethodNotAllowed,
-          "unsupported method `#{request.request_method}'."
-      end
-
-      raise WEBrick::HTTPStatus::BadRequest if parse_content_type(request['Content-type']).first != "text/xml"
-
-      length = (request['Content-length'] || 0).to_i
-
-      raise WEBrick::HTTPStatus::LengthRequired unless length > 0
-
-      data = request.body
-
-      raise WEBrick::HTTPStatus::BadRequest if data.nil? or data.size != length
-
-      resp = process(data, client_request(request))
-      raise WEBrick::HTTPStatus::InternalServerError if resp.nil? or resp.size <= 0
-
-      response.status = 200
-      response['Content-Length'] = resp.size
-      response['Content-Type']   = "text/xml; charset=utf-8"
-      response.body = resp
-    end
-
-    private
-
-    # Generate a ClientRequest object for later validation.
-    def client_request(request)
-      if peer = request.peeraddr
-        client = peer[2]
-        clientip = peer[3]
-      else
-
-              raise ::XMLRPC::FaultException.new(
-                
-          ERR_UNCAUGHT_EXCEPTION,
-        
-          "Could not retrieve client information"
-        )
-      end
-
-      # If they have a certificate (which will almost always be true)
-      # then we get the hostname from the cert, instead of via IP
-      # info
-      valid = false
-      if cert = request.client_cert
-        nameary = cert.subject.to_a.find { |ary|
-          ary[0] == "CN"
-        }
-
-        if nameary.nil?
-          Puppet.warning "Could not retrieve server name from cert"
-        else
-          unless client == nameary[1]
-            Puppet.debug "Overriding #{client} with cert name #{nameary[1]}"
-            client = nameary[1]
-          end
-          valid = true
-        end
-      end
-
-      info = Puppet::Network::ClientRequest.new(client, clientip, valid)
-
-      info
-    end
-  end
-end
-
diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb
index 5b0a986..16a0e5c 100644
--- a/lib/puppet/node.rb
+++ b/lib/puppet/node.rb
@@ -19,6 +19,32 @@ class Puppet::Node
 
   attr_accessor :name, :classes, :source, :ipaddress, :parameters
   attr_reader :time
+  #
+  # Load json before trying to register.
+  Puppet.features.pson? and ::PSON.register_document_type('Node',self)
+
+  def self.from_pson(pson)
+    raise ArgumentError, "No name provided in pson data" unless name = pson['name']
+
+    node = new(name)
+    node.classes = pson['classes']
+    node.parameters = pson['parameters']
+    node.environment = pson['environment']
+    node
+  end
+
+  def to_pson(*args)
+    result = {
+      'document_type' => "Node",
+      'data' => {}
+    }
+    result['data']['name'] = name
+    result['data']['classes'] = classes unless classes.empty?
+    result['data']['parameters'] = parameters unless parameters.empty?
+    result['data']['environment'] = environment.name
+
+    result.to_pson(*args)
+  end
 
   def environment
     return super if @environment
diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb
index 577b62b..8d0a034 100755
--- a/lib/puppet/node/facts.rb
+++ b/lib/puppet/node/facts.rb
@@ -61,18 +61,21 @@ def ==(other)
 
   def self.from_pson(data)
     result = new(data['name'], data['values'])
-    result.timestamp = Time.parse(data['timestamp'])
-    result.expiration = Time.parse(data['expiration'])
+    result.timestamp = Time.parse(data['timestamp']) if data['timestamp']
+    result.expiration = Time.parse(data['expiration']) if data['expiration']
     result
   end
 
   def to_pson(*args)
-    {
-      'expiration' => expiration,
+    result = {
       'name' => name,
-      'timestamp' => timestamp,
       'values' => strip_internal,
-    }.to_pson(*args)
+    }
+
+    result['timestamp'] = timestamp if timestamp
+    result['expiration'] = expiration if expiration
+
+    result.to_pson(*args)
   end
 
   # Add internal data to the facts for storage.
diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb
index c8ebc94..a729f82 100644
--- a/lib/puppet/parser/ast/leaf.rb
+++ b/lib/puppet/parser/ast/leaf.rb
@@ -124,10 +124,11 @@ class Variable < Name
     # not include syntactical constructs, like '$' and '{}').
     def evaluate(scope)
       parsewrap do
-        if (var = scope.lookupvar(@value, :file => file, :line => line)) == :undefined
-          var = :undef
+        if ! scope.include?(@value)
+          :undef
+        else
+          scope[@value, {:file => file, :line => line}]
         end
-        var
       end
     end
 
@@ -141,7 +142,7 @@ class HashOrArrayAccess < AST::Leaf
 
     def evaluate_container(scope)
       container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable
-      (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope.lookupvar(container, :file => file, :line => line)
+      (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope[container, {:file => file, :line => line}]
     end
 
     def evaluate_key(scope)
@@ -161,7 +162,7 @@ def evaluate(scope)
 
       raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array)
 
-      object[array_index_or_key(object, accesskey)]
+      object[array_index_or_key(object, accesskey)] || :undef
     end
 
     # Assign value to this hashkey or array index
diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb
index 8aee2e6..6dfcfdb 100644
--- a/lib/puppet/parser/compiler.rb
+++ b/lib/puppet/parser/compiler.rb
@@ -136,19 +136,21 @@ def evaluate_node_classes
   # evaluated later in the process.
   def evaluate_classes(classes, scope, lazy_evaluate = true)
     raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source
-    param_classes = nil
+    class_parameters = nil
     # if we are a param class, save the classes hash
     # and transform classes to be the keys
     if classes.class == Hash
-      param_classes = classes
+      class_parameters = classes
       classes = classes.keys
     end
     classes.each do |name|
       # If we can find the class, then make a resource that will evaluate it.
       if klass = scope.find_hostclass(name)
 
-        if param_classes
-          resource = klass.ensure_in_catalog(scope, param_classes[name] || {})
+        # If parameters are passed, then attempt to create a duplicate resource
+        # so the appropriate error is thrown.
+        if class_parameters
+          resource = klass.ensure_in_catalog(scope, class_parameters[name] || {})
         else
           next if scope.class_scope(klass)
           resource = klass.ensure_in_catalog(scope)
@@ -447,7 +449,7 @@ def initvars
   # Set the node's parameters into the top-scope as variables.
   def set_node_parameters
     node.parameters.each do |param, value|
-      @topscope.setvar(param, value)
+      @topscope[param] = value
     end
 
     # These might be nil.
@@ -470,7 +472,7 @@ def create_settings_scope
 
     Puppet.settings.each do |name, setting|
       next if name.to_s == "name"
-      scope.setvar name.to_s, environment[name]
+      scope[name.to_s] = environment[name]
     end
   end
 
diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb
index e19ac12..22eee70 100644
--- a/lib/puppet/parser/functions.rb
+++ b/lib/puppet/parser/functions.rb
@@ -29,8 +29,11 @@ def self.autoloader
   Environment = Puppet::Node::Environment
 
   def self.environment_module(env = nil)
+    if env and ! env.is_a?(Puppet::Node::Environment)
+      env = Puppet::Node::Environment.new(env)
+    end
     @modules.synchronize {
-      @modules[ env || Environment.current || Environment.root ] ||= Module.new
+      @modules[ (env || Environment.current || Environment.root).name ] ||= Module.new
     }
   end
 
diff --git a/lib/puppet/parser/functions/create_resources.rb b/lib/puppet/parser/functions/create_resources.rb
index 6467619..3c91b41 100644
--- a/lib/puppet/parser/functions/create_resources.rb
+++ b/lib/puppet/parser/functions/create_resources.rb
@@ -1,7 +1,7 @@
 Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC') do |args|
     Converts a hash into a set of resources and adds them to the catalog.
 
-    This function takes two arguments: a resource type, and a hash describing
+    This function takes two mandatory arguments: a resource type, and a hash describing
     a set of resources. The hash should be in the form `{title => {parameters} }`:
 
         # A hash of user resources:
@@ -14,13 +14,26 @@
                       groups => ['developers', 'prosvc', 'release'], }
         }
 
-        create_resource(user, $myusers)
+        create_resources(user, $myusers)
+
+    A third, optional parameter may be given, also as a hash:
+
+        $defaults => {
+          'ensure'   => present,
+          'provider' => 'ldap',
+        }
+
+        create_resources(user, $myusers, $defaults)
+
+    The values given on the third argument are added to the parameters of each resource
+    present in the set given on the second argument. If a parameter is present on both
+    the second and third arguments, the one on the second argument takes precedence.
 
     This function can be used to create defined resources and classes, as well
     as native resources.
   ENDHEREDOC
-  raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2
-  #raise ArgumentError, 'requires resource type and param hash' if args.size < 2
+  raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2 or 3)") if args.length < 2 || args.length > 3
+
   # figure out what kind of resource we are
   type_of_resource = nil
   type_name = args[0].downcase
@@ -36,8 +49,10 @@
     end
   end
   # iterate through the resources to create
+  defaults = args[2] || {}
   args[1].each do |title, params|
     raise ArgumentError, 'params should not contain title' if(params['title'])
+    params = defaults.merge(params)
     case type_of_resource
     # JJM The only difference between a type and a define is the call to instantiate_resource
     # for a defined type.
@@ -54,7 +69,7 @@
       klass = find_hostclass(title)
       raise ArgumentError, "could not find hostclass #{title}" unless klass
       klass.ensure_in_catalog(self, params)
-      compiler.catalog.add_class([title])
+      compiler.catalog.add_class(title)
     end
   end
 end
diff --git a/lib/puppet/parser/functions/extlookup.rb b/lib/puppet/parser/functions/extlookup.rb
index 5fbf26c..9ffca59 100644
--- a/lib/puppet/parser/functions/extlookup.rb
+++ b/lib/puppet/parser/functions/extlookup.rb
@@ -91,9 +91,9 @@ module Puppet::Parser::Functions
 
   raise Puppet::ParseError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3
 
-  extlookup_datadir = undef_as('',lookupvar('::extlookup_datadir'))
+  extlookup_datadir = undef_as('',self['::extlookup_datadir'])
 
-  extlookup_precedence = undef_as([],lookupvar('::extlookup_precedence')).collect { |var| var.gsub(/%\{(.+?)\}/) { lookupvar("::#{$1}") } }
+  extlookup_precedence = undef_as([],self['::extlookup_precedence']).collect { |var| var.gsub(/%\{(.+?)\}/) { self["::#{$1}"] } }
 
   datafiles = Array.new
 
@@ -121,9 +121,9 @@ module Puppet::Parser::Functions
           if result[0].length == 2
             val = result[0][1].to_s
 
-            # parse %{}'s in the CSV into local variables using lookupvar()
+            # parse %{}'s in the CSV into local variables using the current scope
             while val =~ /%\{(.+?)\}/
-              val.gsub!(/%\{#{$1}\}/, lookupvar($1))
+              val.gsub!(/%\{#{$1}\}/, self[$1])
             end
 
             desired = val
@@ -134,9 +134,9 @@ module Puppet::Parser::Functions
             # Individual cells in a CSV result are a weird data type and throws
             # puppets yaml parsing, so just map it all to plain old strings
             desired = cells.map do |c|
-              # parse %{}'s in the CSV into local variables using lookupvar()
+              # parse %{}'s in the CSV into local variables using the current scope
               while c =~ /%\{(.+?)\}/
-                c.gsub!(/%\{#{$1}\}/, lookupvar($1))
+                c.gsub!(/%\{#{$1}\}/, self[$1])
               end
 
               c.to_s
diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functions/fqdn_rand.rb
index 93ab98b..3b1df6d 100644
--- a/lib/puppet/parser/functions/fqdn_rand.rb
+++ b/lib/puppet/parser/functions/fqdn_rand.rb
@@ -6,7 +6,7 @@
       $random_number = fqdn_rand(30)
       $random_number_seed = fqdn_rand(30,30)") do |args|
     require 'digest/md5'
-    max = args.shift
-    srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex)
+    max = args.shift.to_i
+    srand(Digest::MD5.hexdigest([self['::fqdn'],args].join(':')).hex)
     rand(max).to_s
 end
diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb
index a068668..a7905a6 100644
--- a/lib/puppet/parser/functions/versioncmp.rb
+++ b/lib/puppet/parser/functions/versioncmp.rb
@@ -1,10 +1,7 @@
 require 'puppet/util/package'
 
-
-      Puppet::Parser::Functions::newfunction(
-        :versioncmp, :type => :rvalue,
-
-  :doc => "Compares two version numbers.
+Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, :doc =>
+"Compares two version numbers.
 
 Prototype:
 
diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb
index 4a19003..fae6edc 100644
--- a/lib/puppet/parser/resource.rb
+++ b/lib/puppet/parser/resource.rb
@@ -173,7 +173,7 @@ def set_parameter(param, value = nil)
         :name => param, :value => value, :source => self.source
       )
     elsif ! param.is_a?(Puppet::Parser::Resource::Param)
-      raise ArgumentError, "Must pass a parameter or all necessary values"
+      raise ArgumentError, "Received incomplete information - no value provided for parameter #{param}"
     end
 
     tag(*param.value) if param.name == :tag
@@ -230,15 +230,7 @@ def to_resource
     result
   end
 
-  # Translate our object to a transportable object.
-  def to_trans
-    return nil if virtual?
-
-    to_resource.to_trans
-  end
-
-  # Convert this resource to a RAL resource.  We hackishly go via the
-  # transportable stuff.
+  # Convert this resource to a RAL resource.
   def to_ral
     to_resource.to_ral
   end
@@ -258,7 +250,8 @@ def add_defaults
 
   def add_backward_compatible_relationship_param(name)
     # Skip metaparams for which we get no value.
-    return unless val = scope.lookupvar(name.to_s) and val != :undefined
+    return unless scope.include?(name.to_s)
+    val = scope[name.to_s]
 
     # The default case: just set the value
     set_parameter(name, val) and return unless @parameters[name]
diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb
index 746cfbd..cbc9336 100644
--- a/lib/puppet/parser/scope.rb
+++ b/lib/puppet/parser/scope.rb
@@ -3,7 +3,6 @@
 
 require 'puppet/parser/parser'
 require 'puppet/parser/templatewrapper'
-require 'puppet/transportable'
 require 'strscan'
 
 require 'puppet/resource/type_collection_helper'
@@ -48,13 +47,42 @@ def [](name)
     end
   end
 
+  def [](name, options = {})
+    table = ephemeral?(name) ? @ephemeral.last : @symtable
+    # If the variable is qualified, then find the specified scope and look the variable up there instead.
+    if name =~ /^(.*)::(.+)$/
+      begin
+        qualified_scope($1)[$2,options]
+      rescue RuntimeError => e
+        location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : ''
+        warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}"
+        nil
+      end
+    elsif ephemeral_include?(name) or table.include?(name)
+      # We can't use "if table[name]" here because the value might be false
+      if options[:dynamic] and self != compiler.topscope
+        location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : ''
+        Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated.  Support will be removed in Puppet 2.8.  Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes."
+      end
+      table[name]
+    elsif parent
+      parent[name,options.merge(:dynamic => (dynamic || options[:dynamic]))]
+    else
+      nil
+    end
+  end
+
+  def []=(var, value)
+    setvar(var, value)
+  end
+
   # A demeterific shortcut to the catalog.
   def catalog
     compiler.catalog
   end
 
-  def environment
-    compiler.environment
+  def each
+    to_hash.each { |name, value| yield(name, value) }
   end
 
   # Proxy accessors
@@ -62,6 +90,10 @@ def host
     @compiler.node.name
   end
 
+  def include?(name)
+    ! self[name].nil?
+  end
+
   # Is the value true?  This allows us to control the definition of truth
   # in one place.
   def self.true?(value)
@@ -101,7 +133,7 @@ def add_namespace(ns)
 
   # Remove this when rebasing
   def environment
-    compiler ? compiler.environment : nil
+    compiler ? compiler.environment : Puppet::Node::Environment.new
   end
 
   def find_hostclass(name)
@@ -211,7 +243,11 @@ def lookuptype(name)
   end
 
   def undef_as(x,v)
-    (v == :undefined) ? x : (v == :undef) ? x : v
+    if v.nil? or v == :undef
+      x
+    else
+      v
+    end
   end
 
   def qualified_scope(classname)
@@ -223,29 +259,9 @@ def qualified_scope(classname)
   private :qualified_scope
 
   # Look up a variable.  The simplest value search we do.
+  # This method is effectively deprecated - use self[] instead.
   def lookupvar(name, options = {})
-    table = ephemeral?(name) ? @ephemeral.last : @symtable
-    # If the variable is qualified, then find the specified scope and look the variable up there instead.
-    if name =~ /^(.*)::(.+)$/
-      begin
-        qualified_scope($1).lookupvar($2,options)
-      rescue RuntimeError => e
-        location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : ''
-        warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}"
-        :undefined
-      end
-    elsif ephemeral_include?(name) or table.include?(name)
-      # We can't use "if table[name]" here because the value might be false
-      if options[:dynamic] and self != compiler.topscope
-        location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : ''
-        Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated.  Support will be removed in Puppet 2.8.  Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes."
-      end
-      table[name]
-    elsif parent
-      parent.lookupvar(name,options.merge(:dynamic => (dynamic || options[:dynamic])))
-    else
-      :undefined
-    end
+    self[name, options]
   end
 
   # Return a hash containing our variables and their values, optionally (and
@@ -312,6 +328,8 @@ def setdefaults(type, params)
   # Set a variable in the current scope.  This will override settings
   # in scopes above, but will not allow variables in the current scope
   # to be reassigned.
+  #   It's preferred that you use self[]= instead of this; only use this
+  # when you need to set options.
   def setvar(name,value, options = {})
     table = options[:ephemeral] ? @ephemeral.last : @symtable
     if table.include?(name)
@@ -329,7 +347,7 @@ def setvar(name,value, options = {})
       table[name] = value
     else # append case
       # lookup the value in the scope if it exists and insert the var
-      table[name] = undef_as('',lookupvar(name))
+      table[name] = undef_as('',self[name])
       # concatenate if string, append if array, nothing for other types
       case value
       when Array
@@ -453,6 +471,6 @@ def resolve_type_and_titles(type, titles)
 
   def extend_with_functions_module
     extend Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.root)
-    extend Puppet::Parser::Functions.environment_module(environment)
+    extend Puppet::Parser::Functions.environment_module(environment) if environment != Puppet::Node::Environment.root
   end
 end
diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb
index 27d75bf..9336e70 100644
--- a/lib/puppet/parser/templatewrapper.rb
+++ b/lib/puppet/parser/templatewrapper.rb
@@ -25,7 +25,7 @@ def script_line
 
   # Should return true if a variable is defined, false if it is not
   def has_variable?(name)
-    scope.lookupvar(name.to_s, :file => file, :line => script_line) != :undefined
+    scope.include?(name.to_s)
   end
 
   # Allow templates to access the defined classes
@@ -56,9 +56,8 @@ def all_tags
   # the missing_method definition here until we declare the syntax finally
   # dead.
   def method_missing(name, *args)
-    value = scope.lookupvar(name.to_s,:file => file,:line => script_line)
-    if value != :undefined
-      return value
+    if scope.include?(name.to_s)
+      return scope[name.to_s, {:file => file,:line => script_line}]
     else
       # Just throw an error immediately, instead of searching for
       # other missingmethod things or whatever.
diff --git a/lib/puppet/provider.rb b/lib/puppet/provider.rb
index 4456feb..295ae83 100644
--- a/lib/puppet/provider.rb
+++ b/lib/puppet/provider.rb
@@ -204,15 +204,15 @@ def self.supports_parameter?(param)
 
   dochook(:defaults) do
     if @defaults.length > 0
-      return "  Default for " + @defaults.collect do |f, v|
-        "`#{f}` == `#{v}`"
+      return "Default for " + @defaults.collect do |f, v|
+        "`#{f}` == `#{[v].flatten.join(', ')}`"
       end.join(" and ") + "."
     end
   end
 
   dochook(:commands) do
     if @commands.length > 0
-      return "  Required binaries: " + @commands.collect do |n, c|
+      return "Required binaries: " + @commands.collect do |n, c|
         "`#{c}`"
       end.join(", ") + "."
     end
@@ -220,7 +220,7 @@ def self.supports_parameter?(param)
 
   dochook(:features) do
     if features.length > 0
-      return "  Supported features: " + features.collect do |f|
+      return "Supported features: " + features.collect do |f|
         "`#{f}`"
       end.join(", ") + "."
     end
diff --git a/lib/puppet/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb
index 7214a8b..6f5639a 100644
--- a/lib/puppet/provider/augeas/augeas.rb
+++ b/lib/puppet/provider/augeas/augeas.rb
@@ -17,10 +17,12 @@
 require 'strscan'
 require 'puppet/util'
 require 'puppet/util/diff'
+require 'puppet/util/package'
 
 Puppet::Type.type(:augeas).provide(:augeas) do
   include Puppet::Util
   include Puppet::Util::Diff
+  include Puppet::Util::Package
 
   confine :true => Puppet.features.augeas?
 
@@ -143,19 +145,39 @@ def open_augeas
     unless @aug
       flags = Augeas::NONE
       flags = Augeas::TYPE_CHECK if resource[:type_check] == :true
-      flags |= Augeas::NO_MODL_AUTOLOAD if resource[:incl]
+
+      if resource[:incl]
+        flags |= Augeas::NO_MODL_AUTOLOAD
+      else
+        flags |= Augeas::NO_LOAD
+      end
+
       root = resource[:root]
       load_path = resource[:load_path]
       debug("Opening augeas with root #{root}, lens path #{load_path}, flags #{flags}")
       @aug = Augeas::open(root, load_path,flags)
 
-      debug("Augeas version #{get_augeas_version} is installed") if get_augeas_version >= "0.3.6"
+      debug("Augeas version #{get_augeas_version} is installed") if versioncmp(get_augeas_version, "0.3.6") >= 0
+
+      glob_avail = !aug.match("/augeas/version/pathx/functions/glob").empty?
 
       if resource[:incl]
         aug.set("/augeas/load/Xfm/lens", resource[:lens])
         aug.set("/augeas/load/Xfm/incl", resource[:incl])
-        aug.load
+      elsif glob_avail and resource[:context] and resource[:context].match("^/files/")
+        # Optimize loading if the context is given, requires the glob function
+        # from Augeas 0.8.2 or up
+        ctx_path = resource[:context].sub(/^\/files(.*?)\/?$/, '\1/')
+        load_path = "/augeas/load/*['%s' !~ glob(incl) + regexp('/.*')]" % ctx_path
+
+        if aug.match(load_path).size < aug.match("/augeas/load/*").size
+          aug.rm(load_path)
+        else
+          # This will occur if the context is less specific than any glob
+          debug("Unable to optimize files loaded by context path, no glob matches")
+        end
       end
+      aug.load
     end
     @aug
   end
@@ -259,6 +281,18 @@ def set_augeas_save_mode(mode)
     @aug.set("/augeas/save", mode)
   end
 
+  def print_put_errors
+    errors = @aug.match("/augeas//error[. = 'put_failed']")
+    debug("Put failed on one or more files, output from /augeas//error:") unless errors.empty?
+    errors.each do |errnode|
+      @aug.match("#{errnode}/*").each do |subnode|
+        sublabel = subnode.split("/")[-1]
+        subvalue = @aug.get(subnode)
+        debug("#{sublabel} = #{subvalue}")
+      end
+    end
+  end
+
   # Determines if augeas acutally needs to run.
   def need_to_run?
     force = resource[:force]
@@ -285,18 +319,21 @@ def need_to_run?
         # If we have a verison of augeas which is at least 0.3.6 then we
         # can make the changes now, see if changes were made, and
         # actually do the save.
-        if return_value and get_augeas_version >= "0.3.6"
+        if return_value and versioncmp(get_augeas_version, "0.3.6") >= 0
           debug("Will attempt to save and only run if files changed")
           set_augeas_save_mode(SAVE_NEWFILE)
           do_execute_changes
           save_result = @aug.save
-          fail("Save failed with return code #{save_result}") unless save_result
+          unless save_result
+            print_put_errors
+            fail("Save failed with return code #{save_result}, see debug")
+          end
 
           saved_files = @aug.match("/augeas/events/saved")
           if saved_files.size > 0
             root = resource[:root].sub(/^\/$/, "")
             saved_files.each do |key|
-              saved_file = @aug.get(key).to_s.sub(/^\/files/, root)
+              saved_file = @aug.get(key).sub(/^\/files/, root)
               if Puppet[:show_diff]
                 notice "\n" + diff(saved_file, saved_file + ".augnew")
               end
@@ -325,10 +362,10 @@ def execute_changes
     begin
       open_augeas
       saved_files = @aug.match("/augeas/events/saved")
-      if saved_files
+      unless saved_files.empty?
         saved_files.each do |key|
           root = resource[:root].sub(/^\/$/, "")
-          saved_file = @aug.get(key).to_s.sub(/^\/files/, root)
+          saved_file = @aug.get(key).sub(/^\/files/, root)
           if File.exists?(saved_file + ".augnew")
             success = File.rename(saved_file + ".augnew", saved_file)
             debug(saved_file + ".augnew moved to " + saved_file)
@@ -337,10 +374,12 @@ def execute_changes
         end
       else
         debug("No saved files, re-executing augeas")
-        set_augeas_save_mode(SAVE_OVERWRITE) if get_augeas_version >= "0.3.6"
+        set_augeas_save_mode(SAVE_OVERWRITE) if versioncmp(get_augeas_version, "0.3.6") >= 0
         do_execute_changes
-        success = @aug.save
-        fail("Save failed with return code #{success}") if success != true
+        unless @aug.save
+          print_put_errors
+          fail("Save failed with return code #{success}, see debug")
+        end
       end
     ensure
       close_augeas
diff --git a/lib/puppet/provider/package/macports.rb b/lib/puppet/provider/package/macports.rb
index 22fe6d9..3df29af 100755
--- a/lib/puppet/provider/package/macports.rb
+++ b/lib/puppet/provider/package/macports.rb
@@ -21,7 +21,7 @@
 
 
   def self.parse_installed_query_line(line)
-    regex = /(\S+)\s+@(\S+)_(\S+)\s+\(active\)/
+    regex = /(\S+)\s+@(\S+)_(\d+).*\(active\)/
     fields = [:name, :ensure, :revision]
     hash_from_line(line, regex, fields)
   end
@@ -46,7 +46,7 @@ def self.hash_from_line(line, regex, fields)
 
   def self.instances
     packages = []
-    port("-q", :installed).each do |line|
+    port("-q", :installed).each_line do |line|
       if hash = parse_installed_query_line(line)
         packages << new(hash)
       end
@@ -66,14 +66,16 @@ def install
   end
 
   def query
-    return self.class.parse_installed_query_line(port("-q", :installed, @resource[:name]))
+    result = self.class.parse_installed_query_line(execute([command(:port), "-q", :installed, @resource[:name]], :combine => false))
+    return {} if result.nil?
+    return result
   end
 
   def latest
     # We need both the version and the revision to be confident
     # we've got the latest revision of a specific version
     # Note we're still not doing anything with variants here.
-    info_line = port("-q", :info, "--line", "--version", "--revision", @resource[:name])
+    info_line = execute([command(:port), "-q", :info, "--line", "--version", "--revision", @resource[:name]], :combine => false)
     return nil if info_line == ""
 
     if newest = self.class.parse_info_query_line(info_line)
@@ -96,10 +98,6 @@ def uninstall
   end
 
   def update
-    if query[:name] == @resource[:name]  # 'port upgrade' cannot install new ports
-      port("-q", :upgrade, @resource[:name])
-    else
-      install
-    end
+    install
   end
 end
diff --git a/lib/puppet/provider/package/pacman.rb b/lib/puppet/provider/package/pacman.rb
index 5e05d14..7ee2e88 100644
--- a/lib/puppet/provider/package/pacman.rb
+++ b/lib/puppet/provider/package/pacman.rb
@@ -1,4 +1,5 @@
 require 'puppet/provider/package'
+require 'uri'
 
 Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Package do
   desc "Support for the Package Manager Utility (pacman) used in Archlinux."
@@ -12,13 +13,45 @@
   # Installs quietly, without confirmation or progressbar, updates package
   # list from servers defined in pacman.conf.
   def install
-    pacman "--noconfirm", "--noprogressbar", "-Sy", @resource[:name]
+    if @resource[:source]
+      install_from_file
+    else
+      install_from_repo
+    end
 
     unless self.query
       raise Puppet::ExecutionFailure.new("Could not find package %s" % self.name)
     end
   end
 
+  def install_from_repo
+    pacman "--noconfirm", "--noprogressbar", "-Sy", @resource[:name]
+  end
+  private :install_from_repo
+
+  def install_from_file
+    source = @resource[:source]
+    begin
+      source_uri = URI.parse source
+    rescue => detail
+      fail "Invalid source '#{source}': #{detail}"
+    end
+
+    source = case source_uri.scheme
+    when nil then source
+    when /https?/i then source
+    when /ftp/i then source
+    when /file/i then source_uri.path
+    when /puppet/i
+      fail "puppet:// URL is not supported by pacman"
+    else
+      fail "Source #{source} is not supported by pacman"
+    end
+    pacman "--noconfirm", "--noprogressbar", "-Sy"
+    pacman "--noconfirm", "--noprogressbar", "-U", source
+  end
+  private :install_from_file
+
   def self.listcmd
     [command(:pacman), " -Q"]
   end
diff --git a/lib/puppet/provider/package/pkgin.rb b/lib/puppet/provider/package/pkgin.rb
new file mode 100644
index 0000000..62cb8da
--- /dev/null
+++ b/lib/puppet/provider/package/pkgin.rb
@@ -0,0 +1,60 @@
+require "puppet/provider/package"
+
+Puppet::Type.type(:package).provide :pkgin, :parent => Puppet::Provider::Package do
+  desc "Package management using pkgin, a binary package manager for pkgsrc."
+
+  commands :pkgin => "pkgin"
+
+  has_feature :installable, :uninstallable
+
+  def self.parse_pkgin_line(package, force_status=nil)
+
+    # e.g.
+    #   vim-7.2.446 =        Vim editor (vi clone) without GUI
+    match, name, version, status = *package.match(/(\S+)-(\S+)(?: (=|>|<))?\s+.+$/)
+    if match
+      ensure_status = if force_status
+        force_status
+      elsif status
+        :present
+      else
+        :absent
+      end
+
+      {
+        :name     => name,
+        :ensure   => ensure_status,
+        :provider => :pkgin
+      }
+    end
+  end
+
+  def self.instances
+    pkgin(:list).split("\n").map do |package|
+      new(parse_pkgin_line(package, :present))
+    end
+  end
+
+  def query
+    packages = pkgin(:search, resource[:name]).split("\n")
+
+    # Remove the last three lines of help text.
+    packages.slice!(-3, 3)
+
+    matching_package = nil
+    packages.detect do |package|
+      properties = self.class.parse_pkgin_line(package)
+      matching_package = properties if properties && resource[:name] == properties[:name]
+    end
+
+    matching_package
+  end
+
+  def install
+    pkgin("-y", :install, resource[:name])
+  end
+
+  def uninstall
+    pkgin("-y", :remove, resource[:name])
+  end
+end
diff --git a/lib/puppet/provider/package/yum.rb b/lib/puppet/provider/package/yum.rb
old mode 100755
new mode 100644
index c66c46c..f072779
--- a/lib/puppet/provider/package/yum.rb
+++ b/lib/puppet/provider/package/yum.rb
@@ -56,7 +56,6 @@ def install
     wanted = @resource[:name]
     operation = :install
 
-    # XXX: We don't actually deal with epochs here.
     case should
     when true, false, Symbol
       # pass
@@ -87,7 +86,7 @@ def latest
     unless upd.nil?
       # FIXME: there could be more than one update for a package
       # because of multiarch
-      return "#{upd[:version]}-#{upd[:release]}"
+      return "#{upd[:epoch]}:#{upd[:version]}-#{upd[:release]}"
     else
       # Yum didn't find updates, pretend the current
       # version is the latest
diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb
index 6030da1..e9ee7e9 100755
--- a/lib/puppet/provider/service/debian.rb
+++ b/lib/puppet/provider/service/debian.rb
@@ -42,11 +42,25 @@ def enabled?
     # See x-man-page://invoke-rc.d
     if [104, 106].include?($CHILD_STATUS.exitstatus)
       return :true
+    elsif [105].include?($CHILD_STATUS.exitstatus)
+      # 105 is unknown, which generally means the the iniscript does not support query
+      # The debian policy states that the initscript should support methods of query
+      # For those that do not, peform the checks manually
+      # http://www.debian.org/doc/debian-policy/ch-opersys.html
+      if get_start_link_count >= 4
+        return :true
+      else
+        return :false
+      end
     else
       return :false
     end
   end
 
+  def get_start_link_count
+    Dir.glob("/etc/rc*.d/S*#{@resource[:name]}").length
+  end
+
   def enable
     update_rc "-f", @resource[:name], "remove"
     update_rc @resource[:name], "defaults"
diff --git a/lib/puppet/provider/user/useradd.rb b/lib/puppet/provider/user/useradd.rb
index e374905..d67e915 100644
--- a/lib/puppet/provider/user/useradd.rb
+++ b/lib/puppet/provider/user/useradd.rb
@@ -75,6 +75,14 @@ def addcmd
     cmd += check_system_users
     cmd << @resource[:name]
   end
+  
+  def deletecmd
+    cmd = [command(:delete)]
+    if @resource.managehome?
+      cmd << "-r"
+    end
+    cmd << @resource[:name]
+  end
 
   def passcmd
     age_limits = [:password_min_age, :password_max_age].select { |property| @resource.should(property) }
diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb
index f74e63f..c52b687 100644
--- a/lib/puppet/rails.rb
+++ b/lib/puppet/rails.rb
@@ -47,7 +47,7 @@ def self.database_arguments
     case adapter
     when "sqlite3"
       args[:database] = Puppet[:dblocation]
-    when "mysql", "postgresql"
+    when "mysql", "mysql2", "postgresql"
       args[:host]     = Puppet[:dbserver] unless Puppet[:dbserver].to_s.empty?
       args[:port]     = Puppet[:dbport] unless Puppet[:dbport].to_s.empty?
       args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty?
diff --git a/lib/puppet/rails/database/schema.rb b/lib/puppet/rails/database/schema.rb
index 7b75f42..3eb2589 100644
--- a/lib/puppet/rails/database/schema.rb
+++ b/lib/puppet/rails/database/schema.rb
@@ -22,7 +22,7 @@ def self.init
         # Thanks, mysql!  MySQL requires a length on indexes in text fields.
         # So, we provide them for mysql and handle everything else specially.
         # Oracle doesn't index on CLOB fields, so we skip it
-        if Puppet[:dbadapter] == "mysql"
+        if ['mysql','mysql2'].include? Puppet[:dbadapter]
           execute "CREATE INDEX typentitle ON resources (restype,title(50));"
         elsif Puppet[:dbadapter] != "oracle_enhanced"
           add_index :resources, [:title, :restype]
diff --git a/lib/puppet/reference/network.rb b/lib/puppet/reference/network.rb
deleted file mode 100644
index ee8fea0..0000000
--- a/lib/puppet/reference/network.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require 'puppet/network/handler'
-
-network = Puppet::Util::Reference.newreference :network, :depth => 2, :doc => "Available network handlers and clients" do
-  ret = ""
-  Puppet::Network::Handler.subclasses.sort { |a,b| a.to_s <=> b.to_s }.each do |name|
-    handler = Puppet::Network::Handler.handler(name)
-
-    next if ! handler.doc or handler.doc == ""
-
-    interface = handler.interface
-
-    ret << markdown_header(name, 2)
-
-    ret << scrub(handler.doc)
-    ret << "\n\n"
-    ret << option(:prefix, interface.prefix)
-    ret << option(:side, handler.side.to_s.capitalize)
-    ret << option(:methods, interface.methods.collect { |ary| ary[0] }.join(", ") )
-    ret << "\n\n"
-  end
-
-  ret
-end
-
-network.header = "
-This is a list of all Puppet network interfaces.  Each interface is
-implemented in the form of a client and a handler; the handler is loaded
-on the server, and the client knows how to call the handler's methods
-appropriately.
-
-Most handlers are meant to be started on the server, usually within
-`puppet master`, and the clients are mostly started on the client,
-usually within `puppet agent`.
-
-You can find the server-side handler for each interface at
-`puppet/network/handler/<name>.rb` and the client class at
-`puppet/network/client/<name>.rb`.
-
-"
diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb
index 997206e..cd188fa 100644
--- a/lib/puppet/reports/store.rb
+++ b/lib/puppet/reports/store.rb
@@ -1,4 +1,6 @@
 require 'puppet'
+require 'fileutils'
+require 'tempfile'
 
 Puppet::Reports.register_report(:store) do
   desc "Store the yaml report on disk.  Each host sends its report as a YAML dump
@@ -29,10 +31,15 @@ def process
 
     file = File.join(dir, name)
 
+    f = Tempfile.new(name, dir)
     begin
-      File.open(file, "w", 0640) do |f|
+      begin
+        f.chmod(0640)
         f.print to_yaml
+      ensure
+        f.close
       end
+      FileUtils.mv(f.path, file)
     rescue => detail
       puts detail.backtrace if Puppet[:trace]
       Puppet.warning "Could not write report for #{client} at #{file}: #{detail}"
diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb
index 2330cc5..5fc088a 100644
--- a/lib/puppet/resource.rb
+++ b/lib/puppet/resource.rb
@@ -285,61 +285,33 @@ def to_ral
     end
   end
 
-  # Translate our object to a backward-compatible transportable object.
-  def to_trans
-    if builtin_type? and type.downcase.to_s != "stage"
-      result = to_transobject
-    else
-      result = to_transbucket
-    end
-
-    result.file = self.file
-    result.line = self.line
-
-    result
+  def name
+    # this is potential namespace conflict
+    # between the notion of an "indirector name"
+    # and a "resource name"
+    [ type, title ].join('/')
   end
 
-  def to_trans_ref
-    [type.to_s, title.to_s]
-  end
+  def set_default_parameters(scope)
+    return [] unless resource_type and resource_type.respond_to?(:arguments)
 
-  # Create an old-style TransObject instance, for builtin resource types.
-  def to_transobject
-    # Now convert to a transobject
-    result = Puppet::TransObject.new(title, type)
-    to_hash.each do |p, v|
-      if v.is_a?(Puppet::Resource)
-        v = v.to_trans_ref
-      elsif v.is_a?(Array)
-        v = v.collect { |av|
-          av = av.to_trans_ref if av.is_a?(Puppet::Resource)
-          av
-        }
-      end
+    result = []
 
-      # If the value is an array with only one value, then
-      # convert it to a single value.  This is largely so that
-      # the database interaction doesn't have to worry about
-      # whether it returns an array or a string.
-      result[p.to_s] = if v.is_a?(Array) and v.length == 1
-        v[0]
-          else
-            v
-              end
-    end
+    resource_type.arguments.each do |param, default|
+      param = param.to_sym
+      next if parameters.include?(param)
+      unless is_a?(Puppet::Parser::Resource)
+        fail Puppet::DevError, "Cannot evaluate default parameters for #{self} - not a parser resource"
+      end
 
-    result.tags = self.tags
+      next if default.nil?
 
+      self[param] = default.safeevaluate(scope)
+      result << param
+    end
     result
   end
 
-  def name
-    # this is potential namespace conflict
-    # between the notion of an "indirector name"
-    # and a "resource name"
-    [ type, title ].join('/')
-  end
-
   def to_resource
     self
   end
@@ -348,6 +320,19 @@ def valid_parameter?(name)
     resource_type.valid_parameter?(name)
   end
 
+  # Verify that all required arguments are either present or
+  # have been provided with defaults.
+  # Must be called after 'set_default_parameters'.  We can't join the methods
+  # because Type#set_parameters needs specifically ordered behavior.
+  def validate_complete
+    return unless resource_type and resource_type.respond_to?(:arguments)
+
+    resource_type.arguments.each do |param, default|
+      param = param.to_sym
+      fail Puppet::ParseError, "Must pass #{param} to #{self}" unless parameters.include?(param)
+    end
+  end
+
   def validate_parameter(name)
     raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name)
   end
@@ -389,17 +374,6 @@ def namevar
     end
   end
 
-  # Create an old-style TransBucket instance, for non-builtin resource types.
-  def to_transbucket
-    bucket = Puppet::TransBucket.new([])
-
-    bucket.type = self.type
-    bucket.name = self.title
-
-    # TransBuckets don't support parameters, which is why they're being deprecated.
-    bucket
-  end
-
   def extract_parameters(params)
     params.each do |param, value|
       validate_parameter(param) if strict?
diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb
index 8dc0727..0b8007d 100644
--- a/lib/puppet/resource/catalog.rb
+++ b/lib/puppet/resource/catalog.rb
@@ -193,59 +193,6 @@ def create_resource(type, options)
     resource
   end
 
-  # Turn our catalog graph into an old-style tree of TransObjects and TransBuckets.
-  # LAK:NOTE(20081211): This is a  pre-0.25 backward compatibility method.
-  # It can be removed as soon as xmlrpc is killed.
-  def extract
-    top = nil
-    current = nil
-    buckets = {}
-
-    unless main = resource(:stage, "main")
-      raise Puppet::DevError, "Could not find 'main' stage; cannot generate catalog"
-    end
-
-    if stages = vertices.find_all { |v| v.type == "Stage" and v.title != "main" } and ! stages.empty?
-      Puppet.warning "Stages are not supported by 0.24.x client; stage(s) #{stages.collect { |s| s.to_s }.join(', ') } will be ignored"
-    end
-
-    bucket = nil
-    walk(main, :out) do |source, target|
-      # The sources are always non-builtins.
-      unless tmp = buckets[source.to_s]
-        if tmp = buckets[source.to_s] = source.to_trans
-          bucket = tmp
-        else
-          # This is because virtual resources return nil.  If a virtual
-          # container resource contains realized resources, we still need to get
-          # to them.  So, we keep a reference to the last valid bucket
-          # we returned and use that if the container resource is virtual.
-        end
-      end
-      bucket = tmp || bucket
-      if child = target.to_trans
-        raise "No bucket created for #{source}" unless bucket
-        bucket.push child
-
-        # It's important that we keep a reference to any TransBuckets we've created, so
-        # we don't create multiple buckets for children.
-        buckets[target.to_s] = child unless target.builtin?
-      end
-    end
-
-    # Retrieve the bucket for the top-level scope and set the appropriate metadata.
-    unless result = buckets[main.to_s]
-      # This only happens when the catalog is entirely empty.
-      result = buckets[main.to_s] = main.to_trans
-    end
-
-    result.classes = classes
-
-    # Clear the cache to encourage the GC
-    buckets.clear
-    result
-  end
-
   # Make sure all of our resources are "finished".
   def finalize
     make_default_resources
@@ -547,7 +494,11 @@ def write_resource_file
     ::File.open(Puppet[:resourcefile], "w") do |f|
       to_print = resources.map do |resource|
         next unless resource.managed?
-        "#{resource.type}[#{resource[resource.name_var]}]"
+        if resource.name_var
+          "#{resource.type}[#{resource[resource.name_var]}]"
+        else
+          "#{resource.ref.downcase}"
+        end
       end.compact
       f.puts to_print.join("\n")
     end
@@ -600,9 +551,6 @@ def to_catalog(convert)
       if resource.class == Puppet::Resource
         resource = resource.dup
         resource.catalog = result
-      elsif resource.is_a?(Puppet::TransObject)
-        resource = resource.dup
-        resource.catalog = result
       elsif resource.is_a?(Puppet::Parser::Resource)
         resource = resource.to_resource
         resource.catalog = result
diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb
index f8d820b..8b154ce 100644
--- a/lib/puppet/resource/type.rb
+++ b/lib/puppet/resource/type.rb
@@ -158,11 +158,7 @@ def ensure_in_catalog(scope, parameters=nil)
       return resource
     end
     resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self)
-    if parameters
-      parameters.each do |k,v|
-        resource.set_parameter(k,v)
-      end
-    end
+    assign_parameter_values(parameters, resource)
     instantiate_resource(scope, resource)
     scope.compiler.add_resource(scope, resource)
     resource
@@ -188,6 +184,18 @@ def name_is_regex?
     @name.is_a?(Regexp)
   end
 
+  def assign_parameter_values(parameters, resource)
+    return unless parameters
+    scope = resource.scope || {}
+
+    # It'd be nice to assign default parameter values here,
+    # but we can't because they often rely on local variables
+    # created during set_resource_parameters.
+    parameters.each do |name, value|
+      resource.set_parameter name, value
+    end
+  end
+
   # MQR TODO:
   #
   # The change(s) introduced by the fix for #4270 are mostly silly & should be 
@@ -225,40 +233,32 @@ def set_resource_parameters(resource, scope)
       param = param.to_sym
       fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless valid_parameter?(param)
 
-      exceptwrap { scope.setvar(param.to_s, value) }
+      exceptwrap { scope[param.to_s] = value }
 
       set[param] = true
     end
 
     if @type == :hostclass
-      scope.setvar("title", resource.title.to_s.downcase) unless set.include? :title
-      scope.setvar("name",  resource.name.to_s.downcase ) unless set.include? :name
+      scope["title"] = resource.title.to_s.downcase unless set.include? :title
+      scope["name"] =  resource.name.to_s.downcase  unless set.include? :name
     else
-      scope.setvar("title", resource.title              ) unless set.include? :title
-      scope.setvar("name",  resource.name               ) unless set.include? :name
+      scope["title"] = resource.title               unless set.include? :title
+      scope["name"] =  resource.name                unless set.include? :name
     end
-    scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name
+    scope["module_name"] = module_name if module_name and ! set.include? :module_name
 
     if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name)
-      scope.setvar("caller_module_name", caller_name)
+      scope["caller_module_name"] = caller_name
     end
     scope.class_set(self.name,scope) if hostclass? or node?
-    # Verify that all required arguments are either present or
-    # have been provided with defaults.
-    arguments.each do |param, default|
-      param = param.to_sym
-      next if set.include?(param)
-
-      # Even if 'default' is a false value, it's an AST value, so this works fine
-      fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default
 
-      value = default.safeevaluate(scope)
-      scope.setvar(param.to_s, value)
-
-      # Set it in the resource, too, so the value makes it to the client.
-      resource[param] = value
-    end
+    # Evaluate the default parameters, now that all other variables are set
+    default_params = resource.set_default_parameters(scope)
+    default_params.each { |param| scope[param.to_s] = resource[param] }
 
+    # This has to come after the above parameters so that default values
+    # can use their values
+    resource.validate_complete
   end
 
   # Check whether a given argument is valid.
diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb
index d70fe32..a4baf5b 100644
--- a/lib/puppet/ssl/host.rb
+++ b/lib/puppet/ssl/host.rb
@@ -199,18 +199,26 @@ def certificate
       return nil unless Certificate.indirection.find("ca") unless ca?
       return nil unless @certificate = Certificate.indirection.find(name)
 
-      unless certificate_matches_key?
-        raise Puppet::Error, "Retrieved certificate does not match private key; please remove certificate from server and regenerate it with the current key"
-      end
+      validate_certificate_with_key
     end
     @certificate
   end
 
-  def certificate_matches_key?
-    return false unless key
-    return false unless certificate
-
-    certificate.content.check_private_key(key.content)
+  def validate_certificate_with_key
+    raise Puppet::Error, "No certificate to validate." unless certificate
+    raise Puppet::Error, "No private key with which to validate certificate with fingerprint: #{certificate.fingerprint}" unless key
+    unless certificate.content.check_private_key(key.content)
+      raise Puppet::Error, <<ERROR_STRING
+The certificate retrieved from the master does not match the agent's private key.
+Certificate fingerprint: #{certificate.fingerprint}
+To fix this, remove the certificate from both the master and the agent and then start a puppet run, which will automatically regenerate a certficate.
+On the master:
+  puppet cert clean #{Puppet[:certname]}
+On the agent:
+  rm -f #{Puppet[:hostcert]}
+  puppet agent -t
+ERROR_STRING
+    end
   end
 
   # Generate all necessary parts of our ssl host.
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index e4bc0f2..3fe22b6 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -100,6 +100,7 @@ def evaluate
       if resource.is_a?(Puppet::Type::Component)
         Puppet.warning "Somehow left a component in the relationship graph"
       else
+        resource.info "Starting to evaluate the resource" if Puppet[:evaltrace] and @catalog.host_config?
         seconds = thinmark { eval_resource(resource) }
         resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config?
       end
@@ -234,7 +235,7 @@ def ignore_tags?
   def initialize(catalog, report = nil)
     @catalog = catalog
 
-    @report = report || Puppet::Transaction::Report.new("apply", catalog.version)
+    @report = report || Puppet::Transaction::Report.new("apply", catalog.version, Puppet[:environment])
 
     @event_manager = Puppet::Transaction::EventManager.new(self)
 
diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb
index 8071639..b7a0341 100644
--- a/lib/puppet/transaction/report.rb
+++ b/lib/puppet/transaction/report.rb
@@ -10,7 +10,7 @@ class Puppet::Transaction::Report
 
   indirects :report, :terminus_class => :processor
 
-  attr_accessor :configuration_version, :host
+  attr_accessor :configuration_version, :host, :environment
   attr_reader :resource_statuses, :logs, :metrics, :time, :kind, :status
 
   # This is necessary since Marshall doesn't know how to
@@ -68,7 +68,7 @@ def finalize_report
     @status = compute_status(resource_metrics, change_metric)
   end
 
-  def initialize(kind, configuration_version=nil)
+  def initialize(kind, configuration_version=nil, environment=nil)
     @metrics = {}
     @logs = []
     @resource_statuses = {}
@@ -79,6 +79,7 @@ def initialize(kind, configuration_version=nil)
     @report_format = 2
     @puppet_version = Puppet.version
     @configuration_version = configuration_version
+    @environment = environment
     @status = 'failed' # assume failed until the report is finalized
   end
 
@@ -115,7 +116,7 @@ def summary
 
   # Provide a raw hash summary of this report.
   def raw_summary
-    report = {}
+    report = { "version" => { "config" => configuration_version, "puppet" => Puppet.version  } }
 
     @metrics.each do |name, metric|
       key = metric.name.to_s
@@ -151,7 +152,7 @@ def calculate_change_metric
 
   def calculate_event_metrics
     metrics = Hash.new(0)
-    metrics["total"] = 0
+    %w{total failure success}.each { |m| metrics[m] = 0 }
     resource_statuses.each do |name, status|
       metrics["total"] += status.events.length
       status.events.each do |event|
@@ -163,9 +164,15 @@ def calculate_event_metrics
   end
 
   def calculate_resource_metrics
-    metrics = Hash.new(0)
+    metrics = {}
     metrics["total"] = resource_statuses.length
 
+    # force every resource key in the report to be present
+    # even if no resources is in this given state
+    Puppet::Resource::Status::STATES.each do |state|
+      metrics[state.to_s] = 0
+    end
+
     resource_statuses.each do |name, status|
       Puppet::Resource::Status::STATES.each do |state|
         metrics[state.to_s] += 1 if status.send(state)
diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb
deleted file mode 100644
index f7b839c..0000000
--- a/lib/puppet/transportable.rb
+++ /dev/null
@@ -1,248 +0,0 @@
-require 'puppet'
-require 'yaml'
-
-module Puppet
-  # The transportable objects themselves.  Basically just a hash with some
-  # metadata and a few extra methods.  I used to have the object actually
-  # be a subclass of Hash, but I could never correctly dump them using
-  # YAML.
-  class TransObject
-    include Enumerable
-    attr_accessor :type, :name, :file, :line, :catalog
-
-    attr_writer :tags
-
-    %w{has_key? include? length delete empty? << [] []=}.each { |method|
-      define_method(method) do |*args|
-        @params.send(method, *args)
-      end
-    }
-
-    def each
-      @params.each { |p,v| yield p, v }
-    end
-
-    def initialize(name,type)
-      @type = type.to_s.downcase
-      @name = name
-      @params = {}
-      @tags = []
-    end
-
-    def longname
-      [@type,@name].join('--')
-    end
-
-    def ref
-      @ref ||= Puppet::Resource.new(@type, @name)
-      @ref.to_s
-    end
-
-    def tags
-      @tags
-    end
-
-    # Convert a defined type into a component.
-    def to_component
-      trans = TransObject.new(ref, :component)
-      @params.each { |param,value|
-        next unless Puppet::Type::Component.valid_parameter?(param)
-        Puppet.debug "Defining #{param} on #{ref}"
-        trans[param] = value
-      }
-      trans.catalog = self.catalog
-      Puppet::Type::Component.create(trans)
-    end
-
-    def to_hash
-      @params.dup
-    end
-
-    def to_s
-      "#{@type}(#{@name}) => #{super}"
-    end
-
-    def to_manifest
-      "%s { '%s':\n%s\n}" % [self.type.to_s, self.name,
-        @params.collect { |p, v|
-          if v.is_a? Array
-            "    #{p} => [\'#{v.join("','")}\']"
-          else
-            "    #{p} => \'#{v}\'"
-          end
-        }.join(",\n")
-        ]
-    end
-
-    # Create a normalized resource from our TransObject.
-    def to_resource
-      result = Puppet::Resource.new(type, name, :parameters => @params.dup)
-      result.tag(*tags)
-
-      result
-    end
-
-    def to_yaml_properties
-      instance_variables.reject { |v| %w{@ref}.include?(v) }
-    end
-
-    def to_ref
-      ref
-    end
-
-    def to_ral
-      to_resource.to_ral
-    end
-  end
-
-  # Just a linear container for objects.  Behaves mostly like an array, except
-  # that YAML will correctly dump them even with their instance variables.
-  class TransBucket
-    include Enumerable
-
-    attr_accessor :name, :type, :file, :line, :classes, :keyword, :top, :catalog
-
-    %w{delete shift include? length empty? << []}.each { |method|
-      define_method(method) do |*args|
-        #Puppet.warning "Calling #{method} with #{args.inspect}"
-        @children.send(method, *args)
-        #Puppet.warning @params.inspect
-      end
-    }
-
-    # Recursively yield everything.
-    def delve(&block)
-      @children.each do |obj|
-        block.call(obj)
-        if obj.is_a? self.class
-          obj.delve(&block)
-        else
-          obj
-        end
-      end
-    end
-
-    def each
-      @children.each { |c| yield c }
-    end
-
-    # Turn our heirarchy into a flat list
-    def flatten
-      @children.collect do |obj|
-        if obj.is_a? Puppet::TransBucket
-          obj.flatten
-        else
-          obj
-        end
-      end.flatten
-    end
-
-    def initialize(children = [])
-      @children = children
-    end
-
-    def push(*args)
-      args.each { |arg|
-        case arg
-        when Puppet::TransBucket, Puppet::TransObject
-          # nada
-        else
-          raise Puppet::DevError,
-            "TransBuckets cannot handle objects of type #{arg.class}"
-        end
-      }
-      @children += args
-    end
-
-    # Convert to a parseable manifest
-    def to_manifest
-      unless self.top
-        raise Puppet::DevError, "No keyword; cannot convert to manifest" unless @keyword
-      end
-
-      str = "#{@keyword} #{@name} {\n%s\n}"
-      str % @children.collect { |child|
-        child.to_manifest
-      }.collect { |str|
-        if self.top
-          str
-        else
-          str.gsub(/^/, "    ") # indent everything once
-        end
-      }.join("\n\n") # and throw in a blank line
-    end
-
-    def to_yaml_properties
-      instance_variables
-    end
-
-    # Create a resource graph from our structure.
-    def to_catalog(clear_on_failure = true)
-      catalog = Puppet::Resource::Catalog.new(Facter.value("hostname"))
-
-      # This should really use the 'delve' method, but this
-      # whole class is going away relatively soon, hopefully,
-      # so it's not worth it.
-      delver = proc do |obj|
-        obj.catalog = catalog
-        unless container = catalog.resource(obj.to_ref)
-          container = obj.to_ral
-          catalog.add_resource container
-        end
-        obj.each do |child|
-          child.catalog = catalog
-          unless resource = catalog.resource(child.to_ref)
-            resource = child.to_ral
-            catalog.add_resource resource
-          end
-
-          catalog.add_edge(container, resource)
-          delver.call(child) if child.is_a?(self.class)
-        end
-      end
-
-      begin
-        delver.call(self)
-        catalog.finalize
-      rescue => detail
-        # This is important until we lose the global resource references.
-        catalog.clear if (clear_on_failure)
-        raise
-      end
-
-      catalog
-    end
-
-    def to_ref
-      unless defined?(@ref)
-        if self.type and self.name
-          @ref = Puppet::Resource.new(self.type, self.name)
-        elsif self.type and ! self.name # This is old-school node types
-          @ref = Puppet::Resource.new("node", self.type)
-        elsif ! self.type and self.name
-          @ref = Puppet::Resource.new("component", self.name)
-        else
-          @ref = nil
-        end
-      end
-      @ref.to_s if @ref
-    end
-
-    def to_ral
-      to_resource.to_ral
-    end
-
-    # Create a normalized resource from our TransObject.
-    def to_resource
-      params = defined?(@parameters) ? @parameters.dup : {}
-      Puppet::Resource.new(type, name, :parameters => params)
-    end
-
-    def param(param,value)
-      @parameters ||= {}
-      @parameters[param] = value
-    end
-
-  end
-end
-
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 94f26cf..3cb32c4 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -107,11 +107,9 @@ def self.ensurable(&block)
   def self.ensurable?
     # If the class has all three of these methods defined, then it's
     # ensurable.
-    ens = [:exists?, :create, :destroy].inject { |set, method|
-      set &&= self.public_method_defined?(method)
+    [:exists?, :create, :destroy].all? { |method|
+      self.public_method_defined?(method)
     }
-
-    ens
   end
 
   def self.apply_to_device
@@ -755,10 +753,6 @@ def noop
     noop?
   end
 
-  ###############################
-  # Code related to managing resource instances.
-  require 'puppet/transportable'
-
   # retrieve a named instance of the current type
   def self.[](name)
     raise "Global resource access is deprecated"
@@ -1500,11 +1494,14 @@ class << self
 
       # We need to add documentation for each provider.
       def self.doc
-        @doc + "  Available providers are:\n\n" + parenttype.providers.sort { |a,b|
+        # Since we're mixing @doc with text from other sources, we must normalize
+        # its indentation with scrub. But we don't need to manually scrub the
+        # provider's doc string, since markdown_definitionlist sanitizes its inputs.
+        scrub(@doc) + "Available providers are:\n\n" + parenttype.providers.sort { |a,b|
           a.to_s <=> b.to_s
         }.collect { |i|
-          "* **#{i}**: #{parenttype().provider(i).doc}"
-        }.join("\n")
+          markdown_definitionlist( i, scrub(parenttype().provider(i).doc) )
+        }.join
       end
 
       defaultto {
@@ -1753,7 +1750,6 @@ def log(msg)
 
   # initialize the type instance
   def initialize(resource)
-    raise Puppet::DevError, "Got TransObject instead of Resource or hash" if resource.is_a?(Puppet::TransObject)
     resource = self.class.hash2resource(resource) unless resource.is_a?(Puppet::Resource)
 
     # The list of parameter/property instances.
@@ -1903,15 +1899,9 @@ def to_s
     self.ref
   end
 
-  # Convert to a transportable object
-  def to_trans(ret = true)
-    trans = TransObject.new(self.title, self.class.name)
-
-    values = retrieve_resource
-    values.each do |name, value|
-      name = name.name if name.respond_to? :name
-      trans[name] = value
-    end
+  def to_resource
+    resource = self.retrieve_resource
+    resource.tag(*self.tags)
 
     @parameters.each do |name, param|
       # Avoid adding each instance name twice
@@ -1919,20 +1909,10 @@ def to_trans(ret = true)
 
       # We've already got property values
       next if param.is_a?(Puppet::Property)
-      trans[name] = param.value
+      resource[name] = param.value
     end
 
-    trans.tags = self.tags
-
-    # FIXME I'm currently ignoring 'parent' and 'path'
-
-    trans
-  end
-
-  def to_resource
-    # this 'type instance' versus 'resource' distinction seems artificial
-    # I'd like to see it collapsed someday ~JW
-    self.to_trans.to_resource
+    resource
   end
 
   def virtual?;  !!@virtual;  end
diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb
index 20c774a..2d53771 100644
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -5,7 +5,6 @@
 require 'fileutils'
 require 'enumerator'
 require 'pathname'
-require 'puppet/network/handler'
 require 'puppet/util/diff'
 require 'puppet/util/checksums'
 require 'puppet/util/backups'
@@ -261,13 +260,18 @@ def self.title_patterns
 
   # Autorequire the nearest ancestor directory found in the catalog.
   autorequire(:file) do
+    req = []
     path = Pathname.new(self[:path])
     if !path.root?
       # Start at our parent, to avoid autorequiring ourself
       parents = path.parent.enum_for(:ascend)
-      found = parents.find { |p| catalog.resource(:file, p.to_s) }
-      found and found.to_s
+      if found = parents.find { |p| catalog.resource(:file, p.to_s) }
+        req << found.to_s
+      end
     end
+    # if the resource is a link, make sure the target is created first
+    req << self[:target] if self[:target]
+    req
   end
 
   # Autorequire the owner and group of the file.
@@ -705,13 +709,10 @@ def stat
     end
   end
 
-  # We have to hack this just a little bit, because otherwise we'll get
-  # an error when the target and the contents are created as properties on
-  # the far side.
-  def to_trans(retrieve = true)
-    obj = super
-    obj.delete(:target) if obj[:target] == :notlink
-    obj
+  def to_resource
+    resource = super
+    resource.delete(:target) if resource[:target] == :notlink
+    resource
   end
 
   # Write out the file.  Requires the property name for logging.
diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb
index 8f3b8b4..f68ed95 100755
--- a/lib/puppet/type/file/content.rb
+++ b/lib/puppet/type/file/content.rb
@@ -199,10 +199,18 @@ def chunk_file_from_disk(source_or_content)
       end
     end
 
-    def chunk_file_from_source(source_or_content)
+    def get_from_source(source_or_content, &block)
       request = Puppet::Indirector::Request.new(:file_content, :find, source_or_content.full_path.sub(/^\//,''))
-      connection = Puppet::Network::HttpPool.http_instance(source_or_content.server, source_or_content.port)
-      connection.request_get(indirection2uri(request), add_accept_encoding({"Accept" => "raw"})) do |response|
+
+      request.do_request(:fileserver) do |req|
+        connection = Puppet::Network::HttpPool.http_instance(req.server, req.port)
+        connection.request_get(indirection2uri(req), add_accept_encoding({"Accept" => "raw"}), &block)
+      end
+    end
+
+
+    def chunk_file_from_source(source_or_content)
+      get_from_source(source_or_content) do |response|
         case response.code
         when /^2/;  uncompress(response) { |uncompressor| response.read_body { |chunk| yield uncompressor.uncompress(chunk) } }
         else
diff --git a/lib/puppet/type/file/ctime.rb b/lib/puppet/type/file/ctime.rb
index 90d95da..5f94863 100644
--- a/lib/puppet/type/file/ctime.rb
+++ b/lib/puppet/type/file/ctime.rb
@@ -10,7 +10,7 @@ def retrieve
       current_value
     end
 
-    validate do
+    validate do |val|
       fail "ctime is read-only"
     end
   end
diff --git a/lib/puppet/type/file/mtime.rb b/lib/puppet/type/file/mtime.rb
index 5952b4b..10867dd 100644
--- a/lib/puppet/type/file/mtime.rb
+++ b/lib/puppet/type/file/mtime.rb
@@ -10,7 +10,7 @@ def retrieve
       current_value
     end
 
-    validate do
+    validate do |val|
       fail "mtime is read-only"
     end
   end
diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb
index 9375550..6b457e2 100755
--- a/lib/puppet/type/file/source.rb
+++ b/lib/puppet/type/file/source.rb
@@ -132,6 +132,10 @@ def copy_source_values
         next if metadata_method == :checksum and metadata.ftype == "directory"
         next if metadata_method == :checksum and metadata.ftype == "link" and metadata.links == :manage
 
+        if Puppet.features.microsoft_windows?
+          next if [:owner, :group].include?(metadata_method) and !local?
+        end
+
         if resource[param_name].nil? or resource[param_name] == :absent
           resource[param_name] = metadata.send(metadata_method)
         end
@@ -184,6 +188,10 @@ def full_path
       Puppet::Util.uri_to_path(uri) if found?
     end
 
+    def server?
+       uri and uri.host
+    end
+
     def server
       (uri and uri.host) or Puppet.settings[:server]
     end
diff --git a/lib/puppet/type/file/type.rb b/lib/puppet/type/file/type.rb
index 864d3b1..38f3015 100755
--- a/lib/puppet/type/file/type.rb
+++ b/lib/puppet/type/file/type.rb
@@ -11,7 +11,7 @@ def retrieve
       current_value
     end
 
-    validate do
+    validate do |val|
       fail "type is read-only"
     end
   end
diff --git a/lib/puppet/type/schedule.rb b/lib/puppet/type/schedule.rb
index 2baf726..3193c74 100755
--- a/lib/puppet/type/schedule.rb
+++ b/lib/puppet/type/schedule.rb
@@ -81,7 +81,8 @@ module Puppet
             }
 
         This is mostly useful for restricting certain resources to being
-        applied in maintenance windows or during off-peak hours.
+        applied in maintenance windows or during off-peak hours. Multiple
+        ranges can be applied in array context.
       EOT
 
       # This is lame; properties all use arrays as values, but parameters don't.
@@ -178,7 +179,7 @@ def match?(previous, now)
 
           #self.info limits.inspect
           #self.notice now
-          return now.between?(*limits)
+          return true if now.between?(*limits)
         end
 
         # Else, return false, since our current time isn't between
diff --git a/lib/puppet/util/anonymous_filelock.rb b/lib/puppet/util/anonymous_filelock.rb
new file mode 100644
index 0000000..ff09c5d
--- /dev/null
+++ b/lib/puppet/util/anonymous_filelock.rb
@@ -0,0 +1,36 @@
+
+class Puppet::Util::AnonymousFilelock
+  attr_reader :lockfile
+
+  def initialize(lockfile)
+    @lockfile = lockfile
+  end
+
+  def anonymous?
+    true
+  end
+
+  def lock(msg = '')
+    return false if locked?
+
+    File.open(@lockfile, 'w') { |fd| fd.print(msg) }
+    true
+  end
+
+  def unlock
+    if locked?
+      File.unlink(@lockfile)
+      true
+    else
+      false
+    end
+  end
+
+  def locked?
+    File.exists? @lockfile
+  end
+
+  def message
+    return File.read(@lockfile) if locked?
+  end
+end
\ No newline at end of file
diff --git a/lib/puppet/util/docs.rb b/lib/puppet/util/docs.rb
index 4344d67..0a7c9bc 100644
--- a/lib/puppet/util/docs.rb
+++ b/lib/puppet/util/docs.rb
@@ -20,10 +20,10 @@ def dochook(name, &block)
   def doc
     extra = methods.find_all { |m| m.to_s =~ /^dochook_.+/ }.sort.collect { |m|
       self.send(m)
-    }.join("  ")
+    }.delete_if {|r| r.nil? }.join("  ")
 
     if @doc
-      @doc + extra
+      @doc + (extra.empty? ? '' : "\n\n" + extra)
     else
       extra
     end
@@ -73,6 +73,22 @@ def pad(value, length)
     value.to_s + (" " * (length - value.to_s.length))
   end
 
+  HEADER_LEVELS = [nil, "#", "##", "###", "####", "#####"]
+
+  def markdown_header(name, level)
+    "#{HEADER_LEVELS[level]} #{name}\n\n"
+  end
+
+  def markdown_definitionlist(term, definition)
+    lines = scrub(definition).split("\n")
+    str = "#{term}\n: #{lines.shift}\n"
+    lines.each do |line|
+      str << "  " if line =~ /\S/
+      str << "#{line}\n"
+    end
+    str << "\n"
+  end
+
   # Handle the inline indentation in the docs.
   def scrub(text)
     # Stupid markdown
diff --git a/lib/puppet/util/instrumentation.rb b/lib/puppet/util/instrumentation.rb
new file mode 100644
index 0000000..bd0ed3b
--- /dev/null
+++ b/lib/puppet/util/instrumentation.rb
@@ -0,0 +1,173 @@
+require 'puppet'
+require 'puppet/util/classgen'
+require 'puppet/util/instance_loader'
+
+class Puppet::Util::Instrumentation
+  extend Puppet::Util::ClassGen
+  extend Puppet::Util::InstanceLoader
+  extend MonitorMixin
+
+  # we're using a ruby lazy autoloader to prevent a loop when requiring listeners
+  # since this class sets up an indirection which is also used in Puppet::Indirector::Indirection
+  # which is used to setup indirections...
+  autoload :Listener, 'puppet/util/instrumentation/listener'
+  autoload :Data, 'puppet/util/instrumentation/data'
+
+  # Set up autoloading and retrieving of instrumentation listeners.
+  instance_load :listener, 'puppet/util/instrumentation/listeners'
+
+  class << self
+    attr_accessor :listeners, :listeners_of
+  end
+
+  # instrumentation layer
+
+  # Triggers an instrumentation
+  #
+  # Call this method around the instrumentation point
+  #   Puppet::Util::Instrumentation.instrument(:my_long_computation) do
+  #     ... a long computation
+  #   end
+  #
+  # This will send an event to all the listeners of "my_long_computation".
+  # Note: this method uses ruby yield directive to call the instrumented code.
+  # It is usually way slower than calling start and stop directly around the instrumented code.
+  # For high traffic code path, it is thus advisable to not use this method.
+  def self.instrument(label, data = {})
+    id = self.start(label, data)
+    yield
+  ensure
+    self.stop(label, id, data)
+  end
+
+  # Triggers a "start" instrumentation event
+  #
+  # Important note:
+  #  For proper use, the data hash instance used for start should also
+  #  be used when calling stop. The idea is to use the current scope
+  #  where start is called to retain a reference to 'data' so that it is possible
+  #  to send it back to stop.
+  #  This way listeners can match start and stop events more easily.
+  def self.start(label, data)
+    data[:started] = Time.now
+    publish(label, :start, data)
+    data[:id] = next_id
+  end
+
+  # Triggers a "stop" instrumentation event
+  def self.stop(label, id, data)
+    data[:finished] = Time.now
+    publish(label, :stop, data)
+  end
+
+  def self.publish(label, event, data)
+    each_listener(label) do |k,l|
+      l.notify(label, event, data)
+    end
+  end
+
+  def self.listeners
+    @listeners.values
+  end
+
+  def self.each_listener(label)
+    synchronize {
+      @listeners_of[label] ||= @listeners.select do |k,l|
+        l.listen_to?(label)
+      end
+    }.each do |l|
+      yield l
+    end
+  end
+
+  # Adds a new listener
+  #
+  # Usage:
+  #   Puppet::Util::Instrumentation.new_listener(:my_instrumentation, pattern) do
+  #
+  #     def notify(label, data)
+  #       ... do something for data...
+  #     end
+  #   end
+  #
+  # It is possible to use a "pattern". The listener will be notified only
+  # if the pattern match the label of the event.
+  # The pattern can be a symbol, a string or a regex.
+  # If no pattern is provided, then the listener will be called for every events
+  def self.new_listener(name, options = {}, &block)
+    Puppet.debug "new listener called #{name}"
+    name = symbolize(name)
+    listener = genclass(name, :hash => instance_hash(:listener), :block => block)
+    listener.send(:define_method, :name) do
+      name
+    end
+    subscribe(listener.new, options[:label_pattern], options[:event])
+  end
+
+  def self.subscribe(listener, label_pattern, event)
+    synchronize {
+      raise "Listener #{listener.name} is already subscribed" if @listeners.include?(listener.name)
+      Puppet.debug "registering instrumentation listener #{listener.name}"
+      @listeners[listener.name] = Listener.new(listener, label_pattern, event)
+      listener.subscribed if listener.respond_to?(:subscribed)
+      rehash
+    }
+  end
+
+  def self.unsubscribe(listener)
+    synchronize {
+      Puppet.warning("#{listener.name} hasn't been registered but asked to be unregistered") unless @listeners.include?(listener.name)
+      Puppet.info "unregistering instrumentation listener #{listener.name}"
+      @listeners.delete(listener.name)
+      listener.unsubscribed if listener.respond_to?(:unsubscribed)
+      rehash
+    }
+  end
+
+  def self.init
+    # let's init our probe indirection
+    require 'puppet/util/instrumentation/indirection_probe'
+    synchronize {
+      @listeners ||= {}
+      @listeners_of ||= {}
+      instance_loader(:listener).loadall
+    }
+  end
+
+  def self.clear
+    synchronize {
+      @listeners = {}
+      @listeners_of = {}
+      @id = 0
+    }
+  end
+
+  def self.[](key)
+    synchronize {
+      key = symbolize(key)
+      @listeners[key]
+    }
+  end
+
+  def self.[]=(key, value)
+    synchronize {
+      key = symbolize(key)
+      @listeners[key] = value
+      rehash
+    }
+  end
+
+  private
+
+  # should be called only under the guard
+  # self.synchronize
+  def self.rehash
+    @listeners_of = {}
+  end
+
+  def self.next_id
+    synchronize {
+      @id = (@id || 0) + 1
+    }
+  end
+end
diff --git a/lib/puppet/util/instrumentation/data.rb b/lib/puppet/util/instrumentation/data.rb
new file mode 100644
index 0000000..9157f58
--- /dev/null
+++ b/lib/puppet/util/instrumentation/data.rb
@@ -0,0 +1,34 @@
+require 'puppet/indirector'
+require 'puppet/util/instrumentation'
+
+# This is just a transport class to be used through the instrumentation_data
+# indirection. All the data resides in the real underlying listeners which this
+# class delegates to.
+class Puppet::Util::Instrumentation::Data
+  extend Puppet::Indirector
+
+  indirects :instrumentation_data, :terminus_class => :local
+
+  attr_reader :listener
+
+  def initialize(listener_name)
+    @listener = Puppet::Util::Instrumentation[listener_name]
+    raise "Listener #{listener_name} wasn't registered" unless @listener
+  end
+
+  def name
+    @listener.name
+  end
+
+  def to_pson(*args)
+    result = {
+      'document_type' => "Puppet::Util::Instrumentation::Data",
+      'data' => { :name => name }.merge(@listener.respond_to?(:data) ? @listener.data : {})
+    }
+    result.to_pson(*args)
+  end
+
+  def self.from_pson(data)
+    data
+  end
+end
diff --git a/lib/puppet/util/instrumentation/indirection_probe.rb b/lib/puppet/util/instrumentation/indirection_probe.rb
new file mode 100644
index 0000000..66e5f92
--- /dev/null
+++ b/lib/puppet/util/instrumentation/indirection_probe.rb
@@ -0,0 +1,29 @@
+require 'puppet/indirector'
+require 'puppet/util/instrumentation'
+
+# We need to use a class other than Probe for the indirector because
+# the Indirection class might declare some probes, and this would be a huge unbreakable
+# dependency cycle.
+class Puppet::Util::Instrumentation::IndirectionProbe
+  extend Puppet::Indirector
+
+  indirects :instrumentation_probe, :terminus_class => :local
+
+  attr_reader :probe_name
+
+  def initialize(probe_name)
+    @probe_name = probe_name
+  end
+
+  def to_pson(*args)
+    result = {
+      :document_type => "Puppet::Util::Instrumentation::IndirectionProbe",
+      :data => { :name => probe_name }
+    }
+    result.to_pson(*args)
+  end
+
+  def self.from_pson(data)
+    self.new(data["name"])
+  end
+end
\ No newline at end of file
diff --git a/lib/puppet/util/instrumentation/instrumentable.rb b/lib/puppet/util/instrumentation/instrumentable.rb
new file mode 100644
index 0000000..5789dcb
--- /dev/null
+++ b/lib/puppet/util/instrumentation/instrumentable.rb
@@ -0,0 +1,143 @@
+require 'monitor'
+require 'puppet/util/instrumentation'
+
+# This is the central point of all declared probes.
+# Every class needed to declare probes should include this module
+# and declare the methods that are subject to instrumentation:
+#
+#   class MyClass
+#     extend Puppet::Util::Instrumentation::Instrumentable
+#
+#     probe :mymethod
+#
+#     def mymethod
+#       ... this is code to be instrumented ...
+#     end
+#   end
+module Puppet::Util::Instrumentation::Instrumentable
+  INSTRUMENTED_CLASSES = {}.extend(MonitorMixin)
+
+  attr_reader :probes
+
+  class Probe
+    attr_reader :klass, :method, :label, :data
+
+    def initialize(method, klass, options = {})
+      @method = method
+      @klass = klass
+
+      @label = options[:label] || method
+      @data = options[:data] || {}
+    end
+
+    def enable
+      raise "Probe already enabled" if enabled?
+
+      # We're forced to perform this copy because in the class_eval'uated
+      # block below @method would be evaluated in the class context. It's better
+      # to close on locally-scoped variables than to resort to complex namespacing
+      # to get access to the probe instance variables.
+      method = @method; label = @label; data = @data
+      klass.class_eval {
+        alias_method("instrumented_#{method}", method)
+        define_method(method) do |*args|
+          id = nil
+          instrumentation_data = nil
+          begin
+            instrumentation_label = label.respond_to?(:call) ? label.call(self, args) : label
+            instrumentation_data = data.respond_to?(:call) ? data.call(self, args) : data
+            id = Puppet::Util::Instrumentation.start(instrumentation_label, instrumentation_data)
+            send("instrumented_#{method}".to_sym, *args)
+          ensure
+            Puppet::Util::Instrumentation.stop(instrumentation_label, id, instrumentation_data || {})
+          end
+        end
+      }
+      @enabled = true
+    end
+
+    def disable
+      raise "Probe is not enabled" unless enabled?
+
+      # For the same reason as in #enable, we're forced to do a local
+      # copy
+      method = @method
+      klass.class_eval do
+        alias_method(method, "instrumented_#{method}")
+        remove_method("instrumented_#{method}".to_sym)
+      end
+      @enabled = false
+    end
+
+    def enabled?
+      !!@enabled
+    end
+  end
+
+  # Declares a new probe
+  #
+  # It is possible to pass several options that will be later on evaluated
+  # and sent to the instrumentation layer.
+  #
+  # label::
+  #   this can either be a static symbol/string or a block. If it's a block
+  #   this one will be evaluated on every call of the instrumented method and
+  #   should return a string or a symbol
+  #   
+  # data::
+  #   this can be a hash or a block. If it's a block this one will be evaluated
+  #   on every call of the instrumented method and should return a hash.
+  # 
+  #Example:
+  #
+  #   class MyClass
+  #     extend Instrumentable
+  #
+  #     probe :mymethod, :data => Proc.new { |args|  { :data => args[1] } }, :label => Proc.new { |args| args[0] }
+  #
+  #     def mymethod(name, options)
+  #     end
+  #
+  #   end
+  #
+  def probe(method, options = {})
+    INSTRUMENTED_CLASSES.synchronize {
+      (@probes ||= []) << Probe.new(method, self, options)
+      INSTRUMENTED_CLASSES[self] = @probes
+    }
+  end
+
+  def self.probes
+    @probes
+  end
+
+  def self.probe_names
+    probe_names = []
+    each_probe { |probe| probe_names << "#{probe.klass}.#{probe.method}" }
+    probe_names
+  end
+
+  def self.enable_probes
+    each_probe { |probe| probe.enable }
+  end
+
+  def self.disable_probes
+    each_probe { |probe| probe.disable }
+  end
+
+  def self.clear_probes
+    INSTRUMENTED_CLASSES.synchronize {
+      INSTRUMENTED_CLASSES.clear
+    }
+    nil # do not leak our probes to the exterior world
+  end
+
+  def self.each_probe
+    INSTRUMENTED_CLASSES.synchronize {
+      INSTRUMENTED_CLASSES.each_key do |klass|
+        klass.probes.each { |probe| yield probe }
+      end
+    }
+    nil # do not leak our probes to the exterior world
+  end
+end
\ No newline at end of file
diff --git a/lib/puppet/util/instrumentation/listener.rb b/lib/puppet/util/instrumentation/listener.rb
new file mode 100644
index 0000000..42ec0c0
--- /dev/null
+++ b/lib/puppet/util/instrumentation/listener.rb
@@ -0,0 +1,60 @@
+require 'puppet/indirector'
+require 'puppet/util/instrumentation'
+require 'puppet/util/instrumentation/data'
+
+class Puppet::Util::Instrumentation::Listener
+  include Puppet::Util
+  include Puppet::Util::Warnings
+  extend Puppet::Indirector
+
+  indirects :instrumentation_listener, :terminus_class => :local
+
+  attr_reader :pattern, :listener
+  attr_accessor :enabled
+
+  def initialize(listener, pattern = nil, enabled = false)
+    @pattern = pattern.is_a?(Symbol) ? pattern.to_s : pattern
+    raise "Listener isn't a correct listener (it doesn't provide the notify method)" unless listener.respond_to?(:notify)
+    @listener = listener
+    @enabled = enabled
+  end
+
+  def notify(label, event, data)
+    listener.notify(label, event, data)
+  rescue => e
+    warnonce("Error during instrumentation notification: #{e}")
+  end
+
+  def listen_to?(label)
+    enabled? and (!@pattern || @pattern === label.to_s)
+  end
+
+  def enabled?
+    !!@enabled
+  end
+
+  def name
+    @listener.name.to_s
+  end
+
+  def data
+    { :data => @listener.data }
+  end
+
+  def to_pson(*args)
+    result = {
+      :document_type => "Puppet::Util::Instrumentation::Listener",
+      :data => {
+        :name => name,
+        :pattern => pattern,
+        :enabled => enabled?
+      }
+    }
+    result.to_pson(*args)
+  end
+
+  def self.from_pson(data)
+    result = Puppet::Util::Instrumentation[data["name"]]
+    self.new(result.listener, result.pattern, data["enabled"])
+  end
+end
diff --git a/lib/puppet/util/instrumentation/listeners/log.rb b/lib/puppet/util/instrumentation/listeners/log.rb
new file mode 100644
index 0000000..59e9daf
--- /dev/null
+++ b/lib/puppet/util/instrumentation/listeners/log.rb
@@ -0,0 +1,29 @@
+require 'monitor'
+
+# This is an example instrumentation listener that stores the last
+# 20 instrumented probe run time.
+Puppet::Util::Instrumentation.new_listener(:log) do
+
+  SIZE = 20
+
+  attr_accessor :last_logs
+
+  def initialize
+    @last_logs = {}.extend(MonitorMixin)
+  end
+
+  def notify(label, event, data)
+    return if event == :start
+    log_line = "#{label} took #{data[:finished] - data[:started]}"
+    @last_logs.synchronize {
+      (@last_logs[label] ||= []) << log_line
+      @last_logs[label].shift if @last_logs[label].length > SIZE
+    }
+  end
+
+  def data
+    @last_logs.synchronize {
+      @last_logs.dup
+    }
+  end
+end
\ No newline at end of file
diff --git a/lib/puppet/util/instrumentation/listeners/performance.rb b/lib/puppet/util/instrumentation/listeners/performance.rb
new file mode 100644
index 0000000..b3175a0
--- /dev/null
+++ b/lib/puppet/util/instrumentation/listeners/performance.rb
@@ -0,0 +1,30 @@
+require 'monitor'
+
+Puppet::Util::Instrumentation.new_listener(:performance) do
+
+  attr_reader :samples
+
+  def initialize
+    @samples = {}.extend(MonitorMixin)
+  end
+
+  def notify(label, event, data)
+    return if event == :start
+
+    duration = data[:finished] - data[:started]
+    samples.synchronize do
+      @samples[label] ||= { :count => 0, :max => 0, :min => nil, :sum => 0, :average => 0 }
+      @samples[label][:count] += 1
+      @samples[label][:sum] += duration
+      @samples[label][:max] = [ @samples[label][:max], duration ].max
+      @samples[label][:min] = [ @samples[label][:min], duration ].reject { |val| val.nil? }.min
+      @samples[label][:average] = @samples[label][:sum] / @samples[label][:count]
+    end
+  end
+
+  def data
+    samples.synchronize do
+      @samples.dup
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/puppet/util/instrumentation/listeners/process_name.rb b/lib/puppet/util/instrumentation/listeners/process_name.rb
new file mode 100644
index 0000000..88a185c
--- /dev/null
+++ b/lib/puppet/util/instrumentation/listeners/process_name.rb
@@ -0,0 +1,112 @@
+require 'monitor'
+
+# Unlike the other instrumentation plugins, this one doesn't give back
+# data. Instead it changes the process name of the currently running process
+# with the last labels and data. 
+Puppet::Util::Instrumentation.new_listener(:process_name) do
+  include Sync_m
+
+  # start scrolling when process name is longer than
+  SCROLL_LENGTH = 50
+
+  attr_accessor :active, :reason
+
+  def notify(label, event, data)
+    start(label) if event == :start
+    stop if event == :stop
+  end
+
+  def start(activity)
+    push_activity(Thread.current, activity)
+  end
+
+  def stop()
+    pop_activity(Thread.current)
+  end
+
+  def subscribed
+    synchronize do
+      @oldname = $0
+      @scroller ||= Thread.new do
+        loop do
+          scroll
+          sleep 1
+        end
+      end
+    end
+  end
+
+  def unsubscribed
+    synchronize do
+      $0 = @oldname if @oldname
+      Thread.kill(@scroller)
+      @scroller = nil
+    end
+  end
+
+  def setproctitle
+    $0 = "#{base}: " + rotate(process_name,@x)
+  end
+
+  def push_activity(thread, activity)
+    synchronize do
+      @reason ||= {}
+      @reason[thread] ||= []
+      @reason[thread].push(activity)
+      setproctitle
+    end
+  end
+
+  def pop_activity(thread)
+    synchronize do
+      @reason[thread].pop
+      if @reason[thread].empty?
+        @reason.delete(thread)
+      end
+      setproctitle
+    end
+  end
+
+  def process_name
+    out = (@reason || {}).inject([]) do |out, reason|
+      out << "#{thread_id(reason[0])} #{reason[1].join(',')}"
+    end
+    out.join(' | ')
+  end
+
+  # Getting the ruby thread id might not be portable to other ruby
+  # interpreters than MRI, because Thread#inspect might not return the same
+  # information on a different runtime.
+  def thread_id(thread)
+    thread.inspect.gsub(/^#<.*:0x([a-f0-9]+) .*>$/, '\1')
+  end
+
+  def rotate(string, steps)
+    steps ||= 0
+    if string.length > 0 && steps > 0
+      steps = steps % string.length
+      return string[steps..-1].concat " -- #{string[0..(steps-1)]}"
+    end
+    string
+  end
+
+  def base
+    basename = case Puppet.run_mode.name
+    when :master
+      "master"
+    when :agent
+      "agent"
+    else
+      "puppet"
+    end
+  end
+
+  def scroll
+    @x ||= 1
+    return if process_name.length < SCROLL_LENGTH
+    synchronize do
+      setproctitle
+      @x += 1
+    end
+  end
+end
\ No newline at end of file
diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb
index 81bcdf1..5186a4e 100644
--- a/lib/puppet/util/monkey_patches.rb
+++ b/lib/puppet/util/monkey_patches.rb
@@ -130,3 +130,11 @@ def lines(separator = $/)
     lines
   end
 end
+
+# Ruby 1.8.5 doesn't have tap
+module Kernel
+  def tap
+    yield(self)
+    self
+  end unless method_defined?(:tap)
+end
diff --git a/lib/puppet/util/pidlock.rb b/lib/puppet/util/pidlock.rb
index fcf0cf2..9ed8635 100644
--- a/lib/puppet/util/pidlock.rb
+++ b/lib/puppet/util/pidlock.rb
@@ -1,11 +1,7 @@
 require 'fileutils'
+require 'puppet/util/anonymous_filelock'
 
-class Puppet::Util::Pidlock
-  attr_reader :lockfile
-
-  def initialize(lockfile)
-    @lockfile = lockfile
-  end
+class Puppet::Util::Pidlock < Puppet::Util::AnonymousFilelock
 
   def locked?
     clear_if_stale
@@ -17,29 +13,18 @@ def mine?
   end
 
   def anonymous?
-    return false unless File.exists?(@lockfile)
-    File.read(@lockfile) == ""
+    false
   end
 
-  def lock(opts = {})
-    opts = {:anonymous => false}.merge(opts)
+  def lock
+    return mine? if locked?
 
-    if locked?
-      mine?
-    else
-      if opts[:anonymous]
-        File.open(@lockfile, 'w') { |fd| true }
-      else
-        File.open(@lockfile, "w") { |fd| fd.write(Process.pid) }
-      end
-      true
-    end
+    File.open(@lockfile, "w") { |fd| fd.write(Process.pid) }
+    true
   end
 
   def unlock(opts = {})
-    opts = {:anonymous => false}.merge(opts)
-
-    if mine? or (opts[:anonymous] and anonymous?)
+    if mine?
       File.unlink(@lockfile)
       true
     else
@@ -47,7 +32,6 @@ def unlock(opts = {})
     end
   end
 
-  private
   def lock_pid
     if File.exists? @lockfile
       File.read(@lockfile).to_i
@@ -56,6 +40,7 @@ def lock_pid
     end
   end
 
+  private
   def clear_if_stale
     return if lock_pid.nil?
 
diff --git a/lib/puppet/util/queue/stomp.rb b/lib/puppet/util/queue/stomp.rb
index cabc566..4a7081b 100644
--- a/lib/puppet/util/queue/stomp.rb
+++ b/lib/puppet/util/queue/stomp.rb
@@ -2,12 +2,14 @@
 require 'stomp'
 require 'uri'
 
-# Implements the Ruby Stomp client as a queue type within the Puppet::Indirector::Queue::Client
-# registry, for use with the <tt>:queue</tt> indirection terminus type.
+# Implements the Ruby Stomp client as a queue type within the
+# Puppet::Indirector::Queue::Client registry, for use with the <tt>:queue</tt>
+# indirection terminus type.
 #
-# Looks to <tt>Puppet[:queue_source]</tt> for the sole argument to the underlying Stomp::Client constructor;
-# consequently, for this client to work, <tt>Puppet[:queue_source]</tt> must use the Stomp::Client URL-like
-# syntax for identifying the Stomp message broker: <em>login:pa...@host.port</em>
+# Looks to <tt>Puppet[:queue_source]</tt> for the sole argument to the
+# underlying Stomp::Client constructor; consequently, for this client to work,
+# <tt>Puppet[:queue_source]</tt> must use the Stomp::Client URL-like syntax
+# for identifying the Stomp message broker: <em>login:pa...@host.port</em>
 class Puppet::Util::Queue::Stomp
   attr_accessor :stomp_client
 
@@ -26,10 +28,21 @@ def initialize
     rescue => detail
       raise ArgumentError, "Could not create Stomp client instance with queue source #{Puppet[:queue_source]}: got internal Stomp client error #{detail}"
     end
+
+    # Identify the supported method for sending messages.
+    @method =
+      case
+      when stomp_client.respond_to?(:publish)
+        :publish
+      when stomp_client.respond_to?(:send)
+        :send
+      else
+        raise ArgumentError, "STOMP client does not respond to either publish or send"
+      end
   end
 
   def publish_message(target, msg)
-    stomp_client.publish(stompify_target(target), msg, :persistent => true)
+    stomp_client.__send__(@method, stompify_target(target), msg, :persistent => true)
   end
 
   def subscribe(target)
diff --git a/lib/puppet/util/reference.rb b/lib/puppet/util/reference.rb
index ae5f2d4..6003251 100644
--- a/lib/puppet/util/reference.rb
+++ b/lib/puppet/util/reference.rb
@@ -64,8 +64,6 @@ def self.references
     loaded_instances(:reference).sort { |a,b| a.to_s <=> b.to_s }
   end
 
-  HEADER_LEVELS = [nil, "#", "##", "###", "####", "#####"]
-
   attr_accessor :page, :depth, :header, :title, :dynamic
   attr_writer :doc
 
@@ -81,20 +79,6 @@ def dynamic?
     self.dynamic
   end
 
-  def markdown_header(name, level)
-    "#{HEADER_LEVELS[level]} #{name}\n\n"
-  end
-
-  def markdown_definitionlist(term, definition)
-    lines = definition.split("\n")
-    str = "#{term}\n: #{lines.shift}\n"
-    lines.each do |line|
-      str << "    " if line =~ /\S/
-      str << "#{line}\n"
-    end
-    str << "\n"
-  end
-
   def initialize(name, options = {}, &block)
     @name = name
     options.each do |option, value|
diff --git a/lib/puppet/util/retryaction.rb b/lib/puppet/util/retryaction.rb
new file mode 100644
index 0000000..ba318ec
--- /dev/null
+++ b/lib/puppet/util/retryaction.rb
@@ -0,0 +1,48 @@
+module Puppet::Util::RetryAction
+  class RetryException < Exception; end
+  class RetryException::NoBlockGiven < RetryException; end
+  class RetryException::NoRetriesGiven < RetryException;end
+  class RetryException::RetriesExceeded < RetryException; end
+
+  def self.retry_action( parameters = { :retry_exceptions => nil, :retries => nil } )
+    # Retry actions for a specified amount of time. This method will allow the final
+    # retry to complete even if that extends beyond the timeout period.
+    unless block_given?
+      raise RetryException::NoBlockGiven
+    end
+
+    raise RetryException::NoRetriesGiven if parameters[:retries].nil?
+    parameters[:retry_exceptions] ||= Hash.new
+
+    start = Time.now
+    failures = 0
+
+    begin
+      yield
+    rescue Exception => e
+      # If we were giving exceptions to catch,
+      # catch the excptions we care about and retry.
+      # All others fail hard
+
+      raise RetryException::RetriesExceeded if parameters[:retries] == 0
+
+      if (not parameters[:retry_exceptions].keys.empty?) and parameters[:retry_exceptions].keys.include?(e.class)
+        Puppet.info("Caught exception #{e.class}:#{e}")
+        Puppet.info(parameters[:retry_exceptions][e.class])
+      elsif (not parameters[:retry_exceptions].keys.empty?)
+        # If the exceptions is not in the list of retry_exceptions re-raise.
+        raise e
+      end
+
+      failures += 1
+      parameters[:retries] -= 1
+
+      # Increase the amount of time that we sleep after every
+      # failed retry attempt.
+      sleep (((2 ** failures) -1) * 0.1)
+
+      retry
+
+    end
+  end
+end
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index aaa4f44..9f4fb00 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -782,7 +782,6 @@ def get_config_file_default(default)
     obj
   end
 
-  # Create the transportable objects for users and groups.
   def add_user_resources(catalog, sections)
     return unless Puppet.features.root?
     return if Puppet.features.microsoft_windows?
diff --git a/lib/puppet/util/zaml.rb b/lib/puppet/util/zaml.rb
index bbb2af2..e07a2d7 100644
--- a/lib/puppet/util/zaml.rb
+++ b/lib/puppet/util/zaml.rb
@@ -1,4 +1,15 @@
+# encoding: UTF-8
 #
+# The above encoding line is a magic comment to set the default source encoding
+# of this file for the Ruby interpreter.  It must be on the first or second
+# line of the file if an interpreter is in use.  In Ruby 1.9 and later, the
+# source encoding determines the encoding of String and Regexp objects created
+# from this source file.  This explicit encoding is important becuase otherwise
+# Ruby will pick an encoding based on LANG or LC_CTYPE environment variables.
+# These may be different from site to site so it's important for us to
+# establish a consistent behavior.  For more information on M17n please see:
+# http://links.puppetlabs.com/understanding_m17n
+
 # ZAML -- A partial replacement for YAML, writen with speed and code clarity
 #         in mind.  ZAML fixes one YAML bug (loading Exceptions) and provides
 #         a replacement for YAML.dump unimaginatively called ZAML.dump,
@@ -218,10 +229,16 @@ def self.yaml_new( klass, tag, val )
 class String
   ZAML_ESCAPES = %w{\x00 \x01 \x02 \x03 \x04 \x05 \x06 \a \x08 \t \n \v \f \r \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f }
   def escaped_for_zaml
-    gsub( /\x5C/, "\\\\\\" ).  # Demi-kludge for Maglev/rubinius; the regexp should be /\\/ but parsetree chokes on that.
-    gsub( /"/, "\\\"" ).
-    gsub( /([\x00-\x1F])/ ) { |x| ZAML_ESCAPES[ x.unpack("C")[0] ] }.
-    gsub( /([\x80-\xFF])/ ) { |x| "\\x#{x.unpack("C")[0].to_s(16)}" }
+    # JJM (Note the trailing dots to construct a multi-line method chain.) This
+    # code is meant to escape all bytes which are not ASCII-8BIT printable
+    # characters.  Multi-byte unicode characters are handled just fine because
+    # each byte of the character results in an escaped string emitted to the
+    # YAML stream.  When the YAML is de-serialized back into a String the bytes
+    # will be reconstructed properly into the unicode character.
+    self.to_ascii8bit.gsub( /\x5C/n, "\\\\\\" ).  # Demi-kludge for Maglev/rubinius; the regexp should be /\\/ but parsetree chokes on that.
+    gsub( /"/n, "\\\"" ).
+    gsub( /([\x00-\x1F])/n ) { |x| ZAML_ESCAPES[ x.unpack("C")[0] ] }.
+    gsub( /([\x80-\xFF])/n ) { |x| "\\x#{x.unpack("C")[0].to_s(16)}" }
   end
   def to_zaml(z)
     z.first_time_only(self) {
@@ -238,7 +255,10 @@ def to_zaml(z)
           (self =~ /[\s:]$/) or
           (self =~ /^[>|][-+\d]*\s/i) or
           (self[-1..-1] =~ /\s/) or
-          (self =~ /[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/) or
+          # This regular expression assumes the string is a byte sequence.
+          # It does not concern itself with characters so we convert the string
+          # to ASCII-8BIT for Ruby 1.9 to match up encodings.
+          (self.to_ascii8bit=~ /[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/n) or
           (self =~ /[,\[\]\{\}\r\t]|:\s|\s#/) or
           (self =~ /\A([-:?!#&*'"]|<<|%.+:.)/)
           )
@@ -251,6 +271,20 @@ def to_zaml(z)
       end
     }
   end
+
+  # Return a guranteed ASCII-8BIT encoding for Ruby 1.9 This is a helper
+  # method for other methods that perform regular expressions against byte
+  # sequences deliberately rather than dealing with characters.
+  # The method may or may not return a new instance.
+  def to_ascii8bit
+    if self.respond_to?(:encoding) and self.encoding.name != "ASCII-8BIT" then
+      str = self.dup
+      str.force_encoding("ASCII-8BIT")
+      return str
+    else
+      return self
+    end
+  end
 end
 
 class Hash
diff --git a/spec/fixtures/releases/jamtur01-apache/Modulefile b/spec/fixtures/releases/jamtur01-apache/Modulefile
new file mode 100644
index 0000000..35a1ab8
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/Modulefile
@@ -0,0 +1,2 @@
+name 'jamtur01-apache'
+version '0.0.1'
diff --git a/spec/fixtures/releases/jamtur01-apache/files/httpd b/spec/fixtures/releases/jamtur01-apache/files/httpd
new file mode 100644
index 0000000..438647c
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/files/httpd
@@ -0,0 +1,24 @@
+# Configuration file for the httpd service.
+
+#
+# The default processing model (MPM) is the process-based
+# 'prefork' model.  A thread-based model, 'worker', is also
+# available, but does not work with some modules (such as PHP).
+# The service must be stopped before changing this variable.
+#
+#HTTPD=/usr/sbin/httpd.worker
+
+#
+# To pass additional options (for instance, -D definitions) to the
+# httpd binary at startup, set OPTIONS here.
+#
+#OPTIONS=
+#OPTIONS=-DDOWN
+
+#
+# By default, the httpd process is started in the C locale; to
+# change the locale in which the server runs, the HTTPD_LANG
+# variable can be set.
+#
+#HTTPD_LANG=C
+export SHORTHOST=`hostname -s`
diff --git a/spec/fixtures/releases/jamtur01-apache/files/test.vhost b/spec/fixtures/releases/jamtur01-apache/files/test.vhost
new file mode 100644
index 0000000..801bb85
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/files/test.vhost
@@ -0,0 +1,18 @@
+#
+# Test vhost
+#
+NameVirtualHost *:80
+<VirtualHost *:80>
+  ServerName testvhost
+  DocumentRoot /tmp/testvhost
+  <Directory /tmp/testvhost>
+    Options Indexes FollowSymLinks MultiViews
+    AllowOverride None
+    Order allow,deny
+    allow from all
+  </Directory>
+  ErrorLog /var/log/apache2/error.log
+  LogLevel warn
+  CustomLog /var/log/apache2/access.log combined
+  ServerSignature On
+</VirtualHost>
diff --git a/spec/fixtures/releases/jamtur01-apache/lib/puppet/provider/a2mod/debian.rb b/spec/fixtures/releases/jamtur01-apache/lib/puppet/provider/a2mod/debian.rb
new file mode 100644
index 0000000..82ced05
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/lib/puppet/provider/a2mod/debian.rb
@@ -0,0 +1,21 @@
+Puppet::Type.type(:a2mod).provide(:debian) do
+    desc "Manage Apache 2 modules on Debian-like OSes (e.g. Ubuntu)"
+
+    commands :encmd => "a2enmod"
+    commands :discmd => "a2dismod"
+
+    defaultfor :operatingsystem => [:debian, :ubuntu]
+
+    def create
+        encmd resource[:name]
+    end
+
+    def destroy
+        discmd resource[:name]
+    end
+
+    def exists?
+        mod= "/etc/apache2/mods-enabled/" + resource[:name] + ".load"
+        File.exists?(mod)
+    end
+end
diff --git a/spec/fixtures/releases/jamtur01-apache/lib/puppet/type/a2mod.rb b/spec/fixtures/releases/jamtur01-apache/lib/puppet/type/a2mod.rb
new file mode 100644
index 0000000..a53f07f
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/lib/puppet/type/a2mod.rb
@@ -0,0 +1,12 @@
+Puppet::Type.newtype(:a2mod) do
+    @doc = "Manage Apache 2 modules"
+
+    ensurable
+
+    newparam(:name) do
+       desc "The name of the module to be managed"
+
+       isnamevar
+
+    end
+end
diff --git a/spec/fixtures/releases/jamtur01-apache/manifests/dev.pp b/spec/fixtures/releases/jamtur01-apache/manifests/dev.pp
new file mode 100644
index 0000000..42605e5
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/manifests/dev.pp
@@ -0,0 +1,5 @@
+class apache::dev {
+  include apache::params
+
+  package{$apache::params::apache_dev: ensure => installed}
+}
diff --git a/spec/fixtures/releases/jamtur01-apache/manifests/init.pp b/spec/fixtures/releases/jamtur01-apache/manifests/init.pp
new file mode 100644
index 0000000..bd3f7ba
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/manifests/init.pp
@@ -0,0 +1,34 @@
+# ensure apache is installed
+class apache {
+  include apache::params
+  package{'httpd':
+    name   => $apache::params::apache_name,
+    ensure => present,
+  }
+  service { 'httpd':
+    name      => $apache::params::apache_name,
+    ensure    => running,
+    enable    => true,
+    subscribe => Package['httpd'],
+  }
+  #
+  # May want to purge all none realize modules using the resources resource type.
+  # A2mod resource type is broken.  Look into fixing it and moving it into apache.
+  #
+  A2mod { require => Package['httpd'], notify => Service['httpd']}
+  @a2mod {
+   'rewrite' : ensure => present;
+   'headers' : ensure => present;
+   'expires' : ensure => present;
+  }
+  $vdir = $operatingsystem? {
+    'ubuntu' => '/etc/apache2/sites-enabled/',
+    default => '/etc/httpd/conf.d',
+  }
+  file { $vdir:
+    ensure => directory,
+    recurse => true,
+    purge => true,
+    notify => Service['httpd'],
+  }
+}
diff --git a/spec/fixtures/releases/jamtur01-apache/manifests/params.pp b/spec/fixtures/releases/jamtur01-apache/manifests/params.pp
new file mode 100644
index 0000000..520eccb
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/manifests/params.pp
@@ -0,0 +1,17 @@
+class apache::params{
+  $user  = 'www-data'
+  $group = 'www-data'
+
+  case $operatingsystem {
+    "centos": {
+       $apache_name = httpd
+       $ssl_package = mod_ssl
+       $apache_dev  = httpd-devel
+    }
+    "ubuntu": {
+       $apache_name = apache2
+       $ssl_package = apache-ssl
+       $apache_dev  = [ libaprutil1-dev, libapr1-dev, apache2-prefork-dev ]
+    }
+  }
+}
diff --git a/spec/fixtures/releases/jamtur01-apache/manifests/php.pp b/spec/fixtures/releases/jamtur01-apache/manifests/php.pp
new file mode 100644
index 0000000..0827e80
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/manifests/php.pp
@@ -0,0 +1,5 @@
+class apache::php{
+  package{'libapache2-mod-php5':
+    ensure => present,
+  }
+}
diff --git a/spec/fixtures/releases/jamtur01-apache/manifests/ssl.pp b/spec/fixtures/releases/jamtur01-apache/manifests/ssl.pp
new file mode 100644
index 0000000..349f922
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/manifests/ssl.pp
@@ -0,0 +1,15 @@
+class apache::ssl {
+  include apache
+
+
+  case $operatingsystem {
+     "centos": {
+        package { $apache::params::ssl_package:
+           require => Package['httpd'],
+        }
+     }
+     "ubuntu": {
+        a2mod { "ssl": ensure => present, }
+     }
+  }
+}
diff --git a/spec/fixtures/releases/jamtur01-apache/manifests/vhost.pp b/spec/fixtures/releases/jamtur01-apache/manifests/vhost.pp
new file mode 100644
index 0000000..2fe6ed2
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/manifests/vhost.pp
@@ -0,0 +1,15 @@
+define apache::vhost( $port, $docroot, $ssl=true, $template='apache/vhost-default.conf.erb', $priority, $serveraliases = '' ) {
+  include apache
+  $vdir = $operatingsystem? {
+    'ubuntu' => '/etc/apache2/sites-enabled/',
+    default => '/etc/httpd/conf.d',
+  }
+  file{"${vdir}/${priority}-${name}":
+    content => template($template),
+    owner => 'root',
+    group => 'root',
+    mode => '777',
+    require => Package['httpd'],
+    notify => Service['httpd'],
+  }
+}
diff --git a/spec/fixtures/releases/jamtur01-apache/metadata.json b/spec/fixtures/releases/jamtur01-apache/metadata.json
new file mode 100644
index 0000000..7fb6c08
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/metadata.json
@@ -0,0 +1 @@
+{"dependencies":[],"types":[{"providers":[{"name":"a2mod","doc":"Manage Apache 2 modules on Debian and Ubuntu  Required binaries: ``a2enmod``, ``a2dismod``.    Default for ``operatingsystem`` == ``debianubuntu``.  "}],"parameters":[{"name":"name","doc":"The name of the module to be managed"}],"properties":[{"name":"ensure","doc":"The basic property that the resource should be in.  Valid values are ``present``, ``absent``."}],"name":"a2mod","doc":"Manage Apache 2 modules on Debian and Ubuntu"}],"checksums":{"manifests/params.pp":"71734796921dbdbfd58f503622527616","tests/ssl.pp":"191912535199531fd631f911c6329e56","tests/vhost.pp":"1b91e03c8ef89a7ecb6793831ac18399","manifests/php.pp":"b78cc593f1c4cd800c906e0891c9b11f","files/httpd":"295f5e924afe6f752d29327e73fe6d0a","tests/php.pp":"ce7bb9eef69d32b42a32ce32d9653625","lib/puppet/provider/a2mod/a2mod.rb":"18c5bb180b75a2375e95e07f88a94257","files/test.vhost":"0602022c19a7b6b289f218c7b93c1aea","manifests/ssl.pp":"b4334a161a2ba5fa8a62cf7b38f352c8","manifests/dev.pp":"510813942246cc9a7786d8f2d8874a35","manifests/vhost.pp":"cbc4657b0cce5cd432057393d5f6b0c2","tests/init.pp":"4eac4a7ef68499854c54a78879e25535","lib/puppet/type/a2mod.rb":"0e1b4843431413a10320ac1f6a055d15","tests/apache.pp":"4eac4a7ef68499854c54a78879e25535","tests/dev.pp":"4cf15c1fecea3ca86009f182b402c7ab","templates/vhost-default.conf.erb":"9055aed946e1111c30ab81fedac2c8b0","manifests/init.pp":"dc503e26e8021351078813b541c4bd3d","Modulefile":"d43334b4072cd1744121b3b25cd9ed15"},"version":"0.0.1","name":"jamtur01-apache"}
\ No newline at end of file
diff --git a/spec/fixtures/releases/jamtur01-apache/templates/vhost-default.conf.erb b/spec/fixtures/releases/jamtur01-apache/templates/vhost-default.conf.erb
new file mode 100644
index 0000000..3aaf945
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/templates/vhost-default.conf.erb
@@ -0,0 +1,20 @@
+NameVirtualHost *:<%= port %>
+<VirtualHost *:<%= port %>>
+  ServerName <%= name %>
+<%if serveraliases.is_a? Array -%>
+<% serveraliases.each do |name| -%><%= "  ServerAlias #{name}\n" %><% end -%>
+<% elsif serveraliases != '' -%>
+<%= "  ServerAlias #{serveraliases}" -%>
+<% end -%>
+  DocumentRoot <%= docroot %>
+  <Directory <%= docroot %>>
+    Options Indexes FollowSymLinks MultiViews
+    AllowOverride None
+    Order allow,deny
+    allow from all
+  </Directory>
+  ErrorLog /var/log/apache2/<%= name %>_error.log
+  LogLevel warn
+  CustomLog /var/log/apache2/<%= name %>_access.log combined
+  ServerSignature On
+</VirtualHost>
diff --git a/spec/fixtures/releases/jamtur01-apache/tests/apache.pp b/spec/fixtures/releases/jamtur01-apache/tests/apache.pp
new file mode 100644
index 0000000..b3f9f13
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/tests/apache.pp
@@ -0,0 +1 @@
+include apache
diff --git a/spec/fixtures/releases/jamtur01-apache/tests/dev.pp b/spec/fixtures/releases/jamtur01-apache/tests/dev.pp
new file mode 100644
index 0000000..805ad7e
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/tests/dev.pp
@@ -0,0 +1 @@
+include apache::dev
diff --git a/spec/fixtures/releases/jamtur01-apache/tests/init.pp b/spec/fixtures/releases/jamtur01-apache/tests/init.pp
new file mode 100644
index 0000000..b3f9f13
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/tests/init.pp
@@ -0,0 +1 @@
+include apache
diff --git a/spec/fixtures/releases/jamtur01-apache/tests/php.pp b/spec/fixtures/releases/jamtur01-apache/tests/php.pp
new file mode 100644
index 0000000..618e0eb
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/tests/php.pp
@@ -0,0 +1 @@
+include apache::php
diff --git a/spec/fixtures/releases/jamtur01-apache/tests/ssl.pp b/spec/fixtures/releases/jamtur01-apache/tests/ssl.pp
new file mode 100644
index 0000000..cf2dacf
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/tests/ssl.pp
@@ -0,0 +1 @@
+include apache::ssl
diff --git a/spec/fixtures/releases/jamtur01-apache/tests/vhost.pp b/spec/fixtures/releases/jamtur01-apache/tests/vhost.pp
new file mode 100644
index 0000000..c916596
--- /dev/null
+++ b/spec/fixtures/releases/jamtur01-apache/tests/vhost.pp
@@ -0,0 +1,2 @@
+include apache
+apache::vhost { 'test.vhost': source => 'puppet:///modules/apache/test.vhost' }
diff --git a/spec/fixtures/unit/provider/augeas/augeas/etc/fstab b/spec/fixtures/unit/provider/augeas/augeas/etc/fstab
new file mode 100644
index 0000000..ddbd8ff
--- /dev/null
+++ b/spec/fixtures/unit/provider/augeas/augeas/etc/fstab
@@ -0,0 +1,10 @@
+/dev/vg00/lv00          /                       ext3    defaults        1 1
+LABEL=/boot             /boot                   ext3    defaults        1 2
+devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
+tmpfs                   /dev/shm                tmpfs   defaults        0 0
+/dev/vg00/home          /home                   ext3    defaults        1 2
+proc                    /proc                   proc    defaults        0 0
+sysfs                   /sys                    sysfs   defaults        0 0
+/dev/vg00/local         /local                  ext3    defaults        1 2
+/dev/vg00/images        /var/lib/xen/images     ext3    defaults        1 2
+/dev/vg00/swap          swap                    swap    defaults        0 0
diff --git a/spec/fixtures/unit/provider/augeas/augeas/etc/hosts b/spec/fixtures/unit/provider/augeas/augeas/etc/hosts
new file mode 100644
index 0000000..44cd9da
--- /dev/null
+++ b/spec/fixtures/unit/provider/augeas/augeas/etc/hosts
@@ -0,0 +1,6 @@
+# Do not remove the following line, or various programs
+# that require network functionality will fail.
+127.0.0.1	localhost.localdomain	localhost galia.watzmann.net galia
+#172.31.122.254   granny.watzmann.net granny puppet
+#172.31.122.1     galia.watzmann.net galia
+172.31.122.14   orange.watzmann.net orange
diff --git a/spec/fixtures/unit/provider/augeas/augeas/etc/test b/spec/fixtures/unit/provider/augeas/augeas/etc/test
new file mode 100644
index 0000000..86e041d
--- /dev/null
+++ b/spec/fixtures/unit/provider/augeas/augeas/etc/test
@@ -0,0 +1,3 @@
+foo
+bar
+baz
diff --git a/spec/fixtures/unit/provider/augeas/augeas/test.aug b/spec/fixtures/unit/provider/augeas/augeas/test.aug
new file mode 100644
index 0000000..bea707e
--- /dev/null
+++ b/spec/fixtures/unit/provider/augeas/augeas/test.aug
@@ -0,0 +1,13 @@
+(*
+Simple lens, written to be distributed with Puppet unit tests.
+
+Author: Dominic Cleal <dcl...@redhat.com>
+
+About: License:
+  This file is licensed under the Apache 2.0 licence, like the rest of Puppet.
+*)
+
+module Test = autoload xfm
+let lns = [ seq "line" . store /[^\n]+/ . del "\n" "\n" ]*
+let filter = incl "/etc/test"
+let xfm = transform lns filter
diff --git a/spec/integration/configurer_spec.rb b/spec/integration/configurer_spec.rb
index f5d8bce..abe8770 100755
--- a/spec/integration/configurer_spec.rb
+++ b/spec/integration/configurer_spec.rb
@@ -47,6 +47,7 @@
       Puppet::Transaction::Report.indirection.stubs(:save)
 
       Puppet[:lastrunfile] = tmpfile("lastrunfile")
+      Puppet.settings.setting(:lastrunfile).mode = 0666
       Puppet[:report] = true
 
       # We only record integer seconds in the timestamp, and truncate
@@ -56,6 +57,10 @@
       @configurer.run :catalog => @catalog, :report => report
       t2 = Time.now.tv_sec
 
+      file_mode = Puppet.features.microsoft_windows? ? '100644' : '100666'
+
+      File.stat(Puppet[:lastrunfile]).mode.to_s(8).should == file_mode
+
       summary = nil
       File.open(Puppet[:lastrunfile], "r") do |fd|
         summary = YAML.load(fd.read)
diff --git a/spec/integration/module_tool_spec.rb b/spec/integration/module_tool_spec.rb
new file mode 100644
index 0000000..1067bfa
--- /dev/null
+++ b/spec/integration/module_tool_spec.rb
@@ -0,0 +1,477 @@
+require 'spec_helper'
+require 'tmpdir'
+require 'fileutils'
+
+# FIXME This are helper methods that could be used by other tests in the
+# future, should we move these to a more central location
+def stub_repository_read(code, body)
+  kind = Net::HTTPResponse.send(:response_class, code.to_s)
+  response = kind.new('1.0', code.to_s, 'HTTP MESSAGE')
+  response.stubs(:read_body).returns(body)
+  Puppet::Module::Tool::Repository.any_instance.stubs(:read_response).returns(response)
+end
+
+def stub_installer_read(body)
+  Puppet::Module::Tool::Applications::Installer.any_instance.stubs(:read_match).returns(body)
+end
+
+def stub_cache_read(body)
+  Puppet::Module::Tool::Cache.any_instance.stubs(:read_retrieve).returns(body)
+end
+
+# Return path to temparory directory for testing.
+def testdir
+  return @testdir ||= tmpdir("module_tool_testdir")
+end
+
+# Create a temporary testing directory, change into it, and execute the
+# +block+. When the block exists, remove the test directory and change back
+# to the previous directory.
+def mktestdircd(&block)
+  previousdir = Dir.pwd
+  rmtestdir
+  FileUtils.mkdir_p(testdir)
+  Dir.chdir(testdir)
+  block.call
+ensure
+  rmtestdir
+  Dir.chdir previousdir
+end
+
+# Remove the temporary test directory.
+def rmtestdir
+  FileUtils.rm_rf(testdir) if File.directory?(testdir)
+end
+# END helper methods
+
+
+# Directory that contains sample releases.
+RELEASE_FIXTURES_DIR = File.join(PuppetSpec::FIXTURE_DIR, "releases")
+
+# Return the pathname string to the directory containing the release fixture called +name+.
+def release_fixture(name)
+  return File.join(RELEASE_FIXTURES_DIR, name)
+end
+
+# Copy the release fixture called +name+ into the current working directory.
+def install_release_fixture(name)
+  release_fixture(name)
+  FileUtils.cp_r(release_fixture(name), name)
+end
+
+describe "module_tool", :fails_on_windows => true do
+  include PuppetSpec::Files
+  before do
+    @tmp_confdir = Puppet[:confdir] = tmpdir("module_tool_test_confdir")
+    @tmp_vardir = Puppet[:vardir] = tmpdir("module_tool_test_vardir")
+    Puppet[:module_repository] = "http://forge.puppetlabs.com"
+    @mytmpdir = Pathname.new(tmpdir("module_tool_test"))
+    @options = {}
+    @options[:install_dir] = @mytmpdir
+    @options[:module_repository] = "http://forge.puppetlabs.com"
+  end
+
+  def build_and_install_module
+    Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+    Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+
+    FileUtils.mv("#{@full_module_name}/pkg/#{@release_name}.tar.gz", "#{@release_name}.tar.gz")
+    FileUtils.rm_rf(@full_module_name)
+
+    Puppet::Module::Tool::Applications::Installer.run("#{@release_name}.tar.gz", @options)
+  end
+
+  # Return STDOUT and STDERR output generated from +block+ as it's run within a temporary test directory.
+  def run(&block)
+    mktestdircd do
+      block.call
+    end
+  end
+
+  before :all do
+    @username = "myuser"
+    @module_name  = "mymodule"
+    @full_module_name = "#{@username}-#{@module_name}"
+    @version = "0.0.1"
+    @release_name = "#{@full_module_name}-#{@version}"
+  end
+
+  before :each do
+    Puppet.settings.stubs(:parse)
+    Puppet::Module::Tool::Cache.clean
+  end
+
+  after :each do
+    Puppet::Module::Tool::Cache.clean
+  end
+
+  describe "generate" do
+    it "should generate a module if given a dashed name" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+
+        File.directory?(@full_module_name).should == true
+        modulefile = File.join(@full_module_name, "Modulefile")
+        File.file?(modulefile).should == true
+        metadata = Puppet::Module::Tool::Metadata.new
+        Puppet::Module::Tool::ModulefileReader.evaluate(metadata, modulefile)
+        metadata.full_module_name.should == @full_module_name
+        metadata.username.should == @username
+        metadata.name.should == @module_name
+      end
+    end
+
+    it "should fail if given an undashed name" do
+      run do
+        lambda { Puppet::Module::Tool::Applications::Generator.run("invalid") }.should raise_error(RuntimeError)
+      end
+    end
+
+    it "should fail if directory already exists" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        lambda { Puppet::Module::Tool::Applications::Generator.run(@full_module_name) }.should raise_error(ArgumentError)
+      end
+    end
+
+    it "should return an array of Pathname objects representing paths of generated files" do
+      run do
+        return_value = Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        return_value.each do |generated_file|
+          generated_file.should be_kind_of(Pathname)
+        end
+        return_value.should be_kind_of(Array)
+      end
+    end
+  end
+
+  describe "build" do
+    it "should build a module in a directory" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+
+        File.directory?(File.join(@full_module_name, "pkg", @release_name)).should == true
+        File.file?(File.join(@full_module_name, "pkg", @release_name + ".tar.gz")).should == true
+        metadata_file = File.join(@full_module_name, "pkg", @release_name, "metadata.json")
+        File.file?(metadata_file).should == true
+        metadata = PSON.parse(File.read(metadata_file))
+        metadata["name"].should == @full_module_name
+        metadata["version"].should == @version
+        metadata["checksums"].should be_a_kind_of(Hash)
+        metadata["dependencies"].should == []
+        metadata["types"].should == []
+      end
+    end
+
+    it "should build a module's checksums" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+
+        metadata_file = File.join(@full_module_name, "pkg", @release_name, "metadata.json")
+        metadata = PSON.parse(File.read(metadata_file))
+        metadata["checksums"].should be_a_kind_of(Hash)
+
+        modulefile_path = Pathname.new(File.join(@full_module_name, "Modulefile"))
+        metadata["checksums"]["Modulefile"].should == Digest::MD5.hexdigest(modulefile_path.read)
+      end
+    end
+
+    it "should build a module's types and providers" do
+      run do
+        name = "jamtur01-apache"
+        install_release_fixture name
+        Puppet::Module::Tool::Applications::Builder.run(name)
+
+        metadata_file = File.join(name, "pkg", "#{name}-0.0.1", "metadata.json")
+        metadata = PSON.parse(File.read(metadata_file))
+
+        metadata["types"].size.should == 1
+        type = metadata["types"].first
+        type["name"].should == "a2mod"
+        type["doc"].should == "Manage Apache 2 modules"
+
+
+        type["parameters"].size.should == 1
+        type["parameters"].first.tap do |o|
+          o["name"].should == "name"
+          o["doc"].should == "The name of the module to be managed"
+        end
+
+        type["properties"].size.should == 1
+        type["properties"].first.tap do |o|
+          o["name"].should == "ensure"
+          o["doc"].should =~ /present.+absent/
+        end
+
+        type["providers"].size.should == 1
+        type["providers"].first.tap do |o|
+          o["name"].should == "debian"
+          o["doc"].should =~ /Manage Apache 2 modules on Debian-like OSes/
+        end
+      end
+    end
+
+    it "should build a module's dependencies" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        modulefile = File.join(@full_module_name, "Modulefile")
+
+        dependency1_name = "anotheruser-anothermodule"
+        dependency1_requirement = ">= 1.2.3"
+        dependency2_name = "someuser-somemodule"
+        dependency2_requirement = "4.2"
+        dependency2_repository = "http://some.repo"
+
+        File.open(modulefile, "a") do |handle|
+          handle.puts "dependency '#{dependency1_name}', '#{dependency1_requirement}'"
+          handle.puts "dependency '#{dependency2_name}', '#{dependency2_requirement}', '#{dependency2_repository}'"
+        end
+
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+
+        metadata_file = File.join(@full_module_name, "pkg", "#{@full_module_name}-#{@version}", "metadata.json")
+        metadata = PSON.parse(File.read(metadata_file))
+
+        metadata['dependencies'].size.should == 2
+        metadata['dependencies'].sort_by{|t| t['name']}.tap do |dependencies|
+          dependencies[0].tap do |dependency1|
+            dependency1['name'].should == dependency1_name
+            dependency1['version_requirement'].should == dependency1_requirement
+            dependency1['repository'].should be_nil
+          end
+
+          dependencies[1].tap do |dependency2|
+            dependency2['name'].should == dependency2_name
+            dependency2['version_requirement'].should == dependency2_requirement
+            dependency2['repository'].should == dependency2_repository
+          end
+        end
+      end
+    end
+
+    it "should rebuild a module in a directory" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+      end
+    end
+
+    it "should build a module in the current directory" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        Dir.chdir(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(nil))
+
+        File.file?(File.join("pkg", @release_name + ".tar.gz")).should == true
+      end
+    end
+
+    it "should fail to build a module without a Modulefile" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        FileUtils.rm(File.join(@full_module_name, "Modulefile"))
+
+        lambda { Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(@full_module_name)) }.should raise_error(ArgumentError)
+      end
+    end
+
+    it "should fail to build a module directory that doesn't exist" do
+      run do
+        lambda { Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(@full_module_name)) }.should raise_error(ArgumentError)
+      end
+    end
+
+    it "should fail to build a module in the current directory that's not a module" do
+      run do
+        lambda { Puppet::Module::Tool::Applications::Builder.run(Puppet::Module::Tool.find_module_root(nil)) }.should raise_error(ArgumentError)
+      end
+    end
+
+    it "should return a Pathname object representing the path to the release archive." do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name).should be_kind_of(Pathname)
+      end
+    end
+  end
+
+  describe "search" do
+    it "should display matching modules" do
+      run do
+        stub_repository_read 200, <<-HERE
+          [
+            {"full_module_name": "cli", "version": "1.0"},
+            {"full_module_name": "web", "version": "2.0"}
+          ]
+        HERE
+        Puppet::Module::Tool::Applications::Searcher.run("mymodule", @options).size.should == 2
+      end
+    end
+
+    it "should display no matches" do
+      run do
+        stub_repository_read 200, "[]"
+        Puppet::Module::Tool::Applications::Searcher.run("mymodule", @options).should == []
+      end
+    end
+
+    it "should fail if can't get a connection" do
+      run do
+        stub_repository_read 500, "OH NOES!!1!"
+        lambda { Puppet::Module::Tool::Applications::Searcher.run("mymodule", @options) }.should raise_error(RuntimeError)
+      end
+    end
+
+    it "should return an array of module metadata hashes" do
+      run do
+        results = <<-HERE
+          [
+            {"full_module_name": "cli", "version": "1.0"},
+            {"full_module_name": "web", "version": "2.0"}
+          ]
+        HERE
+        expected = [
+          {"version"=>"1.0", "full_module_name"=>"cli"},
+          {"version"=>"2.0", "full_module_name"=>"web"}
+        ]
+        stub_repository_read 200, results
+        return_value = Puppet::Module::Tool::Applications::Searcher.run("mymodule", @options)
+        return_value.should == expected
+        return_value.should be_kind_of(Array)
+      end
+    end
+  end
+
+  describe "install" do
+    it "should install a module to the puppet modulepath by default" do
+      myothertmpdir = Pathname.new(tmpdir("module_tool_test_myothertmpdir"))
+      run do
+        @options[:install_dir] = myothertmpdir
+        Puppet::Module::Tool.unstub(:install_dir)
+
+        build_and_install_module
+
+        File.directory?(myothertmpdir + @module_name).should == true
+        File.file?(myothertmpdir + @module_name + 'metadata.json').should == true
+      end
+    end
+
+    it "should install a module from a filesystem path" do
+      run do
+        build_and_install_module
+
+        File.directory?(@mytmpdir + @module_name).should == true
+        File.file?(@mytmpdir + @module_name + 'metadata.json').should == true
+      end
+    end
+
+    it "should install a module from a webserver URL" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+
+        stub_cache_read File.read("#{@full_module_name}/pkg/#{@release_name}.tar.gz")
+        FileUtils.rm_rf(@full_module_name)
+
+        stub_installer_read <<-HERE
+          {"file": "/foo/bar/#{@release_name}.tar.gz", "version": "#{@version}"}
+        HERE
+
+        Puppet::Module::Tool::Applications::Installer.run(@full_module_name, @options)
+
+        File.directory?(@mytmpdir + @module_name).should == true
+        File.file?(@mytmpdir + @module_name + 'metadata.json').should == true
+      end
+    end
+
+    it "should install a module from a webserver URL using a version requirement" # TODO
+
+    it "should fail if module isn't a slashed name" do
+      run do
+        lambda { Puppet::Module::Tool::Applications::Installer.run("invalid") }.should raise_error(RuntimeError)
+      end
+    end
+
+    it "should fail if module doesn't exist on webserver" do
+      run do
+        stub_installer_read "{}"
+        lambda { Puppet::Module::Tool::Applications::Installer.run("not-found", @options) }.should raise_error(RuntimeError)
+      end
+    end
+
+    it "should fail gracefully when receiving invalid PSON" do
+      pending "Implement PSON error wrapper" # TODO
+      run do
+        stub_installer_read "1/0"
+        lambda { Puppet::Module::Tool::Applications::Installer.run("not-found") }.should raise_error(SystemExit)
+      end
+    end
+
+    it "should fail if installing a module that's already installed" do
+      run do
+        name = "myuser-mymodule"
+        Dir.mkdir name
+        lambda { Puppet::Module::Tool::Applications::Installer.run(name) }.should raise_error(ArgumentError)
+      end
+    end
+
+    it "should return a Pathname object representing the path to the installed module" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+
+        stub_cache_read File.read("#{@full_module_name}/pkg/#{@release_name}.tar.gz")
+        FileUtils.rm_rf(@full_module_name)
+
+        stub_installer_read <<-HERE
+          {"file": "/foo/bar/#{@release_name}.tar.gz", "version": "#{@version}"}
+        HERE
+
+        Puppet::Module::Tool::Applications::Installer.run(@full_module_name, @options).should be_kind_of(Pathname)
+      end
+    end
+
+  end
+
+  describe "clean" do
+    require 'puppet/module_tool'
+    it "should clean cache" do
+      run do
+        build_and_install_module
+        Puppet::Module::Tool::Cache.base_path.directory?.should == true
+        Puppet::Module::Tool::Applications::Cleaner.run
+        Puppet::Module::Tool::Cache.base_path.directory?.should == false
+      end
+    end
+
+    it "should return a status Hash" do
+      run do
+        build_and_install_module
+        return_value = Puppet::Module::Tool::Applications::Cleaner.run
+        return_value.should include(:msg)
+        return_value.should include(:status)
+        return_value.should be_kind_of(Hash)
+      end
+    end
+  end
+
+  describe "changes" do
+    it "should return an array of modified files" do
+      run do
+        Puppet::Module::Tool::Applications::Generator.run(@full_module_name)
+        Puppet::Module::Tool::Applications::Builder.run(@full_module_name)
+        Dir.chdir("#{@full_module_name}/pkg/#{@release_name}")
+        File.open("Modulefile", "a") do |handle|
+          handle.puts
+          handle.puts "# Added"
+        end
+        return_value = Puppet::Module::Tool::Applications::Checksummer.run(".")
+        return_value.should include("Modulefile")
+        return_value.should be_kind_of(Array)
+      end
+    end
+  end
+end
diff --git a/spec/integration/network/handler_spec.rb b/spec/integration/network/handler_spec.rb
deleted file mode 100755
index e6e6078..0000000
--- a/spec/integration/network/handler_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-
-require 'puppet/network/handler'
-
-describe Puppet::Network::Handler do
-  %w{ca filebucket fileserver master report runner status}.each do |name|
-    it "should have a #{name} client" do
-      Puppet::Network::Handler.handler(name).should be_instance_of(Class)
-    end
-
-    it "should have a name" do
-      Puppet::Network::Handler.handler(name).name.to_s.downcase.should == name.to_s.downcase
-    end
-
-    it "should have an interface" do
-      Puppet::Network::Handler.handler(name).interface.should_not be_nil
-    end
-
-    it "should have a prefix for the interface" do
-      Puppet::Network::Handler.handler(name).interface.prefix.should_not be_nil
-    end
-  end
-end
diff --git a/spec/integration/network/server/webrick_spec.rb b/spec/integration/network/server/webrick_spec.rb
index 7365462..7fa83b0 100755
--- a/spec/integration/network/server/webrick_spec.rb
+++ b/spec/integration/network/server/webrick_spec.rb
@@ -11,7 +11,7 @@
     before :each do
       Puppet[:servertype] = 'webrick'
       Puppet[:server] = '127.0.0.1'
-      @params = { :port => 34343, :handlers => [ :node ], :xmlrpc_handlers => [ :status ] }
+      @params = { :port => 34343, :handlers => [ :node ] }
 
       # Get a safe temporary file
       dir = tmpdir("webrick_integration_testing")
diff --git a/spec/integration/provider/package_spec.rb b/spec/integration/provider/package_spec.rb
index 9f4ea1e..e0d628f 100755
--- a/spec/integration/provider/package_spec.rb
+++ b/spec/integration/provider/package_spec.rb
@@ -27,6 +27,13 @@
           Puppet[:vardir] = tmpdir('msi_package_var_dir')
         end
 
+        # the instances method requires root priviledges on gentoo
+        # if the eix cache is outdated (to run eix-update) so make
+        # sure we dont actually run eix-update
+        if provider.name == :portage
+          provider.stubs(:update_eix).returns('Database contains 15240 packages in 155 categories')
+        end
+
         provider.instances.each do |package|
           package.should be_instance_of(provider)
           package.properties[:provider].should == provider.name
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index e0227be..2fe32b0 100755
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -75,6 +75,11 @@ module PuppetSpec
     # Avoid opening ports to the outside world
     Puppet.settings[:bindaddress] = "127.0.0.1"
 
+    # We don't want to depend upon the reported domain name of the
+    # machine running the tests, nor upon the DNS setup of that
+    # domain.
+    Puppet.settings[:use_srv_records] = false
+
     @logs = []
     Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs))
 
@@ -100,7 +105,7 @@ module PuppetSpec
         indirector.instance_variable_set(variable, value)
       end
     end
-    $saved_indirection_state = nil
+    $saved_indirection_state = {}
 
     GC.enable
   end
diff --git a/spec/unit/agent/disabler_spec.rb b/spec/unit/agent/disabler_spec.rb
new file mode 100644
index 0000000..5e43cf9
--- /dev/null
+++ b/spec/unit/agent/disabler_spec.rb
@@ -0,0 +1,60 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+require 'puppet/agent'
+require 'puppet/agent/locker'
+
+class LockerTester
+  include Puppet::Agent::Disabler
+end
+
+describe Puppet::Agent::Disabler do
+  before do
+    @locker = LockerTester.new
+    @locker.stubs(:lockfile_path).returns "/my/lock"
+  end
+
+  it "should use an AnonymousFilelock instance as its disable_lockfile" do
+    @locker.disable_lockfile.should be_instance_of(Puppet::Util::AnonymousFilelock)
+  end
+
+  it "should use 'lockfile_path' to determine its disable_lockfile path" do
+    @locker.expects(:lockfile_path).returns "/my/lock"
+    lock = Puppet::Util::AnonymousFilelock.new("/my/lock")
+    Puppet::Util::AnonymousFilelock.expects(:new).with("/my/lock.disabled").returns lock
+
+    @locker.disable_lockfile
+  end
+
+  it "should reuse the same lock file each time" do
+    @locker.disable_lockfile.should equal(@locker.disable_lockfile)
+  end
+
+  it "should lock the anonymous lock when disabled" do
+    @locker.disable_lockfile.expects(:lock)
+
+    @locker.disable
+  end
+
+  it "should disable with a message" do
+    @locker.disable_lockfile.expects(:lock).with("disabled because")
+
+    @locker.disable("disabled because")
+  end
+
+  it "should unlock the anonymous lock when enabled" do
+    @locker.disable_lockfile.expects(:unlock)
+
+    @locker.enable
+  end
+
+  it "should check the lock if it is disabled" do
+    @locker.disable_lockfile.expects(:locked?)
+
+    @locker.disabled?
+  end
+
+  it "should report the disable message when disabled" do
+    @locker.disable_lockfile.expects(:message).returns("message")
+    @locker.disable_message.should == "message"
+  end
+end
diff --git a/spec/unit/agent/locker_spec.rb b/spec/unit/agent/locker_spec.rb
index 341859e..9b530c0 100755
--- a/spec/unit/agent/locker_spec.rb
+++ b/spec/unit/agent/locker_spec.rb
@@ -29,18 +29,6 @@ class LockerTester
     @locker.lockfile.should equal(@locker.lockfile)
   end
 
-  it "should use the lock file to anonymously lock the process when disabled" do
-    @locker.lockfile.expects(:lock).with(:anonymous => true)
-
-    @locker.disable
-  end
-
-  it "should use the lock file to anonymously unlock the process when enabled" do
-    @locker.lockfile.expects(:unlock).with(:anonymous => true)
-
-    @locker.enable
-  end
-
   it "should have a method that yields when a lock is attained" do
     @locker.lockfile.expects(:lock).returns true
 
diff --git a/spec/unit/agent_spec.rb b/spec/unit/agent_spec.rb
index d955868..9e2840c 100755
--- a/spec/unit/agent_spec.rb
+++ b/spec/unit/agent_spec.rb
@@ -24,6 +24,7 @@ def without_warnings
 
     # So we don't actually try to hit the filesystem.
     @agent.stubs(:lock).yields
+    @agent.stubs(:disabled?).returns(false)
 
     # make Puppet::Application safe for stubbing; restore in an :after block; silence warnings for this.
     without_warnings { Puppet::Application = Class.new(Puppet::Application) }
@@ -76,6 +77,7 @@ def controlled_run(&block)
 
   describe "when being run" do
     before do
+      AgentTestClient.stubs(:lockfile_path).returns "/my/lock"
       @agent.stubs(:running?).returns false
     end
 
@@ -92,6 +94,12 @@ def controlled_run(&block)
       @agent.run
     end
 
+    it "should do nothing if disabled" do
+      @agent.expects(:disabled?).returns(true)
+      AgentTestClient.expects(:new).never
+      @agent.run
+    end
+
     it "should use Puppet::Application.controlled_run to manage process state behavior" do
       calls = sequence('calls')
       Puppet::Application.expects(:controlled_run).yields.in_sequence(calls)
diff --git a/spec/unit/application/agent_spec.rb b/spec/unit/application/agent_spec.rb
index 6d31ec3..fb5645d 100755
--- a/spec/unit/application/agent_spec.rb
+++ b/spec/unit/application/agent_spec.rb
@@ -5,7 +5,6 @@
 require 'puppet/application/agent'
 require 'puppet/network/server'
 require 'puppet/daemon'
-require 'puppet/network/handler'
 
 describe Puppet::Application::Agent do
   before :each do
@@ -91,7 +90,7 @@
       @puppetd.command_line.stubs(:args).returns([])
     end
 
-    [:centrallogging, :disable, :enable, :debug, :fqdn, :test, :verbose, :digest].each do |option|
+    [:centrallogging, :enable, :debug, :fqdn, :test, :verbose, :digest].each do |option|
       it "should declare handle_#{option} method" do
         @puppetd.should respond_to("handle_#{option}".to_sym)
       end
@@ -102,13 +101,6 @@
       end
     end
 
-    it "should set an existing handler on server" do
-      Puppet::Network::Handler.stubs(:handler).with("handler").returns(true)
-
-      @puppetd.handle_serve("handler")
-      @puppetd.options[:serve].should == [ :handler ]
-    end
-
     it "should set client to false with --no-client" do
       @puppetd.handle_no_client(nil)
       @puppetd.options[:client].should be_false
@@ -349,6 +341,20 @@
         end
       end
 
+      it "should pass the disable message when disabling" do
+        @puppetd.options.stubs(:[]).with(:disable).returns(true)
+        @puppetd.options.stubs(:[]).with(:disable_message).returns("message")
+        @agent.expects(:disable).with("message")
+        expect { @puppetd.enable_disable_client(@agent) }.to exit_with 0
+      end
+
+      it "should pass the default disable message when disabling without a message" do
+        @puppetd.options.stubs(:[]).with(:disable).returns(true)
+        @puppetd.options.stubs(:[]).with(:disable_message).returns(nil)
+        @agent.expects(:disable).with("reason not specified")
+        expect { @puppetd.enable_disable_client(@agent) }.to exit_with 0
+      end
+
       it "should finally exit" do
         expect { @puppetd.enable_disable_client(@agent) }.to exit_with 0
       end
@@ -416,25 +422,38 @@
         expect { @puppetd.setup_listen }.to exit_with 14
       end
 
-      it "should create a server to listen on at least the Runner handler" do
-        Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers] == [:Runner] }
+      it "should use puppet default port" do
+        Puppet[:puppetport] = 32768
+
+        Puppet::Network::Server.expects(:new).with { |args| args[:port] == 32768 }
 
         @puppetd.setup_listen
       end
+    end
 
-      it "should create a server to listen for specific handlers" do
-        @puppetd.options.stubs(:[]).with(:serve).returns([:handler])
-        Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers] == [:handler] }
+    describe "when setting up for fingerprint" do
+      before(:each) do
+        @puppetd.options.stubs(:[]).with(:fingerprint).returns(true)
+      end
 
-        @puppetd.setup_listen
+      it "should not setup as an agent" do
+        @puppetd.expects(:setup_agent).never
+        @puppetd.setup
       end
 
-      it "should use puppet default port" do
-        Puppet[:puppetport] = 32768
+      it "should not create an agent" do
+        Puppet::Agent.stubs(:new).with(Puppet::Configurer).never
+        @puppetd.setup
+      end
 
-        Puppet::Network::Server.expects(:new).with { |args| args[:port] == 32768 }
+      it "should not daemonize" do
+        @daemon.expects(:daemonize).never
+        @puppetd.setup
+      end
 
-        @puppetd.setup_listen
+      it "should setup our certificate host" do
+        @puppetd.expects(:setup_host)
+        @puppetd.setup
       end
     end
   end
diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb
index b12c4fa..f2f9a8e 100755
--- a/spec/unit/application/apply_spec.rb
+++ b/spec/unit/application/apply_spec.rb
@@ -20,7 +20,7 @@
     Puppet::Node.indirection.cache_class = nil
   end
 
-  [:debug,:loadclasses,:verbose,:use_nodes,:detailed_exitcodes].each do |option|
+  [:debug,:loadclasses,:verbose,:use_nodes,:detailed_exitcodes,:catalog].each do |option|
     it "should declare handle_#{option} method" do
       @apply.should respond_to("handle_#{option}".to_sym)
     end
@@ -53,6 +53,17 @@
 
       @apply.handle_logdest("console")
     end
+
+    it "should deprecate --apply" do
+      Puppet.expects(:warning).with do |arg|
+        arg.match(/--apply is deprecated/)
+      end
+
+      command_line = Puppet::Util::CommandLine.new('puppet', ['apply', '--apply', 'catalog.json'])
+      apply = Puppet::Application::Apply.new(command_line)
+      apply.stubs(:run_command)
+      apply.run
+    end
   end
 
   describe "during setup" do
@@ -155,6 +166,11 @@
         Puppet::Configurer.any_instance.stubs(:save_last_run_summary) # to prevent it from trying to write files
       end
 
+      after :each do
+        Puppet::Node::Facts.indirection.reset_terminus_class
+        Puppet::Node::Facts.indirection.cache_class = nil
+      end
+
       it "should set the code to run from --code" do
         @apply.options[:code] = "code to run"
         Puppet.expects(:[]=).with(:code,"code to run")
diff --git a/spec/unit/application/cert_spec.rb b/spec/unit/application/cert_spec.rb
index 300234c..8f0021a 100755
--- a/spec/unit/application/cert_spec.rb
+++ b/spec/unit/application/cert_spec.rb
@@ -2,7 +2,7 @@
 require 'spec_helper'
 require 'puppet/application/cert'
 
-describe Puppet::Application::Cert, :'fails_on_ruby_1.9.2' => true do
+describe Puppet::Application::Cert => true do
   before :each do
     @cert_app = Puppet::Application[:cert]
     Puppet::Util::Log.stubs(:newdestination)
diff --git a/spec/unit/application/master_spec.rb b/spec/unit/application/master_spec.rb
index c6df48f..7a70bb9 100755
--- a/spec/unit/application/master_spec.rb
+++ b/spec/unit/application/master_spec.rb
@@ -312,19 +312,6 @@
         @master.main
       end
 
-      it "should create the server with the right XMLRPC handlers" do
-        Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers] == [:Status, :FileServer, :Master, :Report, :Filebucket]}
-
-        @master.main
-      end
-
-      it "should create the server with a :ca xmlrpc handler if needed" do
-        Puppet.stubs(:[]).with(:ca).returns(true)
-        Puppet::Network::Server.expects(:new).with { |args| args[:xmlrpc_handlers].include?(:CA) }
-
-        @master.main
-      end
-
       it "should generate a SSL cert for localhost" do
         Puppet::SSL::Host.expects(:localhost)
 
@@ -367,17 +354,6 @@
           Puppet::Network::HTTP::Rack.stubs(:new).returns(@app)
         end
 
-        it "it should create the app with REST and XMLRPC support" do
-          @master.options.stubs(:[]).with(:rack).returns(:true)
-
-          Puppet::Network::HTTP::Rack.expects(:new).with { |args|
-            args[:xmlrpc_handlers] == [:Status, :FileServer, :Master, :Report, :Filebucket] and
-            args[:protocols] == [:rest, :xmlrpc]
-          }
-
-          @master.main
-        end
-
         it "it should not start a daemon" do
           @master.options.stubs(:[]).with(:rack).returns(:true)
 
diff --git a/spec/unit/application/resource_spec.rb b/spec/unit/application/resource_spec.rb
index 79935cc..2c173f9 100755
--- a/spec/unit/application/resource_spec.rb
+++ b/spec/unit/application/resource_spec.rb
@@ -4,6 +4,7 @@
 require 'puppet/application/resource'
 
 describe Puppet::Application::Resource do
+  include PuppetSpec::Files
   before :each do
     @resource_app = Puppet::Application[:resource]
     Puppet::Util::Log.stubs(:newdestination)
@@ -54,6 +55,18 @@
 
       @resource_app.extra_params.should == [ :param1, :whatever ]
     end
+
+    it "should get a parameter in the printed data if extra_params are passed" do
+      tty  = stub("tty",  :tty? => true )
+      path = tmpfile('testfile')
+      command_line = Puppet::Util::CommandLine.new("puppet", [ 'resource', 'file', path ], tty )
+      @resource_app.stubs(:command_line).returns command_line
+
+      # provider is a parameter that should always be available
+      @resource_app.extra_params = [ :provider ]
+
+      expect { @resource_app.main }.to have_printed /provider\s+=>/
+    end
   end
 
   describe "during setup" do
diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb
index fd93ceb..591358e 100755
--- a/spec/unit/application_spec.rb
+++ b/spec/unit/application_spec.rb
@@ -8,6 +8,7 @@
 describe Puppet::Application do
 
   before do
+    Puppet::Util::Instrumentation.stubs(:init)
     @app = Class.new(Puppet::Application).new
     @appclass = @app.class
 
@@ -117,6 +118,11 @@ def run_command
     @app.run_command
   end
 
+  it "should initialize the Puppet Instrumentation layer on creation" do
+    Puppet::Util::Instrumentation.expects(:init)
+    Class.new(Puppet::Application).new
+  end
+
   describe 'when invoking clear!' do
     before :each do
       Puppet::Application.run_status = :stop_requested
diff --git a/spec/unit/configurer/downloader_spec.rb b/spec/unit/configurer/downloader_spec.rb
index 215ef89..69e5e6b 100755
--- a/spec/unit/configurer/downloader_spec.rb
+++ b/spec/unit/configurer/downloader_spec.rb
@@ -60,16 +60,35 @@
       @dler.file
     end
 
-    it "should always set the owner to the current UID" do
-      Process.expects(:uid).returns 51
-      Puppet::Type.type(:file).expects(:new).with { |opts| opts[:owner] == 51 }
-      @dler.file
-    end
-
-    it "should always set the group to the current GID" do
-      Process.expects(:gid).returns 61
-      Puppet::Type.type(:file).expects(:new).with { |opts| opts[:group] == 61 }
-      @dler.file
+    describe "on POSIX" do
+      before :each do
+        Puppet.features.stubs(:microsoft_windows?).returns false
+      end
+
+      it "should always set the owner to the current UID" do
+        Process.expects(:uid).returns 51
+        Puppet::Type.type(:file).expects(:new).with { |opts| opts[:owner] == 51 }
+        @dler.file
+      end
+
+      it "should always set the group to the current GID" do
+        Process.expects(:gid).returns 61
+        Puppet::Type.type(:file).expects(:new).with { |opts| opts[:group] == 61 }
+        @dler.file
+      end
+    end
+
+    describe "on Windows", :if => Puppet.features.microsoft_windows? do
+      it "should always set the owner to the current user" do
+        Sys::Admin.expects(:get_login).returns 'foo'
+        Puppet::Type.type(:file).expects(:new).with { |opts| opts[:owner] == 'foo' }
+        @dler.file
+      end
+
+      it "should always set the group to nobody" do
+        Puppet::Type.type(:file).expects(:new).with { |opts| opts[:group] == 'S-1-0-0' }
+        @dler.file
+      end
     end
 
     it "should always force the download" do
diff --git a/spec/unit/configurer_spec.rb b/spec/unit/configurer_spec.rb
index 5c660cc..5afed1f 100755
--- a/spec/unit/configurer_spec.rb
+++ b/spec/unit/configurer_spec.rb
@@ -407,33 +407,33 @@
   end
 
   describe "when saving the summary report file" do
+    include PuppetSpec::Files
+
     before do
       Puppet.settings.stubs(:use).returns(true)
       @configurer = Puppet::Configurer.new
 
-      @report = stub 'report'
-      @trans = stub 'transaction'
-      @lastrunfd = stub 'lastrunfd'
-      Puppet::Util::FileLocking.stubs(:writelock).yields(@lastrunfd)
+      @report = stub 'report', :raw_summary => {}
+
+      Puppet[:lastrunfile] = tmpfile('last_run_file')
     end
 
-    it "should write the raw summary to the lastrunfile setting value" do
-      Puppet::Util::FileLocking.expects(:writelock).with(Puppet[:lastrunfile], 0660)
+    it "should write the last run file" do
       @configurer.save_last_run_summary(@report)
+      FileTest.exists?(Puppet[:lastrunfile]).should be_true
     end
 
     it "should write the raw summary as yaml" do
       @report.expects(:raw_summary).returns("summary")
-      @lastrunfd.expects(:print).with(YAML.dump("summary"))
       @configurer.save_last_run_summary(@report)
+      File.read(Puppet[:lastrunfile]).should == YAML.dump("summary")
     end
 
     it "should log but not fail if saving the last run summary fails" do
-      Puppet::Util::FileLocking.expects(:writelock).raises "exception"
+      Puppet[:lastrunfile] = "/dev/null/inexistant"
       Puppet.expects(:err)
       lambda { @configurer.save_last_run_summary(@report) }.should_not raise_error
     end
-
   end
 
   describe "when retrieving a catalog" do
diff --git a/spec/unit/face/config_spec.rb b/spec/unit/face/config_spec.rb
index 0c762f2..d868121 100755
--- a/spec/unit/face/config_spec.rb
+++ b/spec/unit/face/config_spec.rb
@@ -21,4 +21,11 @@
     Puppet.settings.expects(:print_config_options)
     subject.print("libdir").should be_nil
   end
+
+  it "should default to all when no arguments are given" do
+    Puppet.settings.stubs(:puts)
+    Puppet.settings.expects(:print_config_options)
+    subject.print
+    Puppet.settings[:configprint].should == "all"
+  end
 end
diff --git a/spec/unit/face/instrumentation_data.rb b/spec/unit/face/instrumentation_data.rb
new file mode 100644
index 0000000..2d4cc74
--- /dev/null
+++ b/spec/unit/face/instrumentation_data.rb
@@ -0,0 +1,7 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+require 'puppet/face'
+
+describe Puppet::Face[:instrumentation_data, '0.0.1'] do
+  it_should_behave_like "an indirector face"
+end
diff --git a/spec/unit/face/instrumentation_listener.rb b/spec/unit/face/instrumentation_listener.rb
new file mode 100644
index 0000000..87f2188
--- /dev/null
+++ b/spec/unit/face/instrumentation_listener.rb
@@ -0,0 +1,38 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+require 'puppet/face'
+
+describe Puppet::Face[:instrumentation_listener, '0.0.1'] do
+  it_should_behave_like "an indirector face"
+
+  [:enable, :disable].each do |m|
+    describe "when running ##{m}" do
+      before(:each) do
+        @listener = stub_everything 'listener'
+        Puppet::Face[:instrumentation_listener, '0.0.1'].stubs(:find).returns(@listener)
+        Puppet::Face[:instrumentation_listener, '0.0.1'].stubs(:save)
+        Puppet::Util::Instrumentation::Listener.indirection.stubs(:terminus_class=)
+      end
+
+      it "should force the REST terminus" do
+        Puppet::Util::Instrumentation::Listener.indirection.expects(:terminus_class=).with(:rest)
+        subject.send(m, "dummy")
+      end
+
+      it "should find the named listener" do
+        Puppet::Face[:instrumentation_listener, '0.0.1'].expects(:find).with("dummy").returns(@listener)
+        subject.send(m, "dummy")
+      end
+
+      it "should #{m} the named listener" do
+        @listener.expects(:enabled=).with( m == :enable )
+        subject.send(m, "dummy")
+      end
+
+      it "should save finally the listener" do
+        Puppet::Face[:instrumentation_listener, '0.0.1'].expects(:save).with(@listener)
+        subject.send(m, "dummy")
+      end
+    end
+  end
+end
diff --git a/spec/unit/face/instrumentation_probe.rb b/spec/unit/face/instrumentation_probe.rb
new file mode 100644
index 0000000..3e47590
--- /dev/null
+++ b/spec/unit/face/instrumentation_probe.rb
@@ -0,0 +1,21 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+require 'puppet/face'
+
+describe Puppet::Face[:instrumentation_probe, '0.0.1'] do
+  it_should_behave_like "an indirector face"
+
+  describe 'when running #enable' do
+    it 'should invoke #save' do
+      subject.expects(:save).with(nil)
+      subject.enable('hostname')
+    end
+  end
+
+  describe 'when running #disable' do
+    it 'should invoke #destroy' do
+      subject.expects(:destroy).with(nil)
+      subject.disable('hostname')
+    end
+  end
+end
diff --git a/spec/unit/face/module/build_spec.rb b/spec/unit/face/module/build_spec.rb
new file mode 100644
index 0000000..f4dc7f7
--- /dev/null
+++ b/spec/unit/face/module/build_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+require 'puppet/face'
+
+describe "puppet module build" do
+  subject { Puppet::Face[:module, :current] }
+
+  describe "option validation" do
+    context "without any options" do
+      it "should require a path" do
+        pattern = /wrong number of arguments/
+        expect { subject.build }.to raise_error ArgumentError, pattern
+      end
+    end
+  end
+
+  describe "inline documentation" do
+    subject { Puppet::Face[:module, :current].get_action :build }
+
+    its(:summary)     { should =~ /build.*module/im }
+    its(:description) { should =~ /build.*module/im }
+    its(:returns)     { should =~ /pathname/i }
+    its(:examples)    { should_not be_empty }
+
+    %w{ license copyright summary description returns examples }.each do |doc|
+      context "of the" do
+        its(doc.to_sym) { should_not =~ /(FIXME|REVISIT|TODO)/ }
+      end
+    end
+  end
+end
diff --git a/spec/unit/face/module/changes_spec.rb b/spec/unit/face/module/changes_spec.rb
new file mode 100644
index 0000000..eefa9d2
--- /dev/null
+++ b/spec/unit/face/module/changes_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+require 'puppet/face'
+
+describe "puppet module changes" do
+  subject { Puppet::Face[:module, :current] }
+
+  describe "option validation" do
+    context "without any options" do
+      it "should require a path" do
+        pattern = /wrong number of arguments/
+        expect { subject.changes }.to raise_error ArgumentError, pattern
+      end
+    end
+  end
+
+  describe "inline documentation" do
+    subject { Puppet::Face[:module, :current].get_action :changes }
+
+    its(:summary)     { should =~ /modified.*module/im }
+    its(:description) { should =~ /modified.*module/im }
+    its(:returns)     { should =~ /array/i }
+    its(:examples)    { should_not be_empty }
+
+    %w{ license copyright summary description returns examples }.each do |doc|
+      context "of the" do
+        its(doc.to_sym) { should_not =~ /(FIXME|REVISIT|TODO)/ }
+      end
+    end
+  end
+end
diff --git a/spec/unit/face/module/clean_spec.rb b/spec/unit/face/module/clean_spec.rb
new file mode 100644
index 0000000..708aba1
--- /dev/null
+++ b/spec/unit/face/module/clean_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+require 'puppet/face'
+
+describe "puppet module clean" do
+  subject { Puppet::Face[:module, :current] }
+
+  describe "option validation" do
+    context "without any options" do
+      it "should not require any arguments" do
+        Puppet::Module::Tool::Applications::Cleaner.expects(:run).once
+        subject.clean
+      end
+    end
+  end
+
+  describe "inline documentation" do
+    subject { Puppet::Face[:module, :current].get_action :clean }
+
+    its(:summary)     { should =~ /clean.*module/im }
+    its(:description) { should =~ /clean.*module/im }
+    its(:returns)     { should =~ /hash/i }
+    its(:examples)    { should_not be_empty }
+
+    %w{ license copyright summary description returns examples }.each do |doc|
+      context "of the" do
+        its(doc.to_sym) { should_not =~ /(FIXME|REVISIT|TODO)/ }
+      end
+    end
+  end
+end
diff --git a/spec/unit/face/module/generate_spec.rb b/spec/unit/face/module/generate_spec.rb
new file mode 100644
index 0000000..1e5a420
--- /dev/null
+++ b/spec/unit/face/module/generate_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+require 'puppet/face'
+
+describe "puppet module generate" do
+  subject { Puppet::Face[:module, :current] }
+
+  describe "option validation" do
+    context "without any options" do
+      it "should require name" do
+        pattern = /wrong number of arguments/
+        expect { subject.generate }.to raise_error ArgumentError, pattern
+      end
+    end
+  end
+
+  describe "inline documentation" do
+    subject { Puppet::Face[:module, :current].get_action :generate }
+
+    its(:summary)     { should =~ /generate.*module/im }
+    its(:description) { should =~ /generate.*module/im }
+    its(:returns)     { should =~ /array/i }
+    its(:examples)    { should_not be_empty }
+
+    %w{ license copyright summary description returns examples }.each do |doc|
+      context "of the" do
+        its(doc.to_sym) { should_not =~ /(FIXME|REVISIT|TODO)/ }
+      end
+    end
+  end
+end
diff --git a/spec/unit/face/module/install_spec.rb b/spec/unit/face/module/install_spec.rb
new file mode 100644
index 0000000..6811097
--- /dev/null
+++ b/spec/unit/face/module/install_spec.rb
@@ -0,0 +1,75 @@
+require 'spec_helper'
+require 'puppet/face'
+require 'puppet/module_tool'
+
+describe "puppet module install" do
+  subject { Puppet::Face[:module, :current] }
+
+  let(:options) do
+    {}
+  end
+
+  describe "option validation" do
+    let(:expected_options) do
+      {
+        :install_dir => File.expand_path("/dev/null/modules"),
+        :module_repository => "http://forge.puppetlabs.com",
+      }
+    end
+
+    context "without any options" do
+      it "should require a name" do
+        pattern = /wrong number of arguments/
+        expect { subject.install }.to raise_error ArgumentError, pattern
+      end
+
+      it "should not require any options" do
+        Puppet::Module::Tool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
+        subject.install("puppetlabs-apache")
+      end
+    end
+
+    it "should accept the --force option" do
+      options[:force] = true
+      expected_options.merge!(options)
+      Puppet::Module::Tool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
+      subject.install("puppetlabs-apache", options)
+    end
+
+    it "should accept the --install-dir option" do
+      options[:install_dir] = "/foo/puppet/modules"
+      expected_options.merge!(options)
+      Puppet::Module::Tool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
+      subject.install("puppetlabs-apache", options)
+    end
+
+    it "should accept the --module-repository option" do
+      options[:module_repository] = "http://forge.example.com"
+      expected_options.merge!(options)
+      Puppet::Module::Tool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
+      subject.install("puppetlabs-apache", options)
+    end
+
+    it "should accept the --version option" do
+      options[:version] = "0.0.1"
+      expected_options.merge!(options)
+      Puppet::Module::Tool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
+      subject.install("puppetlabs-apache", options)
+    end
+  end
+
+  describe "inline documentation" do
+    subject { Puppet::Face[:module, :current].get_action :install }
+
+    its(:summary)     { should =~ /install.*module/im }
+    its(:description) { should =~ /install.*module/im }
+    its(:returns)     { should =~ /pathname/i }
+    its(:examples)    { should_not be_empty }
+
+    %w{ license copyright summary description returns examples }.each do |doc|
+      context "of the" do
+        its(doc.to_sym) { should_not =~ /(FIXME|REVISIT|TODO)/ }
+      end
+    end
+  end
+end
diff --git a/spec/unit/face/module/search_spec.rb b/spec/unit/face/module/search_spec.rb
new file mode 100644
index 0000000..250c5e0
--- /dev/null
+++ b/spec/unit/face/module/search_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+require 'puppet/face'
+
+describe "puppet module search" do
+  subject { Puppet::Face[:module, :current] }
+
+  let(:options) do
+    {}
+  end
+
+  describe "option validation" do
+    context "without any options" do
+      it "should require a search term" do
+        pattern = /wrong number of arguments/
+        expect { subject.search }.to raise_error ArgumentError, pattern
+      end
+    end
+
+    it "should accept the --module-repository option" do
+      options[:module_repository] = "http://forge.example.com"
+      Puppet::Module::Tool::Applications::Searcher.expects(:run).with("puppetlabs-apache", options).once
+      subject.search("puppetlabs-apache", options)
+    end
+  end
+
+  describe "inline documentation" do
+    subject { Puppet::Face[:module, :current].get_action :search }
+
+    its(:summary)     { should =~ /search.*module/im }
+    its(:description) { should =~ /search.*module/im }
+    its(:returns)     { should =~ /array/i }
+    its(:examples)    { should_not be_empty }
+
+    %w{ license copyright summary description returns examples }.each do |doc|
+      context "of the" do
+        its(doc.to_sym) { should_not =~ /(FIXME|REVISIT|TODO)/ }
+      end
+    end
+  end
+end
diff --git a/spec/unit/face/module_spec.rb b/spec/unit/face/module_spec.rb
new file mode 100644
index 0000000..33e486e
--- /dev/null
+++ b/spec/unit/face/module_spec.rb
@@ -0,0 +1,3 @@
+# For face related tests, look in the spec/unit/faces/module folder.
+# For integration tests, which test the behavior of module, look in the
+# spec/unit/integration folder.
diff --git a/spec/unit/file_serving/metadata_spec.rb b/spec/unit/file_serving/metadata_spec.rb
index 3842b05..c0bd6f0 100755
--- a/spec/unit/file_serving/metadata_spec.rb
+++ b/spec/unit/file_serving/metadata_spec.rb
@@ -117,10 +117,6 @@
           FileUtils.touch(path)
         end
 
-        it "should be able to produce xmlrpc-style attribute information" do
-          metadata.should respond_to(:attributes_with_tabs)
-        end
-
         it "should set the owner to the file's current owner" do
           metadata.owner.should == owner
         end
@@ -153,12 +149,6 @@
             metadata.collect
             metadata.checksum.should == "{mtime}#{@time}"
           end
-
-          it "should produce tab-separated mode, type, owner, group, and checksum for xmlrpc" do
-            set_mode(0755, path)
-
-            metadata.attributes_with_tabs.should == "#{0755.to_s}\tfile\t#{owner}\t#{group}\t{md5}#{checksum}"
-          end
         end
       end
 
@@ -181,13 +171,6 @@
           metadata.collect
           metadata.checksum.should == "{ctime}#{time}"
         end
-
-        it "should produce tab-separated mode, type, owner, group, and checksum for xmlrpc" do
-          set_mode(0755, path)
-          metadata.collect
-
-          metadata.attributes_with_tabs.should == "#{0755.to_s}\tdirectory\t#{owner}\t#{group}\t{ctime}#{time.to_s}"
-        end
       end
 
       describe "when managing links", :unless => Puppet.features.microsoft_windows? do
@@ -207,15 +190,6 @@
         it "should read links instead of returning their checksums" do
           metadata.destination.should == target
         end
-
-        pending "should produce tab-separated mode, type, owner, group, and destination for xmlrpc" do
-          # "We'd like this to be true, but we need to always collect the checksum because in the server/client/server round trip we lose the distintion between manage and follow."
-          metadata.attributes_with_tabs.should == "#{0755}\tlink\t#{owner}\t#{group}\t#{target}"
-        end
-
-        it "should produce tab-separated mode, type, owner, group, checksum, and destination for xmlrpc" do
-          metadata.attributes_with_tabs.should == "#{fmode}\tlink\t#{owner}\t#{group}\t{md5}eb9c2bf0eb63f3a7bc0ea37ef18aeba5\t#{target}"
-        end
       end
     end
 
diff --git a/spec/unit/indirector/catalog/active_record_spec.rb b/spec/unit/indirector/catalog/active_record_spec.rb
index 35d0117..f9062de 100755
--- a/spec/unit/indirector/catalog/active_record_spec.rb
+++ b/spec/unit/indirector/catalog/active_record_spec.rb
@@ -39,56 +39,11 @@ class Host < Tableless
   end
 
   describe "when finding an instance" do
-    before do
-      @request = stub 'request', :key => "foo", :options => {:cache_integration_hack => true}
-    end
-
-    # This hack is here because we don't want to look in the db unless we actually want
-    # to look in the db, but our indirection architecture in 0.24.x isn't flexible
-    # enough to tune that via configuration.
-    it "should return nil unless ':cache_integration_hack' is set to true" do
-      @request.options[:cache_integration_hack] = false
-      Puppet::Rails::Host.expects(:find_by_name).never
-      @terminus.find(@request).should be_nil
-    end
-
-    it "should use the Hosts ActiveRecord class to find the host" do
-      Puppet::Rails::Host.expects(:find_by_name).with { |key, args| key == "foo" }
-      @terminus.find(@request)
+    it "should return nil" do
+      request = stub 'request', :key => "foo"
+      @terminus.find(request).should be_nil
     end
 
-    it "should return nil if no host instance can be found" do
-      Puppet::Rails::Host.expects(:find_by_name).returns nil
-
-      @terminus.find(@request).should be_nil
-    end
-
-    it "should return a catalog with the same name as the host if the host can be found" do
-      host = stub 'host', :name => "foo", :resources => []
-      Puppet::Rails::Host.expects(:find_by_name).returns host
-
-      result = @terminus.find(@request)
-      result.should be_instance_of(Puppet::Resource::Catalog)
-      result.name.should == "foo"
-    end
-
-    it "should set each of the host's resources as a transportable resource within the catalog" do
-      host = stub 'host', :name => "foo"
-      Puppet::Rails::Host.expects(:find_by_name).returns host
-
-      res1 = mock 'res1', :to_transportable => "trans_res1"
-      res2 = mock 'res2', :to_transportable => "trans_res2"
-
-      host.expects(:resources).returns [res1, res2]
-
-      catalog = stub 'catalog'
-      Puppet::Resource::Catalog.expects(:new).returns catalog
-
-      catalog.expects(:add_resource).with "trans_res1"
-      catalog.expects(:add_resource).with "trans_res2"
-
-      @terminus.find(@request)
-    end
   end
 
   describe "when saving an instance" do
diff --git a/spec/unit/indirector/certificate/rest_spec.rb b/spec/unit/indirector/certificate/rest_spec.rb
index 870d9e4..4ec475b 100755
--- a/spec/unit/indirector/certificate/rest_spec.rb
+++ b/spec/unit/indirector/certificate/rest_spec.rb
@@ -20,6 +20,10 @@
     Puppet::SSL::Certificate::Rest.port_setting.should == :ca_port
   end
 
+  it "should use the :ca SRV service" do
+    Puppet::SSL::Certificate::Rest.srv_service.should == :ca
+  end
+
   it "should make sure found certificates have their names set to the search string" do
     terminus = Puppet::SSL::Certificate::Rest.new
 
diff --git a/spec/unit/indirector/facts/inventory_active_record_spec.rb b/spec/unit/indirector/facts/inventory_active_record_spec.rb
index 88e5e53..43dcc7c 100755
--- a/spec/unit/indirector/facts/inventory_active_record_spec.rb
+++ b/spec/unit/indirector/facts/inventory_active_record_spec.rb
@@ -38,10 +38,22 @@
   end
 
   describe "#save" do
+    let(:node) {
+      Puppet::Rails::InventoryNode.new(:name => "foo", :timestamp => Time.now)
+    }
+
+    let(:facts) {
+      Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin")
+    }
+
+    it "should retry on ActiveRecord error" do
+      Puppet::Rails::InventoryNode.expects(:create).twice.raises(ActiveRecord::StatementInvalid).returns node
+
+      Puppet::Node::Facts.indirection.save(facts)
+    end
+
     it "should use an existing node if possible" do
-      node = Puppet::Rails::InventoryNode.new(:name => "foo", :timestamp => Time.now)
       node.save
-      facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin")
       Puppet::Node::Facts.indirection.save(facts)
 
       Puppet::Rails::InventoryNode.count.should == 1
@@ -52,7 +64,6 @@
       # This test isn't valid if there are nodes to begin with
       Puppet::Rails::InventoryNode.count.should == 0
 
-      facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin")
       Puppet::Node::Facts.indirection.save(facts)
 
       Puppet::Rails::InventoryNode.count.should == 1
@@ -60,7 +71,6 @@
     end
 
     it "should save the facts" do
-      facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin")
       Puppet::Node::Facts.indirection.save(facts)
 
       Puppet::Rails::InventoryFact.all.map{|f| [f.name,f.value]}.should =~ [["uptime_days","60"],["kernel","Darwin"]]
diff --git a/spec/unit/indirector/facts/inventory_service_spec.rb b/spec/unit/indirector/facts/inventory_service_spec.rb
index f44934a..8cce8b3 100644
--- a/spec/unit/indirector/facts/inventory_service_spec.rb
+++ b/spec/unit/indirector/facts/inventory_service_spec.rb
@@ -19,4 +19,3 @@
     }.should_not raise_error
   end
 end
-
diff --git a/spec/unit/indirector/file_content/rest_spec.rb b/spec/unit/indirector/file_content/rest_spec.rb
index 06ad16e..99925a8 100755
--- a/spec/unit/indirector/file_content/rest_spec.rb
+++ b/spec/unit/indirector/file_content/rest_spec.rb
@@ -1,10 +1,14 @@
 #!/usr/bin/env rspec
 require 'spec_helper'
 
-require 'puppet/indirector/file_content'
+require 'puppet/indirector/file_content/rest'
 
-describe "Puppet::Indirector::Content::Rest" do
+describe Puppet::Indirector::FileContent::Rest do
   it "should add the node's cert name to the arguments"
 
   it "should set the content type to text/plain"
+
+  it "should use the :fileserver SRV service" do
+    Puppet::Indirector::FileContent::Rest.srv_service.should == :fileserver
+  end
 end
diff --git a/spec/unit/indirector/instrumentation_data/local_spec.rb b/spec/unit/indirector/instrumentation_data/local_spec.rb
new file mode 100644
index 0000000..45ca1e0
--- /dev/null
+++ b/spec/unit/indirector/instrumentation_data/local_spec.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/instrumentation/listener'
+require 'puppet/indirector/instrumentation_data/local'
+
+describe Puppet::Indirector::InstrumentationData::Local do
+  it "should be a subclass of the Code terminus" do
+    Puppet::Indirector::InstrumentationData::Local.superclass.should equal(Puppet::Indirector::Code)
+  end
+
+  it "should be registered with the configuration store indirection" do
+    indirection = Puppet::Indirector::Indirection.instance(:instrumentation_data)
+    Puppet::Indirector::InstrumentationData::Local.indirection.should equal(indirection)
+  end
+
+  it "should have its name set to :local" do
+    Puppet::Indirector::InstrumentationData::Local.name.should == :local
+  end
+end
+
+describe Puppet::Indirector::InstrumentationData::Local do
+  before :each do
+    Puppet::Util::Instrumentation.stubs(:listener)
+    @data = Puppet::Indirector::InstrumentationData::Local.new
+    @name = "me"
+    @request = stub 'request', :key => @name
+  end
+
+  describe "when finding instrumentation data" do
+    it "should return a Instrumentation Data instance matching the key" do
+    end
+  end
+
+  describe "when searching listeners" do
+    it "should raise an error" do
+      lambda { @data.search(@request) }.should raise_error(Puppet::DevError)
+    end
+  end
+
+  describe "when saving listeners" do
+    it "should raise an error" do
+      lambda { @data.save(@request) }.should raise_error(Puppet::DevError)
+    end
+  end
+
+  describe "when destroying listeners" do
+    it "should raise an error" do
+      lambda { @data.destroy(@reques) }.should raise_error(Puppet::DevError)
+    end
+  end
+end
diff --git a/spec/unit/indirector/instrumentation_data/rest_spec.rb b/spec/unit/indirector/instrumentation_data/rest_spec.rb
new file mode 100644
index 0000000..762667e
--- /dev/null
+++ b/spec/unit/indirector/instrumentation_data/rest_spec.rb
@@ -0,0 +1,11 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/instrumentation/data'
+require 'puppet/indirector/instrumentation_data/rest'
+
+describe Puppet::Indirector::InstrumentationData::Rest do
+  it "should be a subclass of Puppet::Indirector::REST" do
+    Puppet::Indirector::InstrumentationData::Rest.superclass.should equal(Puppet::Indirector::REST)
+  end
+end
diff --git a/spec/unit/indirector/instrumentation_listener/local_spec.rb b/spec/unit/indirector/instrumentation_listener/local_spec.rb
new file mode 100644
index 0000000..b251736
--- /dev/null
+++ b/spec/unit/indirector/instrumentation_listener/local_spec.rb
@@ -0,0 +1,65 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/instrumentation/listener'
+require 'puppet/indirector/instrumentation_listener/local'
+
+describe Puppet::Indirector::InstrumentationListener::Local do
+  it "should be a subclass of the Code terminus" do
+    Puppet::Indirector::InstrumentationListener::Local.superclass.should equal(Puppet::Indirector::Code)
+  end
+
+  it "should be registered with the configuration store indirection" do
+    indirection = Puppet::Indirector::Indirection.instance(:instrumentation_listener)
+    Puppet::Indirector::InstrumentationListener::Local.indirection.should equal(indirection)
+  end
+
+  it "should have its name set to :local" do
+    Puppet::Indirector::InstrumentationListener::Local.name.should == :local
+  end
+end
+
+describe Puppet::Indirector::InstrumentationListener::Local do
+  before :each do
+    Puppet::Util::Instrumentation.stubs(:listener)
+    @listener = Puppet::Indirector::InstrumentationListener::Local.new
+    @name = "me"
+    @request = stub 'request', :key => @name
+  end
+
+  describe "when finding listeners" do
+    it "should return a Instrumentation Listener instance matching the key" do
+      Puppet::Util::Instrumentation.expects(:[]).with("me").returns(:instance)
+      @listener.find(@request).should == :instance
+    end
+  end
+
+  describe "when searching listeners" do
+    it "should return a list of all loaded Instrumentation Listenesrs irregardless of the given key" do
+      Puppet::Util::Instrumentation.expects(:listeners).returns([:instance1, :instance2])
+      @listener.search(@request).should == [:instance1, :instance2]
+    end
+  end
+
+  describe "when saving listeners" do
+    it "should set the new listener to the global listener list" do
+      newlistener = stub 'listener', :name => @name
+      @request.stubs(:instance).returns(newlistener)
+      Puppet::Util::Instrumentation.expects(:[]=).with("me", newlistener)
+      @listener.save(@request)
+    end
+  end
+
+  describe "when destroying listeners" do
+    it "should raise an error if listener wasn't subscribed" do
+      Puppet::Util::Instrumentation.expects(:[]).with("me").returns(nil)
+      lambda { @listener.destroy(@request) }.should raise_error
+    end
+
+    it "should unsubscribe the listener" do
+      Puppet::Util::Instrumentation.expects(:[]).with("me").returns(:instancce)
+      Puppet::Util::Instrumentation.expects(:unsubscribe).with(:instancce)
+      @listener.destroy(@request)
+    end
+  end
+end
diff --git a/spec/unit/indirector/instrumentation_listener/rest_spec.rb b/spec/unit/indirector/instrumentation_listener/rest_spec.rb
new file mode 100644
index 0000000..6355a1c
--- /dev/null
+++ b/spec/unit/indirector/instrumentation_listener/rest_spec.rb
@@ -0,0 +1,11 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/instrumentation/listener'
+require 'puppet/indirector/instrumentation_listener/rest'
+
+describe Puppet::Indirector::InstrumentationListener::Rest do
+  it "should be a subclass of Puppet::Indirector::REST" do
+    Puppet::Indirector::InstrumentationListener::Rest.superclass.should equal(Puppet::Indirector::REST)
+  end
+end
diff --git a/spec/unit/indirector/instrumentation_probe/local_spec.rb b/spec/unit/indirector/instrumentation_probe/local_spec.rb
new file mode 100644
index 0000000..40d64dc
--- /dev/null
+++ b/spec/unit/indirector/instrumentation_probe/local_spec.rb
@@ -0,0 +1,65 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/instrumentation/indirection_probe'
+require 'puppet/indirector/instrumentation_probe/local'
+require 'puppet/util/instrumentation/instrumentable'
+
+describe Puppet::Indirector::InstrumentationProbe::Local do
+  it "should be a subclass of the Code terminus" do
+    Puppet::Indirector::InstrumentationProbe::Local.superclass.should equal(Puppet::Indirector::Code)
+  end
+
+  it "should be registered with the configuration store indirection" do
+    indirection = Puppet::Indirector::Indirection.instance(:instrumentation_probe)
+    Puppet::Indirector::InstrumentationProbe::Local.indirection.should equal(indirection)
+  end
+
+  it "should have its name set to :local" do
+    Puppet::Indirector::InstrumentationProbe::Local.name.should == :local
+  end
+end
+
+describe Puppet::Indirector::InstrumentationProbe::Local do
+  before :each do
+    Puppet::Util::Instrumentation.stubs(:listener)
+    @probe = Puppet::Indirector::InstrumentationProbe::Local.new
+    @name = "me"
+    @request = stub 'request', :key => @name
+  end
+
+  describe "when finding probes" do
+    it "should do nothing" do
+      @probe.find(@request).should be_nil
+    end
+  end
+
+  describe "when searching probes" do
+    it "should return a list of all loaded probes irregardless of the given key" do
+      instance1 = stub 'instance1', :method => "probe1", :klass => "Klass1"
+      instance2 = stub 'instance2', :method => "probe2", :klass => "Klass2"
+      Puppet::Util::Instrumentation::IndirectionProbe.expects(:new).with("Klass1.probe1").returns(:instance1)
+      Puppet::Util::Instrumentation::IndirectionProbe.expects(:new).with("Klass2.probe2").returns(:instance2)
+      Puppet::Util::Instrumentation::Instrumentable.expects(:each_probe).multiple_yields([instance1], [instance2])
+      @probe.search(@request).should == [ :instance1, :instance2 ]
+    end
+  end
+
+  describe "when saving probes" do
+    it "should enable probes" do
+      newprobe = stub 'probe', :name => @name
+      @request.stubs(:instance).returns(newprobe)
+      Puppet::Util::Instrumentation::Instrumentable.expects(:enable_probes)
+      @probe.save(@request)
+    end
+  end
+
+  describe "when destroying probes" do
+    it "should disable probes" do
+      newprobe = stub 'probe', :name => @name
+      @request.stubs(:instance).returns(newprobe)
+      Puppet::Util::Instrumentation::Instrumentable.expects(:disable_probes)
+      @probe.destroy(@request)
+    end
+  end
+end
diff --git a/spec/unit/indirector/instrumentation_probe/rest_spec.rb b/spec/unit/indirector/instrumentation_probe/rest_spec.rb
new file mode 100644
index 0000000..0b73fbd
--- /dev/null
+++ b/spec/unit/indirector/instrumentation_probe/rest_spec.rb
@@ -0,0 +1,11 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/instrumentation/indirection_probe'
+require 'puppet/indirector/instrumentation_probe/rest'
+
+describe Puppet::Indirector::InstrumentationProbe::Rest do
+  it "should be a subclass of Puppet::Indirector::REST" do
+    Puppet::Indirector::InstrumentationProbe::Rest.superclass.should equal(Puppet::Indirector::REST)
+  end
+end
diff --git a/spec/unit/indirector/report/rest_spec.rb b/spec/unit/indirector/report/rest_spec.rb
index 806ae6e..8e969ab 100755
--- a/spec/unit/indirector/report/rest_spec.rb
+++ b/spec/unit/indirector/report/rest_spec.rb
@@ -24,4 +24,8 @@
     Puppet::Transaction::Report::Rest.server.should_not be_nil
     Puppet::Transaction::Report::Rest.port.should_not be_nil
   end
+
+  it "should use the :report SRV service" do
+    Puppet::Transaction::Report::Rest.srv_service.should == :report
+  end
 end
diff --git a/spec/unit/indirector/request_spec.rb b/spec/unit/indirector/request_spec.rb
index d330248..bc6b599 100755
--- a/spec/unit/indirector/request_spec.rb
+++ b/spec/unit/indirector/request_spec.rb
@@ -2,8 +2,16 @@
 require 'spec_helper'
 require 'matchers/json'
 require 'puppet/indirector/request'
+require 'puppet/util/pson'
 
 describe Puppet::Indirector::Request do
+
+  describe "when registering the document type" do
+    it "should register its document type with JSON" do
+      PSON.registered_document_types["IndirectorRequest"].should equal(Puppet::Indirector::Request)
+    end
+  end
+
   describe "when initializing" do
     it "should require an indirection name, a key, and a method" do
       lambda { Puppet::Indirector::Request.new }.should raise_error(ArgumentError)
@@ -311,4 +319,199 @@
       lambda { @request.query_string }.should raise_error(ArgumentError)
     end
   end
+
+  describe "when converting to json" do
+    before do
+      @request = Puppet::Indirector::Request.new(:facts, :find, "foo")
+    end
+
+    it "should produce a hash with the document_type set to 'request'" do
+      @request.should set_json_document_type_to("IndirectorRequest")
+    end
+
+    it "should set the 'key'" do
+      @request.should set_json_attribute("key").to("foo")
+    end
+
+    it "should include an attribute for its indirection name" do
+      @request.should set_json_attribute("type").to("facts")
+    end
+
+    it "should include a 'method' attribute set to its method" do
+      @request.should set_json_attribute("method").to("find")
+    end
+
+    it "should add all attributes under the 'attributes' attribute" do
+      @request.ip = "127.0.0.1"
+      @request.should set_json_attribute("attributes", "ip").to("127.0.0.1")
+    end
+
+    it "should add all options under the 'attributes' attribute" do
+      @request.options["opt"] = "value"
+      PSON.parse(@request.to_pson)["data"]['attributes']['opt'].should == "value"
+    end
+
+    it "should include the instance if provided" do
+      facts = Puppet::Node::Facts.new("foo")
+      @request.instance = facts
+      PSON.parse(@request.to_pson)["data"]['instance'].should be_instance_of(Hash)
+    end
+  end
+
+  describe "when converting from json" do
+    before do
+      @request = Puppet::Indirector::Request.new(:facts, :find, "foo")
+      @klass = Puppet::Indirector::Request
+      @format = Puppet::Network::FormatHandler.format('pson')
+    end
+
+    def from_json(json)
+      @format.intern(Puppet::Indirector::Request, json)
+    end
+
+    it "should set the 'key'" do
+      from_json(@request.to_pson).key.should == "foo"
+    end
+
+    it "should fail if no key is provided" do
+      json = PSON.parse(@request.to_pson)
+      json['data'].delete("key")
+      lambda { from_json(json.to_pson) }.should raise_error(ArgumentError)
+    end
+
+    it "should set its indirector name" do
+      from_json(@request.to_pson).indirection_name.should == :facts
+    end
+
+    it "should fail if no type is provided" do
+      json = PSON.parse(@request.to_pson)
+      json['data'].delete("type")
+      lambda { from_json(json.to_pson) }.should raise_error(ArgumentError)
+    end
+
+    it "should set its method" do
+      from_json(@request.to_pson).method.should == "find"
+    end
+
+    it "should fail if no method is provided" do
+      json = PSON.parse(@request.to_pson)
+      json['data'].delete("method")
+      lambda { from_json(json.to_pson) }.should raise_error(ArgumentError)
+    end
+
+    it "should initialize with all attributes and options" do
+      @request.ip = "127.0.0.1"
+      @request.options["opt"] = "value"
+      result = from_json(@request.to_pson)
+      result.options[:opt].should == "value"
+      result.ip.should == "127.0.0.1"
+    end
+
+    it "should set its instance as an instance if one is provided" do
+      facts = Puppet::Node::Facts.new("foo")
+      @request.instance = facts
+      result = from_json(@request.to_pson)
+      result.instance.should be_instance_of(Puppet::Node::Facts)
+    end
+  end
+
+  context '#do_request' do
+    before :each do
+      @request = Puppet::Indirector::Request.new(:myind, :find, "my key")
+    end
+
+    context 'when not using SRV records' do
+      before :each do
+        Puppet.settings[:use_srv_records] = false
+      end
+
+      it "yields the request with the default server and port when no server or port were specified on the original request" do
+        count = 0
+        rval = @request.do_request(:puppet, 'puppet.example.com', '90210') do |got|
+          count += 1
+          got.server.should == 'puppet.example.com'
+          got.port.should   == '90210'
+          'Block return value'
+        end
+        count.should == 1
+
+        rval.should == 'Block return value'
+      end
+    end
+
+    context 'when using SRV records' do
+      before :each do
+        Puppet.settings[:use_srv_records] = true
+        Puppet.settings[:srv_domain]      = 'example.com'
+      end
+
+      it "yields the request with the original server and port unmodified" do
+        @request.server = 'puppet.example.com'
+        @request.port   = '90210'
+
+        count = 0
+        rval = @request.do_request do |got|
+          count += 1
+          got.server.should == 'puppet.example.com'
+          got.port.should   == '90210'
+          'Block return value'
+        end
+        count.should == 1
+
+        rval.should == 'Block return value'
+      end
+
+      context "when SRV returns servers" do
+        before :each do
+          @dns_mock = mock('dns')
+          Resolv::DNS.expects(:new).returns(@dns_mock)
+
+          @port = 7205
+          @host = '_x-puppet._tcp.example.com'
+          @srv_records = [Resolv::DNS::Resource::IN::SRV.new(0, 0, @port, @host)]
+
+          @dns_mock.expects(:getresources).
+            with("_x-puppet._tcp.#{Puppet.settings[:srv_domain]}", Resolv::DNS::Resource::IN::SRV).
+            returns(@srv_records)
+        end
+
+        it "yields a request using the server and port from the SRV record" do
+          count = 0
+          rval = @request.do_request do |got|
+            count += 1
+            got.server.should == '_x-puppet._tcp.example.com'
+            got.port.should == 7205
+
+            @block_return
+          end
+          count.should == 1
+
+          rval.should == @block_return
+        end
+
+        it "should fall back to the default server when the block raises a SystemCallError" do
+          count = 0
+          second_pass = nil
+
+          rval = @request.do_request(:puppet, 'puppet', 8140) do |got|
+            count += 1
+
+            if got.server == '_x-puppet._tcp.example.com' then
+              raise SystemCallError, "example failure"
+            else
+              second_pass = got
+            end
+
+            @block_return
+          end
+
+          second_pass.server.should == 'puppet'
+          second_pass.port.should   == 8140
+          count.should == 2
+
+          rval.should == @block_return
+        end
+      end
+    end
+  end
 end
diff --git a/spec/unit/indirector/rest_spec.rb b/spec/unit/indirector/rest_spec.rb
index f18e99a..e664ef2 100755
--- a/spec/unit/indirector/rest_spec.rb
+++ b/spec/unit/indirector/rest_spec.rb
@@ -137,6 +137,10 @@ module Test
     end
   end
 
+  it 'should default to :puppet for the srv_service' do
+    Puppet::Indirector::REST.srv_service.should == :puppet
+  end
+
   describe "when deserializing responses" do
     it "should return nil if the response code is 404" do
       response = mock 'response'
@@ -564,4 +568,25 @@ module Test
       lambda { @searcher.save(@request) }.should raise_error(ArgumentError)
     end
   end
+
+  context 'dealing with SRV settings' do
+    [
+      :destroy,
+      :find,
+      :head,
+      :save,
+      :search
+    ].each do |method|
+      it "##{method} passes the SRV service, and fall-back server & port to the request's do_request method" do
+        request = Puppet::Indirector::Request.new(:indirection, method, 'key')
+        stub_response = stub 'response'
+        stub_response.stubs(:code).returns('200')
+        @searcher.stubs(:deserialize)
+
+        request.expects(:do_request).with(@searcher.class.srv_service, @searcher.class.server, @searcher.class.port).returns(stub_response)
+
+        @searcher.send(method, request)
+      end
+    end
+  end
 end
diff --git a/spec/unit/module_spec.rb b/spec/unit/module_spec.rb
index a0f64c6..cf72084 100755
--- a/spec/unit/module_spec.rb
+++ b/spec/unit/module_spec.rb
@@ -371,19 +371,11 @@
     end
   end
 
-  %w{plugins files}.each do |filetype|
-    short = filetype.sub(/s$/, '')
-    dirname = filetype == "plugins" ? "lib" : filetype.to_s
-    it "should be able to return the #{short} directory" do
-      Puppet::Module.new("foo").should respond_to(short + "_directory")
-    end
-
-    it "should return the path to the #{short} directory" do
-      mod = Puppet::Module.new("foo")
-      mod.stubs(:path).returns "/a/foo"
+  it "should return the path to the plugin directory" do
+    mod = Puppet::Module.new("foo")
+    mod.stubs(:path).returns "/a/foo"
 
-      mod.send(short + "_directory").should == "/a/foo/#{dirname}"
-    end
+    mod.plugin_directory.should == "/a/foo/lib"
   end
 
   it "should throw a warning if plugins are in a 'plugins' directory rather than a 'lib' directory" do
diff --git a/spec/unit/module_tool/application_spec.rb b/spec/unit/module_tool/application_spec.rb
new file mode 100644
index 0000000..22d3632
--- /dev/null
+++ b/spec/unit/module_tool/application_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+require 'puppet/module_tool'
+
+describe Puppet::Module::Tool::Applications::Application do
+  describe 'app' do
+
+    good_versions = %w{ 1.2.4 0.0.1 0.0.0 0.0.2git-8-g3d316d1 0.0.3b1 10.100.10000
+                         0.1.2rc1 0.1.2dev-1 0.1.2svn12345 }
+    bad_versions = %w{ 0.1.2-3 0.1 0 0.1.2.3 dev }
+
+    before do
+      @app = Class.new(described_class).new
+    end
+
+    good_versions.each do |ver|
+      it "should accept version string #{ver}" do
+        @app.instance_eval("@filename=%q{puppetlabs-ntp-#{ver}}")
+        @app.parse_filename!
+      end
+    end
+
+    bad_versions.each do |ver|
+      it "should not accept version string #{ver}" do
+        @app.instance_eval("@filename=%q{puppetlabs-ntp-#{ver}}")
+        lambda { @app.parse_filename! }.should raise_error
+      end
+    end
+  end
+end
diff --git a/spec/unit/module_tool/metadata_spec.rb b/spec/unit/module_tool/metadata_spec.rb
new file mode 100644
index 0000000..85d743f
--- /dev/null
+++ b/spec/unit/module_tool/metadata_spec.rb
@@ -0,0 +1,11 @@
+require 'spec_helper'
+require 'puppet/module_tool'
+
+describe Puppet::Module::Tool::Metadata do
+  context "when using default values" do
+    it "should set license to 'Apache License, Version 2.0'" do
+      metadata = Puppet::Module::Tool::Metadata.new
+      metadata.license.should == "Apache License, Version 2.0"
+    end
+  end
+end
diff --git a/spec/unit/module_tool/repository_spec.rb b/spec/unit/module_tool/repository_spec.rb
new file mode 100644
index 0000000..69be166
--- /dev/null
+++ b/spec/unit/module_tool/repository_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+require 'net/http'
+require 'puppet/module_tool'
+
+describe Puppet::Module::Tool::Repository do
+  describe 'instances' do
+    before do
+      @repository = described_class.new('http://fake.com')
+    end
+
+    describe '#make_http_request' do
+      before do
+        # Do a mock of the Proxy call so we can do proper expects for
+        # Net::HTTP
+        Net::HTTP.expects(:Proxy).returns(Net::HTTP)
+        Net::HTTP.expects(:start)
+      end
+      context "when not given an :authenticate option" do
+        it "should authenticate" do
+          @repository.expects(:authenticate).never
+          @repository.make_http_request(nil)
+        end
+      end
+      context "when given an :authenticate option" do
+        it "should authenticate" do
+          @repository.expects(:authenticate)
+          @repository.make_http_request(nil, :authenticate => true)
+        end
+      end
+    end
+
+    describe '#authenticate' do
+      it "should set basic auth on the request" do
+        authenticated_request = stub
+        authenticated_request.expects(:basic_auth)
+        @repository.expects(:prompt).twice
+        @repository.authenticate(authenticated_request)
+      end
+    end
+
+    describe '#retrieve' do
+      before do
+        @uri = URI.parse('http://some.url.com')
+      end
+
+      it "should access the cache" do
+        @repository.cache.expects(:retrieve).with(@uri)
+        @repository.retrieve(@uri)
+      end
+    end
+  end
+end
diff --git a/spec/unit/module_tool_spec.rb b/spec/unit/module_tool_spec.rb
new file mode 100644
index 0000000..15ca6c7
--- /dev/null
+++ b/spec/unit/module_tool_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+require 'puppet/module_tool'
+
+describe Puppet::Module::Tool do
+  describe 'http_proxy support' do
+    before :each do
+      ENV["http_proxy"] = nil
+    end
+
+    after :each do
+      ENV["http_proxy"] = nil
+    end
+
+    it "should support environment variable for port and host" do
+      ENV["http_proxy"] = "http://test.com:8011"
+      described_class.http_proxy_host.should == "test.com"
+      described_class.http_proxy_port.should == 8011
+    end
+
+    it "should support puppet configuration for port and host" do
+      ENV["http_proxy"] = nil
+      Puppet.settings.stubs(:[]).with(:http_proxy_host).returns('test.com')
+      Puppet.settings.stubs(:[]).with(:http_proxy_port).returns(7456)
+
+      described_class.http_proxy_port.should == 7456
+      described_class.http_proxy_host.should == "test.com"
+    end
+
+    it "should use environment variable before puppet settings" do
+      ENV["http_proxy"] = "http://test1.com:8011"
+      Puppet.settings.stubs(:[]).with(:http_proxy_host).returns('test2.com')
+      Puppet.settings.stubs(:[]).with(:http_proxy_port).returns(7456)
+
+      described_class.http_proxy_host.should == "test1.com"
+      described_class.http_proxy_port.should == 8011
+    end
+  end
+end
diff --git a/spec/unit/network/handler/ca_spec.rb b/spec/unit/network/handler/ca_spec.rb
deleted file mode 100644
index 43aa5a7..0000000
--- a/spec/unit/network/handler/ca_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-require 'spec_helper'
-
-require 'puppet/network/handler/ca'
-
-describe Puppet::Network::Handler::CA, :unless => Puppet.features.microsoft_windows? do
-  include PuppetSpec::Files
-
-  describe "#getcert" do
-    let(:host)      { "testhost" }
-    let(:x509_name) { OpenSSL::X509::Name.new [['CN', host]] }
-    let(:key)       { Puppet::SSL::Key.new(host).generate }
-
-    let(:csr) do
-      csr = OpenSSL::X509::Request.new
-      csr.subject = x509_name
-      csr.public_key = key.public_key
-      csr
-    end
-
-    let(:ca)     { Puppet::SSL::CertificateAuthority.new }
-    let(:cacert) { ca.instance_variable_get(:@certificate) }
-
-    before :each do
-      Puppet[:confdir] = tmpdir('conf')
-
-      Puppet::SSL::CertificateAuthority.stubs(:ca?).returns true
-      Puppet::SSL::CertificateAuthority.stubs(:singleton_instance).returns ca
-    end
-
-    it "should do nothing if the master is not a CA" do
-      Puppet::SSL::CertificateAuthority.stubs(:ca?).returns false
-
-      csr = OpenSSL::X509::Request.new
-      subject.getcert(csr.to_pem).should == ''
-    end
-
-    describe "when a certificate already exists for the host" do
-      let!(:cert)    { ca.generate(host) }
-
-      it "should return the existing cert if it matches the public key of the CSR" do
-        csr.public_key = cert.content.public_key
-
-        subject.getcert(csr.to_pem).should == [cert.to_s, cacert.to_s]
-      end
-
-      it "should fail if the public key of the CSR does not match the existing cert" do
-        expect do
-          subject.getcert(csr.to_pem)
-        end.to raise_error(Puppet::Error, /Certificate request does not match existing certificate/)
-      end
-    end
-
-    describe "when autosign is enabled" do
-      before :each do
-        Puppet[:autosign] = true
-      end
-
-      it "should return the new cert and the CA cert" do
-        cert_str, cacert_str = subject.getcert(csr.to_pem)
-
-        returned_cert = Puppet::SSL::Certificate.from_s(cert_str)
-        returned_cacert = Puppet::SSL::Certificate.from_s(cacert_str)
-
-        returned_cert.name.should == host
-        returned_cacert.content.subject.cmp(cacert.content.subject).should == 0
-      end
-    end
-
-    describe "when autosign is disabled" do
-      before :each do
-        Puppet[:autosign] = false
-      end
-
-      it "should save the CSR without signing it" do
-        subject.getcert(csr.to_pem)
-
-        Puppet::SSL::Certificate.indirection.find(host).should be_nil
-        Puppet::SSL::CertificateRequest.indirection.find(host).should be_a(Puppet::SSL::CertificateRequest)
-      end
-
-      it "should not return a cert" do
-        subject.getcert(csr.to_pem).should be_nil
-      end
-    end
-  end
-end
diff --git a/spec/unit/network/handler/fileserver_spec.rb b/spec/unit/network/handler/fileserver_spec.rb
deleted file mode 100755
index 2b8094b..0000000
--- a/spec/unit/network/handler/fileserver_spec.rb
+++ /dev/null
@@ -1,201 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-
-require 'puppet/network/handler/fileserver'
-
-describe Puppet::Network::Handler::FileServer do
-  include PuppetSpec::Files
-
-  def create_file(filename)
-    File.open(filename, "w") { |f| f.puts filename}
-  end
-
-  def create_nested_file
-    dirname = File.join(@basedir, "nested_dir")
-    Dir.mkdir(dirname)
-    file = File.join(dirname, "nested_dir_file")
-    create_file(file)
-  end
-
-  before do
-    @basedir = tmpdir("test_network_handler")
-    @file = File.join(@basedir, "aFile")
-    @link = File.join(@basedir, "aLink")
-    create_file(@file)
-    @mount = Puppet::Network::Handler::FileServer::Mount.new("some_path", @basedir)
-  end
-
-  describe "when parsing the fileserver.conf" do
-    it "should create a valid mount when a valid conf is read" do
-      config_file = tmpfile('fileserver.conf')
-      mountdir = tmpdir('mountdir')
-
-      conf_text = <<-HEREDOC
-        [mymount]
-          path #{mountdir}
-          allow anyone.com
-          deny nobody.com
-      HEREDOC
-      File.open(config_file, 'w') { |f| f.write conf_text }
-
-      fs = Puppet::Network::Handler::FileServer.new(:Config => config_file) 
-      mounts = fs.instance_variable_get(:@mounts)
-      mount = mounts["mymount"]
-      mount.path == mountdir
-      mount.instance_variable_get(:@declarations).map {|d| d.pattern}.should =~ [["com", "nobody"], ["com", "anyone"]]
-    end
-
-    ['path', 'allow', 'deny'].each do |arg|
-      it "should error if config file doesn't specify a mount for #{arg} argument" do
-        config_file = tmpfile('fileserver.conf')
-        File.open(config_file, 'w') { |f| f.puts "#{arg} 127.0.0.1/24" }
-
-        expect { 
-          Puppet::Network::Handler::FileServer.new(:Config => config_file) 
-        }.should raise_error(Puppet::Network::Handler::FileServerError, "No mount specified for argument #{arg} 127.0.0.1/24")
-      end
-    end
-  end
-
-  it "should list a single directory" do
-    @mount.list("/", false, false).should == [["/", "directory"]]
-  end
-
-  it "should list a file within a directory when given the file path" do
-    @mount.list("/aFile", false, "false").should == [["/", "file"]]
-  end
-
-  it "should list a file within a directory when given the file path with recursion" do
-    @mount.list("/aFile", true, "false").should == [["/", "file"]]
-  end
-
-  it "should return nil for a non-existent path" do
-    @mount.list("/no_such_file", false, false).should be(nil)
-  end
-
-  it "should list a symbolic link as a file when given the link path", :unless => Puppet.features.microsoft_windows? do
-    File.symlink(@file, @link)
-    @mount.list("/aLink", false, false).should == [["/", "file"]]
-  end
-
-  it "should return nil for a dangling symbolic link when given the link path", :unless => Puppet.features.microsoft_windows? do
-    File.symlink("/some/where", @link)
-    @mount.list("/aLink", false, false).should be(nil)
-  end
-
-  it "should list directory contents of a flat directory structure when asked to recurse" do
-    list = @mount.list("/", true, false)
-    list.should include(["/aFile", "file"])
-    list.should include(["/", "directory"])
-    list.should have(2).items
-  end
-
-  it "should list the contents of a nested directory" do
-    create_nested_file
-    list = @mount.list("/", true, false)
-    list.sort.should == [   ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort
-  end
-
-  it "should list the contents of a directory ignoring files that match" do
-    create_nested_file
-    list = @mount.list("/", true, "*File")
-    list.sort.should == [   ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort
-  end
-
-  it "should list the contents of a directory ignoring directories that match" do
-    create_nested_file
-    list = @mount.list("/", true, "*nested_dir")
-    list.sort.should == [   ["/aFile", "file"], ["/", "directory"] ].sort
-  end
-
-  it "should list the contents of a directory ignoring all ignore patterns that match" do
-    create_nested_file
-    list = @mount.list("/", true, ["*File" , "*nested_dir"])
-    list.should == [ ["/", "directory"] ]
-  end
-
-  it "should list the directory when recursing to a depth of zero" do
-    create_nested_file
-    list = @mount.list("/", 0, false)
-    list.should == [["/", "directory"]]
-  end
-
-  it "should list the base directory and files and nested directory to a depth of one" do
-    create_nested_file
-    list = @mount.list("/", 1, false)
-    list.sort.should == [ ["/aFile", "file"], ["/nested_dir", "directory"], ["/", "directory"] ].sort
-  end
-
-  it "should list the base directory and files and nested directory to a depth of two" do
-    create_nested_file
-    list = @mount.list("/", 2, false)
-    list.sort.should == [   ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort
-  end
-
-  it "should list the base directory and files and nested directory to a depth greater than the directory structure" do
-    create_nested_file
-    list = @mount.list("/", 42, false)
-    list.sort.should == [   ["/aFile", "file"], ["/", "directory"] , ["/nested_dir", "directory"], ["/nested_dir/nested_dir_file", "file"]].sort
-  end
-
-  it "should list a valid symbolic link as a file when recursing base dir", :unless => Puppet.features.microsoft_windows? do
-    File.symlink(@file, @link)
-    list = @mount.list("/", true, false)
-    list.sort.should == [ ["/", "directory"], ["/aFile", "file"], ["/aLink", "file"] ].sort
-  end
-
-  it "should not error when a dangling symlink is present", :unless => Puppet.features.microsoft_windows? do
-    File.symlink("/some/where", @link)
-    lambda { @mount.list("/", true, false) }.should_not raise_error
-  end
-
-  it "should return the directory contents of valid entries when a dangling symlink is present", :unless => Puppet.features.microsoft_windows? do
-    File.symlink("/some/where", @link)
-    list = @mount.list("/", true, false)
-    list.sort.should == [ ["/aFile", "file"], ["/", "directory"] ].sort
-  end
-
-  describe Puppet::Network::Handler::FileServer::PluginMount, :'fails_on_ruby_1.9.2' => true do
-    PLUGINS = Puppet::Network::Handler::FileServer::PLUGINS
-
-    # create a module plugin hierarchy
-    def create_plugin(mod, plugin)
-      dirname = File.join(@basedir, mod)
-      Dir.mkdir(dirname)
-      plugins = File.join(dirname, PLUGINS)
-      Dir.mkdir(plugins)
-      facter = File.join(plugins, plugin)
-      Dir.mkdir(facter)
-      create_file(File.join(facter,"fact.rb"))
-    end
-
-    before :each do
-      @modules = ["one","two"]
-      @modules.each { |m| create_plugin(m, "facter") }
-
-      Puppet::Node::Environment.new.stubs(:modulepath).returns @basedir
-
-      @mount = Puppet::Network::Handler::FileServer::PluginMount.new(PLUGINS)
-      @mount.allow("*")
-    end
-
-    it "should list a file within a directory when given the file path with recursion" do
-      @mount.list("facter/fact.rb", true, "false").should == [["/", "file"], ["/", "file"]]
-    end
-
-    it "should return a merged view of all plugins for all modules" do
-      list = @mount.list("facter",true,false)
-      list.should == [["/", "directory"], ["/fact.rb", "file"], ["/", "directory"], ["/fact.rb", "file"]]
-    end
-
-    it "should not fail for inexistant plugins type" do
-      @mount.list("puppet/parser",true,false)
-    end
-
-  end
-
-  after do
-    FileUtils.rm_rf(@basedir)
-  end
-
-end
diff --git a/spec/unit/network/http/api/v1_spec.rb b/spec/unit/network/http/api/v1_spec.rb
index a952f24..039bccf 100755
--- a/spec/unit/network/http/api/v1_spec.rb
+++ b/spec/unit/network/http/api/v1_spec.rb
@@ -123,6 +123,10 @@ class V1RestApiTester
       @tester.uri2indirection("GET", "/env/statuses/bar", {})[0].should == 'status'
     end
 
+    it "should change indirection name to 'probe' if the http method is a GET and the indirection name is probes" do
+      @tester.uri2indirection("GET", "/env/probes/bar", {})[0].should == 'probe'
+    end
+
     it "should choose 'delete' as the indirection method if the http method is a DELETE and the indirection name is singular" do
       @tester.uri2indirection("DELETE", "/env/foo/bar", {})[1].should == :destroy
     end
diff --git a/spec/unit/network/http/mongrel/xmlrpc_spec.rb b/spec/unit/network/http/mongrel/xmlrpc_spec.rb
deleted file mode 100755
index e69de29..0000000
diff --git a/spec/unit/network/http/mongrel_spec.rb b/spec/unit/network/http/mongrel_spec.rb
index 9e7e9c4..2e0ff04 100755
--- a/spec/unit/network/http/mongrel_spec.rb
+++ b/spec/unit/network/http/mongrel_spec.rb
@@ -20,10 +20,7 @@
     @mock_mongrel.stubs(:register)
     Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel)
 
-    @mock_puppet_mongrel = mock('puppet_mongrel')
-    Puppet::Network::HTTPServer::Mongrel.stubs(:new).returns(@mock_puppet_mongrel)
-
-    @listen_params = { :address => "127.0.0.1", :port => 31337, :protocols => [ :rest, :xmlrpc ], :xmlrpc_handlers => [ :status, :fileserver ] }
+    @listen_params = { :address => "127.0.0.1", :port => 31337 }
   end
 
   it "should fail if already listening" do
@@ -31,10 +28,6 @@
     Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError)
   end
 
-  it "should require at least one protocol" do
-    Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError)
-  end
-
   it "should require a listening address to be specified" do
     Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError)
   end
@@ -66,29 +59,6 @@
 
       @server.listen(@listen_params)
     end
-
-    it "should use a Mongrel + REST class to configure Mongrel when REST services are requested" do
-      @server.expects(:class_for_protocol).with(:rest).at_least_once.returns(Puppet::Network::HTTP::MongrelREST)
-      @server.listen(@listen_params)
-    end
-  end
-
-  describe "when providing XMLRPC services" do
-    it "should do nothing if no xmlrpc handlers have been provided" do
-      Puppet::Network::HTTPServer::Mongrel.expects(:new).never
-      @server.listen(@listen_params.merge(:xmlrpc_handlers => []))
-    end
-
-    it "should create an instance of the existing Mongrel http server with the right handlers" do
-      Puppet::Network::HTTPServer::Mongrel.expects(:new).with([:status, :master]).returns(@mock_puppet_mongrel)
-      @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master]))
-    end
-
-    it "should register the Mongrel server instance at /RPC2" do
-      @mock_mongrel.expects(:register).with("/RPC2", @mock_puppet_mongrel)
-
-      @server.listen(@listen_params.merge(:xmlrpc_handlers => [:status, :master]))
-    end
   end
 end
 
@@ -99,7 +69,7 @@
     @mock_mongrel.stubs(:register)
     Mongrel::HttpServer.stubs(:new).returns(@mock_mongrel)
     @server = Puppet::Network::HTTP::Mongrel.new
-    @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] }
+    @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ]}
   end
 
   it "should fail unless listening" do
diff --git a/spec/unit/network/http/rack/xmlrpc_spec.rb b/spec/unit/network/http/rack/xmlrpc_spec.rb
deleted file mode 100755
index 9173438..0000000
--- a/spec/unit/network/http/rack/xmlrpc_spec.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-require 'puppet/network/handler'
-require 'puppet/network/http/rack' if Puppet.features.rack?
-require 'puppet/network/http/rack/xmlrpc' if Puppet.features.rack?
-
-describe "Puppet::Network::HTTP::RackXMLRPC", :if => Puppet.features.rack? do
-  describe "when initializing" do
-    it "should create an Puppet::Network::XMLRPCServer" do
-      Puppet::Network::XMLRPCServer.expects(:new).returns stub_everything
-      Puppet::Network::HTTP::RackXMLRPC.new([])
-    end
-
-    it "should create each handler" do
-      handler = stub_everything 'handler'
-      Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler)
-      Puppet::Network::Handler.expects(:handler).returns(handler).times(2)
-      Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar])
-    end
-
-    it "should add each handler to the XMLRPCserver" do
-      handler = stub_everything 'handler'
-      Puppet::Network::Handler.stubs(:handler).returns(handler)
-      Puppet::Network::XMLRPCServer.any_instance.expects(:add_handler).times(2)
-      Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar])
-    end
-  end
-
-  describe "when serving a request" do
-
-    before :each do
-      foo_handler = stub_everything 'foo_handler'
-      Puppet::Network::Handler.stubs(:handler).with(:foo).returns foo_handler
-      Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler)
-      Puppet::Network::XMLRPCServer.any_instance.stubs(:process).returns('<xml/>')
-      @handler = Puppet::Network::HTTP::RackXMLRPC.new([:foo])
-    end
-
-    before :each do
-      @response = Rack::Response.new
-    end
-
-    def mk_req(opts = {})
-      opts[:method] = 'POST' if !opts[:method]
-      opts['CONTENT_TYPE'] = 'text/xml; foo=bar' if !opts['CONTENT_TYPE']
-      env = Rack::MockRequest.env_for('/RPC2', opts)
-      Rack::Request.new(env)
-    end
-
-    it "should reject non-POST requests" do
-      req = mk_req :method => 'PUT'
-      @handler.process(req, @response)
-      @response.status.should == 405
-    end
-
-    it "should reject non text/xml requests" do
-      req = mk_req 'CONTENT_TYPE' => 'yadda/plain'
-    end
-
-    it "should create a ClientRequest" do
-      cr = Puppet::Network::ClientRequest.new(nil, '127.0.0.1', false)
-      Puppet::Network::ClientRequest.expects(:new).returns cr
-      req = mk_req
-      @handler.process(req, @response)
-    end
-
-    it "should let xmlrpcserver process the request" do
-      Puppet::Network::XMLRPCServer.any_instance.expects(:process).returns('yay')
-      req = mk_req
-      @handler.process(req, @response)
-    end
-
-    it "should report the response as OK" do
-      req = mk_req
-      @handler.process(req, @response)
-      @response.status.should == 200
-    end
-
-    it "should report the response with the correct content type" do
-      req = mk_req
-      @handler.process(req, @response)
-      @response['Content-Type'].should == 'text/xml; charset=utf-8'
-    end
-
-    it "should set 'authenticated' to false if no certificate is present" do
-      req = mk_req
-      Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false }
-      @handler.process(req, @response)
-    end
-
-    it "should use the client's ip address" do
-      req = mk_req 'REMOTE_ADDR' => 'ipaddress'
-      Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| ip == 'ipaddress' }
-      @handler.process(req, @response)
-    end
-
-    describe "with pre-validated certificates" do
-
-      it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do
-        Puppet.settings.stubs(:value).returns "eh"
-        Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader"
-        req = mk_req "myheader" => "/CN=host.domain.com"
-        @handler.process(req, @response)
-      end
-
-      it "should retrieve the hostname by matching the certificate parameter" do
-        Puppet.settings.stubs(:value).returns "eh"
-        Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader"
-        Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| node == "host.domain.com" }
-        req = mk_req "myheader" => "/CN=host.domain.com"
-        @handler.process(req, @response)
-      end
-
-      it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do
-        Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader"
-        Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader"
-        req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com"
-        @handler.process(req, @response)
-      end
-
-      it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do
-        Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader"
-        Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
-        Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == true }
-        req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com"
-        @handler.process(req, @response)
-      end
-
-      it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do
-        Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader"
-        Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
-        Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false }
-        req = mk_req "myheader" => "whatever", "certheader" => "/CN=host.domain.com"
-        @handler.process(req, @response)
-      end
-
-      it "should consider the host unauthenticated if no certificate information is present" do
-        Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader"
-        Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
-        Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| authenticated == false }
-        req = mk_req "myheader" => nil, "certheader" => "/CN=host.domain.com"
-        @handler.process(req, @response)
-      end
-
-      it "should resolve the node name with an ip address look-up if no certificate is present" do
-        Puppet.settings.stubs(:value).returns "eh"
-        Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader"
-        Resolv.any_instance.expects(:getname).returns("host.domain.com")
-        Puppet::Network::ClientRequest.expects(:new).with { |node,ip,authenticated| node == "host.domain.com" }
-        req = mk_req "myheader" => nil
-        @handler.process(req, @response)
-      end
-    end
-  end
-end
diff --git a/spec/unit/network/http/rack_spec.rb b/spec/unit/network/http/rack_spec.rb
index 9e1ee3d..5f14809 100755
--- a/spec/unit/network/http/rack_spec.rb
+++ b/spec/unit/network/http/rack_spec.rb
@@ -1,47 +1,11 @@
 #!/usr/bin/env rspec
 require 'spec_helper'
-require 'puppet/network/handler'
 require 'puppet/network/http/rack' if Puppet.features.rack?
 
 describe "Puppet::Network::HTTP::Rack", :if => Puppet.features.rack? do
-  describe "while initializing" do
-
-    it "should require a protocol specification" do
-      Proc.new { Puppet::Network::HTTP::Rack.new({}) }.should raise_error(ArgumentError)
-    end
-
-    it "should not accept imaginary protocols" do
-      Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:foo]}) }.should raise_error(ArgumentError)
-    end
-
-    it "should accept the REST protocol" do
-      Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:rest]}) }.should_not raise_error(ArgumentError)
-    end
-
-    it "should create a RackREST instance" do
-      Puppet::Network::HTTP::RackREST.expects(:new)
-      Puppet::Network::HTTP::Rack.new({:protocols => [:rest]})
-    end
-
-    describe "with XMLRPC enabled" do
-
-      it "should require XMLRPC handlers" do
-        Proc.new { Puppet::Network::HTTP::Rack.new({:protocols => [:xmlrpc]}) }.should raise_error(ArgumentError)
-      end
-
-      it "should create a RackXMLRPC instance" do
-        Puppet::Network::HTTP::RackXMLRPC.expects(:new)
-        Puppet::Network::HTTP::Rack.new({:protocols => [:xmlrpc], :xmlrpc_handlers => [:Status]})
-      end
-
-    end
-
-  end
-
   describe "when called" do
-
     before :all do
-      @app = Puppet::Network::HTTP::Rack.new({:protocols => [:rest]})
+      @app = Puppet::Network::HTTP::Rack.new()
       # let's use Rack::Lint to verify that we're OK with the rack specification
       @linted = Rack::Lint.new(@app)
     end
@@ -75,26 +39,5 @@
       Rack::Response.any_instance.expects(:finish).once
       @app.call(@env) # can't lint when finish is a stub
     end
-
-  end
-
-  describe "when serving XMLRPC" do
-
-    before :all do
-      @app = Puppet::Network::HTTP::Rack.new({:protocols => [:rest, :xmlrpc], :xmlrpc_handlers => [:Status]})
-      @linted = Rack::Lint.new(@app)
-    end
-
-    before :each do
-      @env = Rack::MockRequest.env_for('/RPC2', :method => 'POST')
-    end
-
-    it "should use RackXMLRPC to serve /RPC2 requests" do
-      Puppet::Network::HTTP::RackXMLRPC.any_instance.expects(:process).once
-      @linted.call(@env)
-    end
-
   end
-
 end
-
diff --git a/spec/unit/network/http/webrick/xmlrpc_spec.rb b/spec/unit/network/http/webrick/xmlrpc_spec.rb
deleted file mode 100755
index e69de29..0000000
diff --git a/spec/unit/network/http/webrick_spec.rb b/spec/unit/network/http/webrick_spec.rb
index f84e78e..ec04c77 100755
--- a/spec/unit/network/http/webrick_spec.rb
+++ b/spec/unit/network/http/webrick_spec.rb
@@ -1,6 +1,5 @@
 #!/usr/bin/env rspec
 require 'spec_helper'
-require 'puppet/network/handler'
 require 'puppet/network/http'
 require 'puppet/network/http/webrick'
 
@@ -17,7 +16,7 @@
     WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick)
     @server = Puppet::Network::HTTP::WEBrick.new
     [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging
-    @listen_params = { :address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [], :protocols => [ :rest ] }
+    @listen_params = { :address => "127.0.0.1", :port => 31337, :protocols => [ :rest ] }
   end
 
   it "should fail if already listening" do
@@ -25,10 +24,6 @@
     Proc.new { @server.listen(@listen_params) }.should raise_error(RuntimeError)
   end
 
-  it "should require at least one protocol" do
-    Proc.new { @server.listen(@listen_params.delete_if {|k,v| :protocols == k}) }.should raise_error(ArgumentError)
-  end
-
   it "should require a listening address to be specified" do
     Proc.new { @server.listen(@listen_params.delete_if {|k,v| :address == k})}.should raise_error(ArgumentError)
   end
@@ -84,77 +79,6 @@
       @server.listen(@listen_params.merge(:protocols => [:rest]))
     end
   end
-
-  describe "when the XMLRPC protocol is requested" do
-    before do
-      @servlet = mock 'servlet'
-
-      Puppet::Network::XMLRPC::WEBrickServlet.stubs(:new).returns @servlet
-
-      @master_handler = mock('master_handler')
-      @file_handler = mock('file_handler')
-
-      @master = mock 'master'
-      @file = mock 'file'
-      @master_handler.stubs(:new).returns @master
-      @file_handler.stubs(:new).returns @file
-
-      Puppet::Network::Handler.stubs(:handler).with(:master).returns @master_handler
-      Puppet::Network::Handler.stubs(:handler).with(:fileserver).returns @file_handler
-    end
-
-    it "should do nothing if no xmlrpc handlers have been specified" do
-      Puppet::Network::Handler.expects(:handler).never
-
-      @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => []))
-    end
-
-    it "should look the handler classes up via their base class" do
-      Puppet::Network::Handler.expects(:handler).with(:master).returns @master_handler
-      Puppet::Network::Handler.expects(:handler).with(:fileserver).returns @file_handler
-
-      @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver]))
-    end
-
-    it "should create an instance for each requested xmlrpc handler" do
-      @master_handler.expects(:new).returns @master
-      @file_handler.expects(:new).returns @file
-
-      @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver]))
-    end
-
-    it "should create a webrick servlet with the xmlrpc handler instances" do
-      Puppet::Network::XMLRPC::WEBrickServlet.expects(:new).with([@master, @file]).returns @servlet
-
-      @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver]))
-    end
-
-    it "should mount the webrick servlet at /RPC2" do
-      @mock_webrick.stubs(:mount)
-      @mock_webrick.expects(:mount).with("/RPC2", @servlet)
-
-      @server.listen(@listen_params.merge(:protocols => [:xmlrpc], :xmlrpc_handlers => [:master, :fileserver]))
-    end
-  end
-end
-
-
-describe Puppet::Network::HTTP::WEBrick, "when looking up the class to handle a protocol", :unless => Puppet.features.microsoft_windows? do
-  it "should require a protocol" do
-    lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol }.should raise_error(ArgumentError)
-  end
-
-  it "should accept a protocol" do
-    lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("bob") }.should_not raise_error(ArgumentError)
-  end
-
-  it "should use a WEBrick + REST class when a REST protocol is specified" do
-    Puppet::Network::HTTP::WEBrick.class_for_protocol("rest").should == Puppet::Network::HTTP::WEBrickREST
-  end
-
-  it "should fail when an unknown protocol is specified" do
-    lambda { Puppet::Network::HTTP::WEBrick.class_for_protocol("abcdefg") }.should raise_error
-  end
 end
 
 describe Puppet::Network::HTTP::WEBrick, "when turning off listening", :unless => Puppet.features.microsoft_windows? do
diff --git a/spec/unit/network/resolver_spec.rb b/spec/unit/network/resolver_spec.rb
new file mode 100755
index 0000000..1ccc102
--- /dev/null
+++ b/spec/unit/network/resolver_spec.rb
@@ -0,0 +1,207 @@
+#!/usr/bin/env ruby
+require 'spec_helper'
+require 'puppet/network/resolver'
+
+describe Puppet::Network::Resolver do
+  before do
+    @dns_mock_object = mock('dns')
+    Resolv::DNS.stubs(:new).returns(@dns_mock_object)
+
+    @rr_type         = Resolv::DNS::Resource::IN::SRV
+    @test_srv_domain = "domain.com"
+    @test_a_hostname = "puppet.domain.com"
+    @test_port       = 1000
+
+    # The records we should use.
+    @test_records = [
+      #                                  priority,  weight, port, hostname
+      Resolv::DNS::Resource::IN::SRV.new(0,         20,     8140, "puppet1.domain.com"),
+      Resolv::DNS::Resource::IN::SRV.new(0,         80,     8140, "puppet2.domain.com"),
+      Resolv::DNS::Resource::IN::SRV.new(1,         1,      8140, "puppet3.domain.com"),
+      Resolv::DNS::Resource::IN::SRV.new(4,         1,      8140, "puppet4.domain.com")
+    ]
+  end
+
+  describe 'when the domain is not known' do
+    before :each do
+      @dns_mock_object.stubs(:getresources).returns(@test_records)
+    end
+
+    describe 'because domain is nil' do
+      it 'does not yield' do
+        Puppet::Network::Resolver.each_srv_record(nil) do |_,_,_|
+          raise Exception.new("nil domain caused SRV lookup")
+        end
+      end
+    end
+
+    describe 'because domain is an empty string' do
+      it 'does not yield' do
+        Puppet::Network::Resolver.each_srv_record('') do |_,_,_|
+          raise Exception.new("nil domain caused SRV lookup")
+        end
+      end
+    end
+  end
+
+  describe "when resolving a host without SRV records" do
+    it "should not yield anything" do
+      # No records returned for a DNS entry without any SRV records
+      @dns_mock_object.expects(:getresources).with(
+        "_x-puppet._tcp.#{@test_a_hostname}",
+        @rr_type
+      ).returns([])
+
+      Puppet::Network::Resolver.each_srv_record(@test_a_hostname) do |hostname, port, remaining|
+        raise Exception.new("host with no records passed block")
+      end
+    end
+  end
+
+  describe "when resolving a host with SRV records" do
+    it "should iterate through records in priority order" do
+      # The order of the records that should be returned,
+      # an array means unordered (for weight)
+      order = {
+        0 => ["puppet1.domain.com", "puppet2.domain.com"],
+        1 => ["puppet3.domain.com"],
+        2 => ["puppet4.domain.com"]
+      }
+
+      @dns_mock_object.expects(:getresources).with(
+        "_x-puppet._tcp.#{@test_srv_domain}",
+        @rr_type
+      ).returns(@test_records)
+
+      Puppet::Network::Resolver.each_srv_record(@test_srv_domain) do |hostname, port|
+        expected_priority = order.keys.min
+
+        order[expected_priority].should include(hostname)
+        port.should_not be(@test_port)
+
+        # Remove the host from our expected hosts
+        order[expected_priority].delete hostname
+
+        # Remove this priority level if we're done with it
+        order.delete expected_priority if order[expected_priority] == []
+      end
+    end
+
+    it "should fall back to the :puppet service if no records are found for a more specific service" do
+      # The order of the records that should be returned,
+      # an array means unordered (for weight)
+      order = {
+        0 => ["puppet1.domain.com", "puppet2.domain.com"],
+        1 => ["puppet3.domain.com"],
+        2 => ["puppet4.domain.com"]
+      }
+
+      @dns_mock_object.expects(:getresources).with(
+        "_x-puppet-report._tcp.#{@test_srv_domain}",
+        @rr_type
+      ).returns([])
+
+      @dns_mock_object.expects(:getresources).with(
+        "_x-puppet._tcp.#{@test_srv_domain}",
+        @rr_type
+      ).returns(@test_records)
+
+      Puppet::Network::Resolver.each_srv_record(@test_srv_domain, :report) do |hostname, port|
+        expected_priority = order.keys.min
+
+        order[expected_priority].should include(hostname)
+        port.should_not be(@test_port)
+
+        # Remove the host from our expected hosts
+        order[expected_priority].delete hostname
+
+        # Remove this priority level if we're done with it
+        order.delete expected_priority if order[expected_priority] == []
+      end
+    end
+
+    it "should use SRV records from the specific service if they exist" do
+      # The order of the records that should be returned,
+      # an array means unordered (for weight)
+      order = {
+        0 => ["puppet1.domain.com", "puppet2.domain.com"],
+        1 => ["puppet3.domain.com"],
+        2 => ["puppet4.domain.com"]
+      }
+
+      bad_records = [
+        #                                  priority,  weight, port, hostname
+        Resolv::DNS::Resource::IN::SRV.new(0,         20,     8140, "puppet1.bad.domain.com"),
+        Resolv::DNS::Resource::IN::SRV.new(0,         80,     8140, "puppet2.bad.domain.com"),
+        Resolv::DNS::Resource::IN::SRV.new(1,         1,      8140, "puppet3.bad.domain.com"),
+        Resolv::DNS::Resource::IN::SRV.new(4,         1,      8140, "puppet4.bad.domain.com")
+      ]
+
+      @dns_mock_object.expects(:getresources).with(
+        "_x-puppet-report._tcp.#{@test_srv_domain}",
+        @rr_type
+      ).returns(@test_records)
+
+      @dns_mock_object.stubs(:getresources).with(
+        "_x-puppet._tcp.#{@test_srv_domain}",
+        @rr_type
+      ).returns(bad_records)
+
+      Puppet::Network::Resolver.each_srv_record(@test_srv_domain, :report) do |hostname, port|
+        expected_priority = order.keys.min
+
+        order[expected_priority].should include(hostname)
+        port.should_not be(@test_port)
+
+        # Remove the host from our expected hosts
+        order[expected_priority].delete hostname
+
+        # Remove this priority level if we're done with it
+        order.delete expected_priority if order[expected_priority] == []
+      end
+    end
+  end
+
+  describe "when finding weighted servers" do
+    it "should return nil when no records were found" do
+      Puppet::Network::Resolver.find_weighted_server([]).should == nil
+    end
+
+    it "should return the first record when one record is passed" do
+      result = Puppet::Network::Resolver.find_weighted_server([@test_records.first])
+      result.should == @test_records.first
+    end
+
+    {
+      "all have weights"  => [1, 3, 2, 4],
+      "some have weights" => [2, 0, 1, 0],
+      "none have weights" => [0, 0, 0, 0],
+    }.each do |name, weights|
+      it "should return correct results when #{name}" do
+        records = []
+        count   = 0
+        weights.each do |w|
+          count += 1
+          #                                             priority, weight, port, server
+          records << Resolv::DNS::Resource::IN::SRV.new(0,        w,      1,    count.to_s)
+        end
+
+        seen  = Hash.new(0)
+        total_weight = records.inject(0) do |sum, record|
+          sum + Puppet::Network::Resolver.weight(record)
+        end
+
+        total_weight.times do |n|
+          Kernel.expects(:rand).once.with(total_weight).returns(n)
+          server = Puppet::Network::Resolver.find_weighted_server(records)
+          seen[server] += 1
+        end
+
+        seen.length.should == records.length
+        records.each do |record|
+          seen[record].should == Puppet::Network::Resolver.weight(record)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/unit/network/rights_spec.rb b/spec/unit/network/rights_spec.rb
index b709f10..30a4024 100755
--- a/spec/unit/network/rights_spec.rb
+++ b/spec/unit/network/rights_spec.rb
@@ -461,22 +461,13 @@
       end
     end
 
-    ["off", "no", "false", false].each do |auth|
-      it "should allow filtering on unauthenticated requests with '#{auth}'" do
+    ["off", "no", "false", false, "all", "any", :all, :any].each do |auth|
+      it "should allow filtering on authenticated or unauthenticated requests with '#{auth}'" do
         @acl.restrict_authenticated(auth)
-
         @acl.authentication.should be_false
       end
     end
 
-    ["all", "any", :all, :any].each do |auth|
-      it "should not use request authenticated state filtering with '#{auth}'" do
-        @acl.restrict_authenticated(auth)
-
-        @acl.authentication.should be_nil
-      end
-    end
-
     describe "when checking right authorization" do
       it "should return :dunno if this right is not restricted to the given method" do
         @acl.restrict_method(:destroy)
diff --git a/spec/unit/network/server_spec.rb b/spec/unit/network/server_spec.rb
index b38e82b..b769472 100755
--- a/spec/unit/network/server_spec.rb
+++ b/spec/unit/network/server_spec.rb
@@ -1,7 +1,6 @@
 #!/usr/bin/env rspec
 require 'spec_helper'
 require 'puppet/network/server'
-require 'puppet/network/handler'
 
 describe Puppet::Network::Server do
   before do
@@ -19,7 +18,6 @@
   describe "when initializing" do
     before do
       Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
-      Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler')
       Puppet.settings.stubs(:value).with(:bindaddress).returns("")
       Puppet.settings.stubs(:value).with(:masterport).returns('')
     end
@@ -94,25 +92,20 @@
       lambda { @server.unregister(:foo, :bar, :baz) }.should_not raise_error
     end
 
-    it "should allow registering XMLRPC handlers" do
-      @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz])
-      lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should_not raise_error
-    end
-
     it "should not be listening after initialization" do
       Puppet::Network::Server.new(:port => 31337).should_not be_listening
     end
 
     it "should use the :main setting section" do
       Puppet.settings.expects(:use).with { |*args| args.include?(:main) }
-      @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz])
+      @server = Puppet::Network::Server.new(:port => 31337)
     end
 
     it "should use the Puppet[:name] setting section" do
       Puppet.settings.expects(:value).with(:name).returns "me"
       Puppet.settings.expects(:use).with { |*args| args.include?("me") }
 
-      @server = Puppet::Network::Server.new(:port => 31337, :xmlrpc_handlers => [ :foo, :bar, :baz])
+      @server = Puppet::Network::Server.new(:port => 31337)
     end
   end
 
@@ -302,14 +295,6 @@
     @server.server_type.should == :suparserver
   end
 
-  it "should provide a means of determining which protocols are in use" do
-    @server.should respond_to(:protocols)
-  end
-
-  it "should set the protocols to :rest and :xmlrpc" do
-    @server.protocols.should == [ :rest, :xmlrpc ]
-  end
-
   it "should provide a means of determining the listening address" do
     @server.address.should == "127.0.0.1"
   end
@@ -330,70 +315,6 @@
     lambda { @server2.unregister(:bar) }.should raise_error(ArgumentError)
   end
 
-  describe "when managing xmlrpc registrations" do
-    before do
-      Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler')
-    end
-
-    it "should allow registering an xmlrpc handler by specifying its namespace" do
-      lambda { @server.register_xmlrpc(:foo) }.should_not raise_error
-    end
-
-    it "should require that the xmlrpc namespace be valid" do
-      Puppet::Network::Handler.stubs(:handler).returns nil
-
-      lambda { @server.register_xmlrpc(:foo) }.should raise_error(ArgumentError)
-    end
-
-    it "should require at least one namespace" do
-      lambda { @server.register_xmlrpc }.should raise_error(ArgumentError)
-    end
-
-    it "should allow multiple namespaces to be registered at once" do
-      lambda { @server.register_xmlrpc(:foo, :bar) }.should_not raise_error
-    end
-
-    it "should allow the use of namespaces to specify which are no longer accessible to clients" do
-      @server.register_xmlrpc(:foo, :bar)
-    end
-
-    it "should leave other namespaces accessible to clients when turning off xmlrpc namespaces" do
-      @server.register_xmlrpc(:foo, :bar)
-      @server.unregister_xmlrpc(:foo)
-      lambda { @server.unregister_xmlrpc(:bar)}.should_not raise_error
-    end
-
-    it "should allow specifying numerous namespaces which are to be no longer accessible to clients" do
-      @server.register_xmlrpc(:foo, :bar)
-      lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error
-    end
-
-    it "should not turn off any indirections if given unknown namespaces to turn off" do
-      @server.register_xmlrpc(:foo, :bar)
-      lambda { @server.unregister_xmlrpc(:foo, :bar, :baz) }.should raise_error(ArgumentError)
-      lambda { @server.unregister_xmlrpc(:foo, :bar) }.should_not raise_error
-    end
-
-    it "should not allow turning off unknown namespaces" do
-      @server.register_xmlrpc(:foo, :bar)
-      lambda { @server.unregister_xmlrpc(:baz) }.should raise_error(ArgumentError)
-    end
-
-    it "should disable client access immediately when turning off namespaces" do
-      @server.register_xmlrpc(:foo, :bar)
-      @server.unregister_xmlrpc(:foo)
-      lambda { @server.unregister_xmlrpc(:foo) }.should raise_error(ArgumentError)
-    end
-
-    it "should allow turning off all namespaces at once" do
-      @server.register_xmlrpc(:foo, :bar)
-      @server.unregister_xmlrpc
-      [ :foo, :bar, :baz].each do |indirection|
-        lambda { @server.unregister_xmlrpc(indirection) }.should raise_error(ArgumentError)
-      end
-    end
-  end
-
   describe "when listening is off" do
     before do
       @mock_http_server = mock('http server')
@@ -440,9 +361,8 @@
   describe "when listening is being turned on" do
     before do
       Puppet::Indirector::Indirection.stubs(:model).returns mock('indirection')
-      Puppet::Network::Handler.stubs(:handler).returns mock('xmlrpc_handler')
 
-      @server = Puppet::Network::Server.new(:port => 31337, :handlers => [:node], :xmlrpc_handlers => [:master])
+      @server = Puppet::Network::Server.new(:port => 31337, :handlers => [:node])
       @mock_http_server = mock('http server')
       @mock_http_server.stubs(:listen)
     end
@@ -482,22 +402,6 @@
       end
       @server.listen
     end
-
-    it "should pass a list of XMLRPC handlers to the HTTP server" do
-      @server.stubs(:http_server).returns(@mock_http_server)
-      @mock_http_server.expects(:listen).with do |args|
-        args[:xmlrpc_handlers] == [ :master ]
-      end
-      @server.listen
-    end
-
-    it "should pass a list of protocols to the HTTP server" do
-      @server.stubs(:http_server).returns(@mock_http_server)
-      @mock_http_server.expects(:listen).with do |args|
-        args[:protocols] == [ :rest, :xmlrpc ]
-      end
-      @server.listen
-    end
   end
 
   describe "when listening is being turned off" do
diff --git a/spec/unit/node/facts_spec.rb b/spec/unit/node/facts_spec.rb
index 4514607..b3a0f92 100755
--- a/spec/unit/node/facts_spec.rb
+++ b/spec/unit/node/facts_spec.rb
@@ -124,6 +124,20 @@
         result['timestamp'].should == facts.timestamp.to_s
         result['expiration'].should == facts.expiration.to_s
       end
+
+      it "should not include nil values" do
+        facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3})
+        pson = PSON.parse(facts.to_pson)
+        pson.should_not be_include("expiration")
+      end
+
+      it "should be able to handle nil values" do
+        pson = %Q({"name": "foo", "values": {"a": "1", "b": "2", "c": "3"}})
+        format = Puppet::Network::FormatHandler.format('pson')
+        facts = format.intern(Puppet::Node::Facts,pson)
+        facts.name.should == 'foo'
+        facts.expiration.should be_nil
+      end
     end
   end
 end
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index 33bb4d1..a47c716 100755
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -3,6 +3,10 @@
 require 'matchers/json'
 
 describe Puppet::Node do
+  it "should register its document type as Node" do
+    PSON.registered_document_types["Node"].should equal(Puppet::Node)
+  end
+
   describe "when managing its environment" do
     it "should use any set environment" do
       Puppet::Node.new("foo", :environment => "bar").environment.name.should == :bar
@@ -36,6 +40,73 @@
       node.environment.name.should == :bar
     end
   end
+
+  describe "when converting to json" do
+    before do
+      @node = Puppet::Node.new("mynode")
+    end
+
+    it "should provide its name" do
+      @node.should set_json_attribute('name').to("mynode")
+    end
+
+    it "should produce a hash with the document_type set to 'Node'" do
+      @node.should set_json_document_type_to("Node")
+    end
+
+    it "should include the classes if set" do
+      @node.classes = %w{a b c}
+      @node.should set_json_attribute("classes").to(%w{a b c})
+    end
+
+    it "should not include the classes if there are none" do
+      @node.should_not set_json_attribute('classes')
+    end
+
+    it "should include parameters if set" do
+      @node.parameters = {"a" => "b", "c" => "d"}
+      @node.should set_json_attribute('parameters').to({"a" => "b", "c" => "d"})
+    end
+
+    it "should not include the parameters if there are none" do
+      @node.should_not set_json_attribute('parameters')
+    end
+
+    it "should include the environment" do
+      @node.environment = "production"
+      @node.should set_json_attribute('environment').to('production')
+    end
+  end
+
+  describe "when converting from json" do
+    before do
+      @node = Puppet::Node.new("mynode")
+      @format = Puppet::Network::FormatHandler.format('pson')
+    end
+
+    def from_json(json)
+      @format.intern(Puppet::Node, json)
+    end
+
+    it "should set its name" do
+      Puppet::Node.should read_json_attribute('name').from(@node.to_pson).as("mynode")
+    end
+
+    it "should include the classes if set" do
+      @node.classes = %w{a b c}
+      Puppet::Node.should read_json_attribute('classes').from(@node.to_pson).as(%w{a b c})
+    end
+
+    it "should include parameters if set" do
+      @node.parameters = {"a" => "b", "c" => "d"}
+      Puppet::Node.should read_json_attribute('parameters').from(@node.to_pson).as({"a" => "b", "c" => "d"})
+    end
+
+    it "should include the environment" do
+      @node.environment = "production"
+      Puppet::Node.should read_json_attribute('environment').from(@node.to_pson).as(Puppet::Node::Environment.new(:production))
+    end
+  end
 end
 
 describe Puppet::Node, "when initializing" do
diff --git a/spec/unit/other/transbucket_spec.rb b/spec/unit/other/transbucket_spec.rb
deleted file mode 100755
index b95a4ab..0000000
--- a/spec/unit/other/transbucket_spec.rb
+++ /dev/null
@@ -1,187 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-
-describe Puppet::TransBucket do
-  before do
-    @bucket = Puppet::TransBucket.new
-  end
-
-  it "should be able to produce a RAL component" do
-    @bucket.name = "luke"
-    @bucket.type = "foo"
-
-    resource = nil
-    proc { resource = @bucket.to_ral }.should_not raise_error
-    resource.should be_instance_of(Puppet::Type::Component)
-    resource.title.should == "Foo[luke]"
-  end
-
-  it "should accept TransObjects into its children list" do
-    object = Puppet::TransObject.new("luke", "user")
-    proc { @bucket.push(object) }.should_not raise_error
-    @bucket.each do |o|
-      o.should equal(object)
-    end
-  end
-
-  it "should accept TransBuckets into its children list" do
-    object = Puppet::TransBucket.new
-    proc { @bucket.push(object) }.should_not raise_error
-    @bucket.each do |o|
-      o.should equal(object)
-    end
-  end
-
-  it "should refuse to accept any children that are not TransObjects or TransBuckets" do
-    proc { @bucket.push "a test" }.should raise_error
-  end
-
-  it "should return use 'node' as the type and the provided name as the title if only a type is provided" do
-    @bucket.type = "mystuff"
-    @bucket.to_ref.should == "Node[mystuff]"
-  end
-
-  it "should return use 'component' as the type and the provided type as the title if only a name is provided" do
-    @bucket.name = "mystuff"
-    @bucket.to_ref.should == "Class[Mystuff]"
-  end
-
-  it "should return nil as its reference when type and name are missing" do
-    @bucket.to_ref.should be_nil
-  end
-
-  it "should return the title as its reference" do
-    @bucket.name = "luke"
-    @bucket.type = "user"
-    @bucket.to_ref.should == "User[luke]"
-  end
-
-  it "should canonize resource references when the type is 'component'" do
-    @bucket.name = 'something'
-    @bucket.type = 'foo::bar'
-
-    @bucket.to_ref.should == "Foo::Bar[something]"
-  end
-end
-
-describe Puppet::TransBucket, " when generating a catalog" do
-  before do
-    @bottom = Puppet::TransBucket.new
-    @bottom.type = "fake"
-    @bottom.name = "bottom"
-    @bottomobj = Puppet::TransObject.new("bottom", "notify")
-    @bottom.push @bottomobj
-
-    @middle = Puppet::TransBucket.new
-    @middle.type = "fake"
-    @middle.name = "middle"
-    @middleobj = Puppet::TransObject.new("middle", "notify")
-    @middle.push(@middleobj)
-    @middle.push(@bottom)
-
-    @top = Puppet::TransBucket.new
-    @top.type = "fake"
-    @top.name = "top"
-    @topobj = Puppet::TransObject.new("top", "notify")
-    @top.push(@topobj)
-    @top.push(@middle)
-
-    @users = %w{top middle bottom}
-    @fakes = %w{Fake[bottom] Fake[middle] Fake[top]}
-  end
-
-  it "should convert all transportable objects to RAL resources" do
-    @catalog = @top.to_catalog
-    @users.each do |name|
-      @catalog.vertices.find { |r| r.class.name == :notify and r.title == name }.should be_instance_of(Puppet::Type.type(:notify))
-    end
-  end
-
-  it "should fail if any transportable resources fail to convert to RAL resources" do
-    @bottomobj.expects(:to_ral).raises ArgumentError
-    lambda { @bottom.to_catalog }.should raise_error(ArgumentError)
-  end
-
-  it "should convert all transportable buckets to RAL components" do
-    @catalog = @top.to_catalog
-    @fakes.each do |name|
-      @catalog.vertices.find { |r| r.class.name == :component and r.title == name }.should be_instance_of(Puppet::Type.type(:component))
-    end
-  end
-
-  it "should add all resources to the graph's resource table" do
-    @catalog = @top.to_catalog
-    @catalog.resource("fake[top]").should equal(@top)
-  end
-
-  it "should finalize all resources" do
-    @catalog = @top.to_catalog
-    @catalog.vertices.each do |vertex| vertex.should be_finalized end
-  end
-
-  it "should only call to_ral on each resource once" do
-    # We just raise exceptions here because we're not interested in
-    # what happens with the result, only that the method only
-    # gets called once.
-    resource = @topobj.to_ral
-    @topobj.expects(:to_ral).once.returns resource
-    @top.to_catalog
-  end
-
-  it "should set each TransObject's catalog before converting to a RAL resource" do
-    @middleobj.expects(:catalog=).with { |c| c.is_a?(Puppet::Resource::Catalog) }
-    @top.to_catalog
-  end
-
-  it "should set each TransBucket's catalog before converting to a RAL resource" do
-    # each bucket is seen twice in the loop, so we have to handle the case where the config
-    # is set twice
-    @bottom.expects(:catalog=).with { |c| c.is_a?(Puppet::Resource::Catalog) }.at_least_once
-    @top.to_catalog
-  end
-end
-
-describe Puppet::TransBucket, " when serializing" do
-  before do
-    @bucket = Puppet::TransBucket.new(%w{one two})
-    @bucket.name = "one"
-    @bucket.type = "two"
-  end
-
-  it "should be able to be dumped to yaml" do
-    proc { YAML.dump(@bucket) }.should_not raise_error
-  end
-
-  it "should dump YAML that produces an equivalent object" do
-    result = YAML.dump(@bucket)
-
-    newobj = YAML.load(result)
-    newobj.name.should == "one"
-    newobj.type.should == "two"
-    children = []
-    newobj.each do |o|
-      children << o
-    end
-    children.should == %w{one two}
-  end
-end
-
-describe Puppet::TransBucket, " when converting to a Puppet::Resource" do
-  before do
-    @trans = Puppet::TransBucket.new
-    @trans.name = "foo"
-    @trans.type = "bar"
-    @trans.param(:noop, true)
-  end
-
-  it "should create a resource with the correct type and title" do
-    result = @trans.to_resource
-    result.type.should == "Bar"
-    result.title.should == "foo"
-  end
-
-  it "should add all of its parameters to the created resource" do
-    @trans.param(:noop, true)
-    @trans.to_resource[:noop].should be_true
-  end
-end
diff --git a/spec/unit/other/transobject_spec.rb b/spec/unit/other/transobject_spec.rb
deleted file mode 100755
index 4715e2f..0000000
--- a/spec/unit/other/transobject_spec.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-
-require 'puppet/transportable'
-
-describe Puppet::TransObject do
-  it "should canonize resource references" do
-    resource = Puppet::TransObject.new("me", "foo::bar")
-    resource.ref.should == 'Foo::Bar[me]'
-  end
-
-  it "should lower-case resource types for backward compatibility with 0.23.2" do
-    resource = Puppet::TransObject.new("me", "Foo")
-    resource.type.should == 'foo'
-  end
-end
-
-describe Puppet::TransObject, " when serializing" do
-  before do
-    @resource = Puppet::TransObject.new("/my/file", "file")
-    @resource["one"] = "test"
-    @resource["two"] = "other"
-  end
-
-  it "should be able to be dumped to yaml" do
-    proc { YAML.dump(@resource) }.should_not raise_error
-  end
-
-  it "should produce an equivalent yaml object" do
-    text = YAML.dump(@resource)
-
-    newresource = YAML.load(text)
-    newresource.name.should == "/my/file"
-    newresource.type.should == "file"
-    %w{one two}.each do |param|
-      newresource[param].should == @resource[param]
-    end
-  end
-end
-
-describe Puppet::TransObject, " when converting to a Puppet::Resource" do
-  before do
-    @trans = Puppet::TransObject.new("/my/file", "file")
-    @trans["one"] = "test"
-    @trans["two"] = "other"
-  end
-
-  it "should create a resource with the correct type and title" do
-    result = @trans.to_resource
-    result.type.should == "File"
-    result.title.should == "/my/file"
-  end
-
-  it "should add all of its parameters to the created resource" do
-    @trans[:noop] = true
-    @trans.to_resource[:noop].should be_true
-  end
-
-  it "should copy over the tags" do
-    @trans.tags = %w{foo bar}
-    result = @trans.to_resource
-    result.should be_tagged("foo")
-    result.should be_tagged("bar")
-  end
-end
-
-describe Puppet::TransObject, " when converting to a RAL resource" do
-  before do
-    @resource = Puppet::TransObject.new("/my/file", "file")
-    @resource["one"] = "test"
-    @resource["two"] = "other"
-  end
-
-  it "should use a Puppet::Resource to create the resource" do
-    resource = mock 'resource'
-    @resource.expects(:to_resource).returns resource
-    resource.expects(:to_ral).returns "myral"
-    @resource.to_ral.should == "myral"
-  end
-end
-
-describe Puppet::TransObject, " when converting to a RAL component instance" do
-  before do
-    @resource = Puppet::TransObject.new("/my/file", "one::two")
-    @resource["one"] = "test"
-    @resource["noop"] = "other"
-  end
-
-  it "should use a new TransObject whose name is a resource reference of the type and title of the original TransObject" do
-    Puppet::Type::Component.expects(:new).with { |resource| resource.type == "component" and resource.name == "One::Two[/my/file]" }.returns(:yay)
-    @resource.to_component.should == :yay
-  end
-
-  it "should pass the resource parameters on to the newly created TransObject" do
-    Puppet::Type::Component.expects(:new).with { |resource| resource["noop"] == "other" }.returns(:yay)
-    @resource.to_component.should == :yay
-  end
-
-  it "should copy over the catalog" do
-    @resource.catalog = "mycat"
-    Puppet::Type::Component.expects(:new).with { |resource| resource.catalog == "mycat" }.returns(:yay)
-    @resource.to_component
-  end
-
-  # LAK:FIXME This really isn't the design we want going forward, but it's
-  # good enough for now.
-  it "should not pass resource parameters that are not metaparams" do
-    Puppet::Type::Component.expects(:new).with { |resource| resource["one"].nil? }.returns(:yay)
-    @resource.to_component.should == :yay
-  end
-end
diff --git a/spec/unit/parser/ast/casestatement_spec.rb b/spec/unit/parser/ast/casestatement_spec.rb
index e211907..a76a9ae 100755
--- a/spec/unit/parser/ast/casestatement_spec.rb
+++ b/spec/unit/parser/ast/casestatement_spec.rb
@@ -154,7 +154,7 @@
     tests.each do |should, values|
       values.each do |value|
         @scope = Puppet::Parser::Scope.new
-        @scope.setvar("testparam", value)
+        @scope['testparam'] = value
         result = ast.evaluate(@scope)
 
         result.should == should
diff --git a/spec/unit/parser/ast/leaf_spec.rb b/spec/unit/parser/ast/leaf_spec.rb
index ff3fed5..0dfda37 100755
--- a/spec/unit/parser/ast/leaf_spec.rb
+++ b/spec/unit/parser/ast/leaf_spec.rb
@@ -3,7 +3,7 @@
 
 describe Puppet::Parser::AST::Leaf do
   before :each do
-    @scope = stub 'scope'
+    @scope = Puppet::Parser::Scope.new
     @value = stub 'value'
     @leaf = Puppet::Parser::AST::Leaf.new(:value => @value)
   end
@@ -56,7 +56,7 @@
 describe Puppet::Parser::AST::Concat do
   describe "when evaluating" do
     before :each do
-      @scope = stub_everything 'scope'
+      @scope = Puppet::Parser::Scope.new
     end
     it "should interpolate variables and concatenate their values" do
       one = Puppet::Parser::AST::String.new(:value => "one")
@@ -86,7 +86,7 @@
 
 describe Puppet::Parser::AST::Undef do
   before :each do
-    @scope = stub 'scope'
+    @scope = Puppet::Parser::Scope.new
     @undef = Puppet::Parser::AST::Undef.new(:value => :undef)
   end
 
@@ -101,12 +101,12 @@
 
 describe Puppet::Parser::AST::HashOrArrayAccess do
   before :each do
-    @scope = stub 'scope'
+    @scope = Puppet::Parser::Scope.new
   end
 
   describe "when evaluating" do
     it "should evaluate the variable part if necessary" do
-      @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["b"])
+      @scope["a"] = ["b"]
 
       variable = stub 'variable', :evaluate => "a"
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => variable, :key => 0 )
@@ -117,7 +117,7 @@
     end
 
     it "should evaluate the access key part if necessary" do
-      @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["b"])
+      @scope["a"] = ["b"]
 
       index = stub 'index', :evaluate => 0
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => index )
@@ -128,7 +128,7 @@
     end
 
     it "should be able to return an array member" do
-      @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["val1", "val2", "val3"])
+      @scope["a"] = %w{val1 val2 val3}
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 1 )
 
@@ -136,7 +136,7 @@
     end
 
     it "should be able to return an array member when index is a stringified number" do
-      @scope.stubs(:lookupvar).with { |name,options| name == "a" }.returns(["val1", "val2", "val3"])
+      @scope["a"] = %w{val1 val2 val3}
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "1" )
 
@@ -144,23 +144,39 @@
     end
 
     it "should raise an error when accessing an array with a key" do
-      @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns(["val1", "val2", "val3"])
+      @scope["a"] = ["val1", "val2", "val3"]
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" )
 
       lambda { access.evaluate(@scope) }.should raise_error
     end
 
+    it "should be able to return :undef for an unknown array index" do
+      @scope["a"] = ["val1", "val2", "val3"]
+
+      access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 6 )
+
+      access.evaluate(@scope).should == :undef
+    end
+
     it "should be able to return an hash value" do
-      @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key1" => "val1", "key2" => "val2", "key3" => "val3" })
+      @scope["a"] = { "key1" => "val1", "key2" => "val2", "key3" => "val3" }
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" )
 
       access.evaluate(@scope).should == "val2"
     end
 
+    it "should be able to return :undef for unknown hash keys" do
+      @scope["a"] = { "key1" => "val1", "key2" => "val2", "key3" => "val3" }
+
+      access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key12" )
+
+      access.evaluate(@scope).should == :undef
+    end
+
     it "should be able to return an hash value with a numerical key" do
-      @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns({ "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" })
+      @scope["a"] = { "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" }
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "45" )
 
@@ -168,7 +184,7 @@
     end
 
     it "should raise an error if the variable lookup didn't return an hash or an array" do
-      @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns("I'm a string")
+      @scope["a"] = "I'm a string"
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" )
 
@@ -176,8 +192,6 @@
     end
 
     it "should raise an error if the variable wasn't in the scope" do
-      @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(nil)
-
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" )
 
       lambda { access.evaluate(@scope) }.should raise_error
@@ -189,7 +203,7 @@
     end
 
     it "should work with recursive hash access" do
-      @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key" => { "subkey" => "b" }})
+      @scope["a"] = { "key" => { "subkey" => "b" }}
 
       access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key")
       access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => "subkey")
@@ -198,7 +212,7 @@
     end
 
     it "should work with interleaved array and hash access" do
-      @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key" => [ "a" , "b" ]})
+      @scope['a'] = { "key" => [ "a" , "b" ]}
 
       access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key")
       access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => 1)
@@ -210,16 +224,16 @@
   describe "when assigning" do
     it "should add a new key and value" do
       scope = Puppet::Parser::Scope.new
-      scope.setvar("a", { 'a' => 'b' })
+      scope['a'] = { 'a' => 'b' }
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "b")
       access.assign(scope, "c" )
 
-      scope.lookupvar("a").should be_include("b")
+      scope['a'].should be_include("b")
     end
 
     it "should raise an error when assigning an array element with a key" do
-      @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns([])
+      @scope['a'] = []
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" )
 
@@ -228,16 +242,16 @@
 
     it "should be able to return an array member when index is a stringified number" do
       scope = Puppet::Parser::Scope.new
-      scope.setvar("a", [])
+      scope['a'] = []
 
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "0" )
 
       access.assign(scope, "val2")
-      scope.lookupvar("a").should == ["val2"]
+      scope['a'].should == ["val2"]
     end
 
     it "should raise an error when trying to overwrite an hash value" do
-      @scope.stubs(:lookupvar).with { |name,options| name == "a" }.returns({ "key" => [ "a" , "b" ]})
+      @scope['a'] = { "key" => [ "a" , "b" ]}
       access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key")
 
       lambda { access.assign(@scope, "test") }.should raise_error
@@ -247,7 +261,7 @@
 
 describe Puppet::Parser::AST::Regex do
   before :each do
-    @scope = stub 'scope'
+    @scope = Puppet::Parser::Scope.new
   end
 
   describe "when initializing" do
@@ -330,22 +344,21 @@
 
 describe Puppet::Parser::AST::Variable do
   before :each do
-    @scope = stub 'scope'
+    @scope = Puppet::Parser::Scope.new
     @var = Puppet::Parser::AST::Variable.new(:value => "myvar", :file => 'my.pp', :line => 222)
   end
 
   it "should lookup the variable in scope" do
-    @scope.expects(:lookupvar).with { |name,options| name == "myvar" }.returns(:myvalue)
+    @scope["myvar"] = :myvalue
     @var.safeevaluate(@scope).should == :myvalue
   end
 
   it "should pass the source location to lookupvar" do
-    @scope.expects(:lookupvar).with { |name,options| name == "myvar" and options[:file] == 'my.pp' and options[:line] == 222 }.returns(:myvalue)
+    @scope.setvar("myvar", :myvalue, :file => 'my.pp', :line => 222 )
     @var.safeevaluate(@scope).should == :myvalue
   end
 
   it "should return undef if the variable wasn't set" do
-    @scope.expects(:lookupvar).with { |name,options| name == "myvar" }.returns(:undefined)
     @var.safeevaluate(@scope).should == :undef
   end
 
@@ -359,7 +372,7 @@
 
 describe Puppet::Parser::AST::HostName do
   before :each do
-    @scope = stub 'scope'
+    @scope = Puppet::Parser::Scope.new
     @value = stub 'value', :=~ => false
     @value.stubs(:to_s).returns(@value)
     @value.stubs(:downcase).returns(@value)
diff --git a/spec/unit/parser/ast/resource_reference_spec.rb b/spec/unit/parser/ast/resource_reference_spec.rb
index 4d1c191..4e069cc 100755
--- a/spec/unit/parser/ast/resource_reference_spec.rb
+++ b/spec/unit/parser/ast/resource_reference_spec.rb
@@ -36,7 +36,7 @@ def newref(type, title)
   end
 
   it "should return an array of resources if given a variable containing an array of titles" do
-    @scope.setvar("my_files", ["foo", "bar"])
+    @scope["my_files"] = ["foo", "bar"]
     titles = Puppet::Parser::AST::Variable.new(:value => "my_files")
     ref = newref('File', titles)
     ref.evaluate(@scope).should == [
diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb
index 2478d27..411d1b8 100755
--- a/spec/unit/parser/compiler_spec.rb
+++ b/spec/unit/parser/compiler_spec.rb
@@ -179,8 +179,8 @@ def compile_stub(*except)
       @node.stubs(:parameters).returns(params)
       compile_stub(:set_node_parameters)
       @compiler.compile
-      @compiler.topscope.lookupvar("a").should == "b"
-      @compiler.topscope.lookupvar("c").should == "d"
+      @compiler.topscope['a'].should == "b"
+      @compiler.topscope['c'].should == "d"
     end
 
     it "should set the client and server versions on the catalog" do
@@ -573,42 +573,62 @@ def add_resource(name, parent = nil)
       @compiler.evaluate_classes(%w{myclass}, @scope)
     end
 
-    it "should ensure each node class hash is in catalog and have appropriate parameters", :'fails_on_ruby_1.9.2' => true do
-      klasses = {'foo'=>{'1'=>'one'}, 'bar::foo'=>{'2'=>'two'}, 'bar'=>{'1'=> [1,2,3], '2'=>{'foo'=>'bar'}}}
-      @node.classes = klasses
-      ast_obj = Puppet::Parser::AST::String.new(:value => 'foo')
-      klasses.each do |name, params|
-        klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj})
+    describe "and the classes are specified as a hash with parameters" do
+      before do
+        @node.classes = {}
+        @ast_obj = Puppet::Parser::AST::String.new(:value => 'foo')
+      end
+
+      # Define the given class with default parameters
+      def define_class(name, parameters)
+        @node.classes[name] = parameters
+        klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => @ast_obj, '2' => @ast_obj})
         @compiler.topscope.known_resource_types.add klass
       end
-      catalog = @compiler.compile
-      catalog.classes.should =~ ['foo', 'bar::foo', 'settings', 'bar']
 
-      r1 = catalog.resources.detect {|r| r.title == 'Foo' }
-      r1.to_hash.should == {:'1' => 'one', :'2' => 'foo'}
-      r1.tags. should =~ ['class', 'foo']
+      def compile
+        @catalog = @compiler.compile
+      end
 
-      r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' }
-      r2.to_hash.should == {:'1' => 'foo', :'2' => 'two'}
-      r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo']
+      it "should record which classes are evaluated" do
+        classes = {'foo'=>{}, 'bar::foo'=>{}, 'bar'=>{}}
+        classes.each { |c, params| define_class(c, params) }
+        compile()
+        classes.each { |name, p| @catalog.classes.should include(name) }
+      end
 
-      r2 = catalog.resources.detect {|r| r.title == 'Bar' }
-      r2.to_hash.should == {:'1' => [1,2,3], :'2' => {'foo'=>'bar'}}
-      r2.tags.should =~ ['class', 'bar']
-    end
+      it "should provide default values for parameters that have no values specified" do
+        define_class('foo', {})
+        compile()
+        @catalog.resource(:class, 'foo')['1'].should == "foo"
+      end
 
-    it "should ensure each node class is in catalog and has appropriate tags", :'fails_on_ruby_1.9.2' => true do
-      klasses = ['bar::foo']
-      @node.classes = klasses
-      ast_obj = Puppet::Parser::AST::String.new(:value => 'foo')
-      klasses.each do |name|
-        klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj})
-        @compiler.topscope.known_resource_types.add klass
+      it "should use any provided values" do
+        define_class('foo', {'1' => 'real_value'})
+        compile()
+        @catalog.resource(:class, 'foo')['1'].should == "real_value"
+      end
+
+      it "should support providing some but not all values" do
+        define_class('foo', {'1' => 'real_value'})
+        compile()
+        @catalog.resource(:class, 'Foo')['1'].should == "real_value"
+        @catalog.resource(:class, 'Foo')['2'].should == "foo"
       end
-      catalog = @compiler.compile
 
-      r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' }
-      r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo']
+      it "should ensure each node class is in catalog and has appropriate tags", :'fails_on_ruby_1.9.2' => true do
+        klasses = ['bar::foo']
+        @node.classes = klasses
+        ast_obj = Puppet::Parser::AST::String.new(:value => 'foo')
+        klasses.each do |name|
+          klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj})
+          @compiler.topscope.known_resource_types.add klass
+        end
+        catalog = @compiler.compile
+
+        r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' }
+        r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo']
+      end
     end
 
     it "should fail if required parameters are missing" do
@@ -616,15 +636,15 @@ def add_resource(name, parent = nil)
       @node.classes = klass
       klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil})
       @compiler.topscope.known_resource_types.add klass
-      lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Must pass 2 to Class[Foo]"
+      lambda { @compiler.compile }.should raise_error(Puppet::ParseError, "Must pass 2 to Class[Foo]")
     end
 
     it "should fail if invalid parameters are passed" do
       klass = {'foo'=>{'3'=>'one'}}
       @node.classes = klass
-      klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil})
+      klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {})
       @compiler.topscope.known_resource_types.add klass
-      lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Invalid parameter 3"
+      lambda { @compiler.compile }.should raise_error(Puppet::ParseError, "Invalid parameter 3")
     end
 
     it "should ensure class is in catalog without params" do
diff --git a/spec/unit/parser/functions/create_resources_spec.rb b/spec/unit/parser/functions/create_resources_spec.rb
index da76e75..b833681 100755
--- a/spec/unit/parser/functions/create_resources_spec.rb
+++ b/spec/unit/parser/functions/create_resources_spec.rb
@@ -20,8 +20,9 @@ def get_scope
   it "should exist" do
     Puppet::Parser::Functions.function(:create_resources).should == "function_create_resources"
   end
-  it 'should require two arguments' do
-    lambda { @scope.function_create_resources(['foo']) }.should raise_error(ArgumentError, 'create_resources(): wrong number of arguments (1; must be 2)')
+  it 'should require two or three arguments' do
+    lambda { @scope.function_create_resources(['foo']) }.should raise_error(ArgumentError, 'create_resources(): wrong number of arguments (1; must be 2 or 3)')
+    lambda { @scope.function_create_resources(['foo', 'bar', 'blah', 'baz']) }.should raise_error(ArgumentError, 'create_resources(): wrong number of arguments (4; must be 2 or 3)')
   end
   describe 'when creating native types' do
     before :each do
@@ -58,6 +59,11 @@ def get_scope
       foo.should be
       rg.path_between(test,foo).should be
     end
+    it 'should account for default values' do
+      @scope.function_create_resources(['file', {'/etc/foo'=>{'ensure'=>'present'}, '/etc/baz'=>{'group'=>'food'}}, {'group' => 'bar'}])
+      @compiler.catalog.resource(:file, "/etc/foo")['group'].should == 'bar'
+      @compiler.catalog.resource(:file, "/etc/baz")['group'].should == 'food'
+    end
   end
   describe 'when dynamically creating resource types' do
     before :each do 
@@ -78,7 +84,7 @@ def get_scope
     end
     it 'should fail if defines are missing params' do
       @scope.function_create_resources(['foo', {'blah'=>{}}])
-      lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, 'Must pass one to Foo[blah] at line 1')
+      lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /Must pass one to Foo\[blah\]/)
     end
     it 'should be able to add multiple defines' do
       hash = {}
@@ -103,6 +109,11 @@ def get_scope
       rg.path_between(test,blah).should be
       @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
     end
+    it 'should account for default values' do
+      @scope.function_create_resources(['foo', {'blah'=>{}}, {'one' => 'two'}])
+      @scope.compiler.compile
+      @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
+    end
   end
   describe 'when creating classes' do
     before :each do
@@ -114,7 +125,7 @@ def get_scope
       @scope.resource=Puppet::Parser::Resource.new('class', 't', :scope => @scope)
       Puppet::Parser::Functions.function(:create_resources)
     end
-    it 'should be able to create classes', :'fails_on_ruby_1.9.2' => true do
+    it 'should be able to create classes' do
       @scope.function_create_resources(['class', {'bar'=>{'one'=>'two'}}])
       @scope.compiler.compile
       @compiler.catalog.resource(:notify, "test")['message'].should == 'two'
@@ -123,7 +134,7 @@ def get_scope
     it 'should fail to create non-existing classes' do
       lambda { @scope.function_create_resources(['class', {'blah'=>{'one'=>'two'}}]) }.should raise_error(ArgumentError ,'could not find hostclass blah')
     end
-    it 'should be able to add edges', :'fails_on_ruby_1.9.2' => true do
+    it 'should be able to add edges' do
       @scope.function_create_resources(['class', {'bar'=>{'one'=>'two', 'require' => 'Notify[tester]'}}])
       @scope.compiler.compile
       rg = @scope.compiler.catalog.to_ral.relationship_graph
@@ -133,5 +144,11 @@ def get_scope
       tester.should be
       rg.path_between(tester,test).should be
     end
+    it 'should account for default values' do
+      @scope.function_create_resources(['class', {'bar'=>{}}, {'one' => 'two'}])
+      @scope.compiler.compile
+      @compiler.catalog.resource(:notify, "test")['message'].should == 'two'
+      @compiler.catalog.resource(:class, "bar").should_not be_nil#['message'].should == 'two'
+    end
   end
 end
diff --git a/spec/unit/parser/functions/extlookup_spec.rb b/spec/unit/parser/functions/extlookup_spec.rb
index 486e7cb..59ecf39 100755
--- a/spec/unit/parser/functions/extlookup_spec.rb
+++ b/spec/unit/parser/functions/extlookup_spec.rb
@@ -67,7 +67,7 @@
   describe "should look in $extlookup_datadir for data files listed by $extlookup_precedence" do
     before do
       dir = tmpdir('extlookup_datadir')
-      @scope.stubs(:lookupvar).with('::extlookup_datadir').returns(dir)
+      @scope.stubs(:[]).with('::extlookup_datadir').returns(dir)
       File.open(File.join(dir, "one.csv"),"w"){|one| one.puts "key,value1" }
       File.open(File.join(dir, "two.csv"),"w") do |two|
         two.puts "key,value2"
@@ -76,21 +76,21 @@
     end
 
     it "when the key is in the first file" do
-      @scope.stubs(:lookupvar).with('::extlookup_precedence').returns(["one","two"])
+      @scope.stubs(:[]).with('::extlookup_precedence').returns(["one","two"])
       result = @scope.function_extlookup([ "key" ])
       result.should == "value1"
     end
 
     it "when the key is in the second file" do
-      @scope.stubs(:lookupvar).with('::extlookup_precedence').returns(["one","two"])
+      @scope.stubs(:[]).with('::extlookup_precedence').returns(["one","two"])
       result = @scope.function_extlookup([ "key2" ])
       result.should == "value_two"
     end
 
     it "should not modify extlookup_precedence data" do
       variable = '%{fqdn}'
-      @scope.stubs(:lookupvar).with('::extlookup_precedence').returns([variable,"one"])
-      @scope.stubs(:lookupvar).with('::fqdn').returns('myfqdn')
+      @scope.stubs(:[]).with('::extlookup_precedence').returns([variable,"one"])
+      @scope.stubs(:[]).with('::fqdn').returns('myfqdn')
       result = @scope.function_extlookup([ "key" ])
       variable.should == '%{fqdn}'
     end
diff --git a/spec/unit/parser/functions/fqdn_rand_spec.rb b/spec/unit/parser/functions/fqdn_rand_spec.rb
index 90fc0ef..53c4984 100755
--- a/spec/unit/parser/functions/fqdn_rand_spec.rb
+++ b/spec/unit/parser/functions/fqdn_rand_spec.rb
@@ -8,6 +8,7 @@
 
   before :each do
     @scope = Puppet::Parser::Scope.new
+    @scope[:fqdn] = "127.0.0.1"
   end
 
   it "should exist" do
@@ -15,49 +16,40 @@
   end
 
   it "should handle 0 arguments" do
-    @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
     lambda { @scope.function_fqdn_rand([]) }.should_not raise_error(Puppet::ParseError)
   end
 
   it "should handle 1 argument'}" do
-    @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
     lambda { @scope.function_fqdn_rand([3]) }.should_not raise_error(Puppet::ParseError)
   end
 
 
   (1..10).each { |n|
     it "should handle #{n} additional arguments" do
-      @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
       lambda { @scope.function_fqdn_rand([3,1,2,3,4,5,6,7,8,9,10][0..n]) }.should_not raise_error(Puppet::ParseError)
     end
     it "should handle #{n} additional string arguments" do
-      @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
       lambda { @scope.function_fqdn_rand([3,%w{ 1 2 3 4 5 6 7 8 9 10}].flatten[0..n]) }.should_not raise_error(Puppet::ParseError)
     end
   }
 
   it "should return a value less than max" do
-    @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
     @scope.function_fqdn_rand([3]).should satisfy {|n| n.to_i < 3 }
   end
 
   it "should return the same values on subsequent invocations for the same host" do
-    @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice
     @scope.function_fqdn_rand([3,4]).should eql(@scope.function_fqdn_rand([3, 4]))
   end
 
   it "should return different sequences of value for different hosts" do
-    @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
     val1 = @scope.function_fqdn_rand([10000000,4])
-    @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.2")
+    @scope.expects(:[]).with("::fqdn").returns("127.0.0.2")
     val2 = @scope.function_fqdn_rand([10000000,4])
     val1.should_not eql(val2)
   end
 
   it "should return different values for the same hosts with different seeds" do
-    @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
     val1 = @scope.function_fqdn_rand([10000000,4])
-    @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
     val2 = @scope.function_fqdn_rand([10000000,42])
     val1.should_not eql(val2)
   end
diff --git a/spec/unit/parser/functions_spec.rb b/spec/unit/parser/functions_spec.rb
index 8240a18..7eb6f29 100755
--- a/spec/unit/parser/functions_spec.rb
+++ b/spec/unit/parser/functions_spec.rb
@@ -20,13 +20,17 @@
   end
 
   it "should have a method for returning an environment-specific module" do
-    Puppet::Parser::Functions.environment_module("myenv").should be_instance_of(Module)
+    Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.new("myenv")).should be_instance_of(Module)
   end
 
   it "should use the current default environment if no environment is provided" do
     Puppet::Parser::Functions.environment_module.should be_instance_of(Module)
   end
 
+  it "should be able to retrieve environment modules asked for by name rather than instance" do
+    Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.new("myenv")).should equal(Puppet::Parser::Functions.environment_module("myenv"))
+  end
+
   describe "when calling newfunction" do
     before do
       @module = Module.new
diff --git a/spec/unit/parser/resource_spec.rb b/spec/unit/parser/resource_spec.rb
index 1190716..db6dbc3 100755
--- a/spec/unit/parser/resource_spec.rb
+++ b/spec/unit/parser/resource_spec.rb
@@ -271,7 +271,7 @@ def newnode(name)
     end
 
     it "should not copy relationship metaparams when not in metaparam compatibility mode" do
-      @scope.setvar("require", "bar")
+      @scope['require'] = "bar"
 
       @resource.stubs(:metaparam_compatibility_mode?).returns false
       @resource.class.publicize_methods(:add_metaparams)  { @resource.add_metaparams }
@@ -280,7 +280,7 @@ def newnode(name)
     end
 
     it "should copy relationship metaparams when in metaparam compatibility mode" do
-      @scope.setvar("require", "bar")
+      @scope['require'] = "bar"
 
       @resource.stubs(:metaparam_compatibility_mode?).returns true
       @resource.class.publicize_methods(:add_metaparams)  { @resource.add_metaparams }
@@ -290,7 +290,7 @@ def newnode(name)
 
     it "should stack relationship metaparams when in metaparam compatibility mode" do
       @resource.set_parameter("require", "foo")
-      @scope.setvar("require", "bar")
+      @scope['require'] = "bar"
 
       @resource.stubs(:metaparam_compatibility_mode?).returns true
       @resource.class.publicize_methods(:add_metaparams)  { @resource.add_metaparams }
@@ -452,26 +452,6 @@ def newnode(name)
     @resource.should respond_to(:to_resource)
   end
 
-  it "should use its resource converter to convert to a transportable resource" do
-    @source = stub 'scope', :name => "myscope"
-    @resource = mkresource :source => @source
-
-    newresource = Puppet::Resource.new(:file, "/my")
-    Puppet::Resource.expects(:new).returns(newresource)
-
-    newresource.expects(:to_trans).returns "mytrans"
-
-    @resource.to_trans.should == "mytrans"
-  end
-
-  it "should return nil if converted to a transportable resource and it is virtual" do
-    @source = stub 'scope', :name => "myscope"
-    @resource = mkresource :source => @source
-
-    @resource.expects(:virtual?).returns true
-    @resource.to_trans.should be_nil
-  end
-
   describe "when being converted to a resource" do
     before do
       @parser_resource = mkresource :scope => @scope, :parameters => {:foo => "bar", :fee => "fum"}
diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb
index 67f0db0..2d4f375 100755
--- a/spec/unit/parser/scope_spec.rb
+++ b/spec/unit/parser/scope_spec.rb
@@ -42,12 +42,16 @@
   end
 
   it "should get its environment from its compiler" do
-    env = stub 'environment'
+    env = Puppet::Node::Environment.new
     compiler = stub 'compiler', :environment => env
     scope = Puppet::Parser::Scope.new :compiler => compiler
     scope.environment.should equal(env)
   end
 
+  it "should use the default environment if none is available" do
+    Puppet::Parser::Scope.new.environment.should equal(Puppet::Node::Environment.new)
+  end
+
   it "should use the resource type collection helper to find its known resource types" do
     Puppet::Parser::Scope.ancestors.should include(Puppet::Resource::TypeCollectionHelper)
   end
@@ -75,22 +79,18 @@
   describe "when initializing" do
     it "should extend itself with its environment's Functions module as well as the default" do
       env = Puppet::Node::Environment.new("myenv")
+      root = Puppet::Node::Environment.root
       compiler = stub 'compiler', :environment => env
-      mod      = Module.new
-      root_mod = Module.new
-      Puppet::Parser::Functions.expects(:environment_module).with(Puppet::Node::Environment.root).returns root_mod
-      Puppet::Parser::Functions.expects(:environment_module).with(env).returns mod
 
-      Puppet::Parser::Scope.new(:compiler => compiler).singleton_class.ancestors.should be_include(mod)
+      scope = Puppet::Parser::Scope.new(:compiler => compiler)
+      scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(env))
+      scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(root))
     end
 
-    it "should extend itself with the default Functions module if it has no environment" do
-      mod = Module.new
-      Puppet::Parser::Functions.expects(:environment_module).with(Puppet::Node::Environment.root).returns(mod)
-
-      Puppet::Parser::Functions.expects(:environment_module).with(nil).returns mod
-
-      Puppet::Parser::Scope.new.singleton_class.ancestors.should be_include(mod)
+    it "should extend itself with the default Functions module if its environment is the default" do
+      root = Puppet::Node::Environment.root
+      scope = Puppet::Parser::Scope.new
+      scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(root))
     end
 
     it "should remember if it is dynamic" do
@@ -103,29 +103,55 @@
   end
 
   describe "when looking up a variable" do
-    it "should return ':undefined' for unset variables" do
-      @scope.lookupvar("var").should == :undefined
+    it "should support :lookupvar and :setvar for backward compatibility" do
+      @scope.setvar("var", "yep")
+      @scope.lookupvar("var").should == "yep"
+    end
+
+    it "should return nil for unset variables" do
+      @scope["var"].should be_nil
     end
 
     it "should be able to look up values" do
-      @scope.setvar("var", "yep")
-      @scope.lookupvar("var").should == "yep"
+      @scope["var"] = "yep"
+      @scope["var"].should == "yep"
     end
 
     it "should be able to look up hashes" do
-      @scope.setvar("var", {"a" => "b"})
-      @scope.lookupvar("var").should == {"a" => "b"}
+      @scope["var"] = {"a" => "b"}
+      @scope["var"].should == {"a" => "b"}
     end
 
     it "should be able to look up variables in parent scopes" do
-      @topscope.setvar("var", "parentval")
-      @scope.lookupvar("var").should == "parentval"
+      @topscope["var"] = "parentval"
+      @scope["var"].should == "parentval"
     end
 
     it "should prefer its own values to parent values" do
-      @topscope.setvar("var", "parentval")
-      @scope.setvar("var", "childval")
-      @scope.lookupvar("var").should == "childval"
+      @topscope["var"] = "parentval"
+      @scope["var"] = "childval"
+      @scope["var"].should == "childval"
+    end
+
+    it "should be able to detect when variables are set" do
+      @scope["var"] = "childval"
+      @scope.should be_include("var")
+    end
+
+    it "should be able to detect when variables are not set" do
+      @scope.should_not be_include("var")
+    end
+
+    it "should support iteration over its variables" do
+      @scope["one"] = "two"
+      @scope["three"] = "four"
+      hash = {}
+      @scope.each { |name, value| hash[name] = value }
+      hash.should == {"one" => "two", "three" => "four" }
+    end
+
+    it "should include Enumerable" do
+      @scope.singleton_class.ancestors.should be_include(Enumerable)
     end
 
     describe "and the variable is qualified" do
@@ -153,84 +179,84 @@ def create_class_scope(name)
       it "should be able to look up explicitly fully qualified variables from main" do
         other_scope = create_class_scope("")
 
-        other_scope.setvar("othervar", "otherval")
+        other_scope["othervar"] = "otherval"
 
-        @scope.lookupvar("::othervar").should == "otherval"
+        @scope["::othervar"].should == "otherval"
       end
 
       it "should be able to look up explicitly fully qualified variables from other scopes" do
         other_scope = create_class_scope("other")
 
-        other_scope.setvar("var", "otherval")
+        other_scope["var"] = "otherval"
 
-        @scope.lookupvar("::other::var").should == "otherval"
+        @scope["::other::var"].should == "otherval"
       end
 
       it "should be able to look up deeply qualified variables" do
         other_scope = create_class_scope("other::deep::klass")
 
-        other_scope.setvar("var", "otherval")
+        other_scope["var"] = "otherval"
 
-        @scope.lookupvar("other::deep::klass::var").should == "otherval"
+        @scope["other::deep::klass::var"].should == "otherval"
       end
 
-      it "should return ':undefined' for qualified variables that cannot be found in other classes" do
+      it "should return nil for qualified variables that cannot be found in other classes" do
         other_scope = create_class_scope("other::deep::klass")
 
-        @scope.lookupvar("other::deep::klass::var").should == :undefined
+        @scope["other::deep::klass::var"].should be_nil
       end
 
-      it "should warn and return ':undefined' for qualified variables whose classes have not been evaluated" do
+      it "should warn and return nil for qualified variables whose classes have not been evaluated" do
         klass = newclass("other::deep::klass")
         @scope.expects(:warning)
-        @scope.lookupvar("other::deep::klass::var").should == :undefined
+        @scope["other::deep::klass::var"].should be_nil
       end
 
-      it "should warn and return ':undefined' for qualified variables whose classes do not exist" do
+      it "should warn and return nil for qualified variables whose classes do not exist" do
         @scope.expects(:warning)
-        @scope.lookupvar("other::deep::klass::var").should == :undefined
+        @scope["other::deep::klass::var"].should be_nil
       end
 
-      it "should return ':undefined' when asked for a non-string qualified variable from a class that does not exist" do
+      it "should return nil when asked for a non-string qualified variable from a class that does not exist" do
         @scope.stubs(:warning)
-        @scope.lookupvar("other::deep::klass::var").should == :undefined
+        @scope["other::deep::klass::var"].should be_nil
       end
 
-      it "should return ':undefined' when asked for a non-string qualified variable from a class that has not been evaluated" do
+      it "should return nil when asked for a non-string qualified variable from a class that has not been evaluated" do
         @scope.stubs(:warning)
         klass = newclass("other::deep::klass")
-        @scope.lookupvar("other::deep::klass::var").should == :undefined
+        @scope["other::deep::klass::var"].should be_nil
       end
     end
   end
 
-  describe "when setvar is called with append=true" do
-    it "should raise error if the variable is already defined in this scope" do
+  describe "when variables are set with append=true" do
+    it "should raise an error if the variable is already defined in this scope" do
       @scope.setvar("var","1", :append => false)
       lambda { @scope.setvar("var","1", :append => true) }.should raise_error(Puppet::ParseError)
     end
 
     it "should lookup current variable value" do
-      @scope.expects(:lookupvar).with("var").returns("2")
+      @scope.expects(:[]).with("var").returns("2")
       @scope.setvar("var","1", :append => true)
     end
 
     it "should store the concatenated string '42'" do
       @topscope.setvar("var","4", :append => false)
       @scope.setvar("var","2", :append => true)
-      @scope.lookupvar("var").should == "42"
+      @scope["var"].should == "42"
     end
 
     it "should store the concatenated array [4,2]" do
       @topscope.setvar("var",[4], :append => false)
       @scope.setvar("var",[2], :append => true)
-      @scope.lookupvar("var").should == [4,2]
+      @scope["var"].should == [4,2]
     end
 
     it "should store the merged hash {a => b, c => d}" do
       @topscope.setvar("var",{"a" => "b"}, :append => false)
       @scope.setvar("var",{"c" => "d"}, :append => true)
-      @scope.lookupvar("var").should == {"a" => "b", "c" => "d"}
+      @scope["var"].should == {"a" => "b", "c" => "d"}
     end
 
     it "should raise an error when appending a hash with something other than another hash" do
@@ -305,7 +331,7 @@ def create_class_scope(name)
     it "should store the variable value" do
       @scope.setvar("1", :value, :ephemeral => true)
 
-      @scope.lookupvar("1").should == :value
+      @scope["1"].should == :value
     end
 
     it "should remove the variable value when unset_ephemeral_var is called" do
@@ -314,17 +340,17 @@ def create_class_scope(name)
 
       @scope.unset_ephemeral_var
 
-      @scope.lookupvar("1").should == :undefined
+      @scope["1"].should be_nil
     end
 
     it "should not remove classic variables when unset_ephemeral_var is called" do
-      @scope.setvar("myvar", :value1)
+      @scope['myvar'] = :value1
       @scope.setvar("1", :value2, :ephemeral => true)
       @scope.stubs(:parent).returns(nil)
 
       @scope.unset_ephemeral_var
 
-      @scope.lookupvar("myvar").should == :value1
+      @scope["myvar"].should == :value1
     end
 
     it "should raise an error when setting it again" do
@@ -345,7 +371,7 @@ def create_class_scope(name)
         @scope.setvar("0", :earliest, :ephemeral => true)
         @scope.new_ephemeral
         @scope.setvar("0", :latest, :ephemeral => true)
-        @scope.lookupvar("0").should == :latest
+        @scope["0"].should == :latest
       end
 
       it "should be able to report the current level" do
@@ -376,7 +402,7 @@ def create_class_scope(name)
         @scope.setvar("1", :value1, :ephemeral => true)
         @scope.new_ephemeral
         @scope.setvar("0", :value2, :ephemeral => true)
-        @scope.lookupvar("1").should == :value1
+        @scope["1"].should == :value1
       end
 
       describe "when calling unset_ephemeral_var without a level" do
@@ -387,7 +413,7 @@ def create_class_scope(name)
 
           @scope.unset_ephemeral_var
 
-          @scope.lookupvar("1").should == :undefined
+          @scope["1"].should be_nil
         end
       end
 
@@ -401,7 +427,7 @@ def create_class_scope(name)
 
           @scope.unset_ephemeral_var(2)
 
-          @scope.lookupvar("1").should == :value2
+          @scope["1"].should == :value2
         end
       end
     end
@@ -441,22 +467,22 @@ def create_class_scope(name)
 
   describe "when unsetting variables" do
     it "should be able to unset normal variables" do
-      @scope.setvar("foo", "bar")
+      @scope["foo"] = "bar"
       @scope.unsetvar("foo")
-      @scope.lookupvar("foo").should == :undefined
+      @scope["foo"].should be_nil
     end
 
     it "should be able to unset ephemeral variables" do
       @scope.setvar("0", "bar", :ephemeral => true)
       @scope.unsetvar("0")
-      @scope.lookupvar("0").should == :undefined
+      @scope["0"].should be_nil
     end
 
     it "should not unset ephemeral variables in previous ephemeral scope" do
       @scope.setvar("0", "bar", :ephemeral => true)
       @scope.new_ephemeral
       @scope.unsetvar("0")
-      @scope.lookupvar("0").should == "bar"
+      @scope["0"].should == "bar"
     end
   end
 
diff --git a/spec/unit/parser/templatewrapper_spec.rb b/spec/unit/parser/templatewrapper_spec.rb
index 600293b..6080346 100755
--- a/spec/unit/parser/templatewrapper_spec.rb
+++ b/spec/unit/parser/templatewrapper_spec.rb
@@ -72,25 +72,23 @@ def mock_template(source=nil)
   end
 
   it "should return the contents of a variable if called via method_missing" do
-    @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns("is good")
+    @scope["chicken"] = "is good"
     tw = Puppet::Parser::TemplateWrapper.new(@scope)
     tw.chicken.should eql("is good")
   end
 
   it "should throw an exception if a variable is called via method_missing and it does not exist" do
-    @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns(:undefined)
     tw = Puppet::Parser::TemplateWrapper.new(@scope)
     lambda { tw.chicken }.should raise_error(Puppet::ParseError)
   end
 
   it "should allow you to check whether a variable is defined with has_variable?" do
-    @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns("is good")
+    @scope["chicken"] = "is good"
     tw = Puppet::Parser::TemplateWrapper.new(@scope)
     tw.has_variable?("chicken").should eql(true)
   end
 
   it "should allow you to check whether a variable is not defined with has_variable?" do
-    @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns(:undefined)
     tw = Puppet::Parser::TemplateWrapper.new(@scope)
     tw.has_variable?("chicken").should eql(false)
   end
diff --git a/spec/unit/provider/augeas/augeas_spec.rb b/spec/unit/provider/augeas/augeas_spec.rb
index 874f70a..187730b 100755
--- a/spec/unit/provider/augeas/augeas_spec.rb
+++ b/spec/unit/provider/augeas/augeas_spec.rb
@@ -1,17 +1,26 @@
 #!/usr/bin/env rspec
 require 'spec_helper'
+require 'puppet/util/package'
 
 provider_class = Puppet::Type.type(:augeas).provider(:augeas)
 
 describe provider_class do
-  describe "command parsing" do
-    before do
-      @resource = stub("resource")
-      @provider = provider_class.new(@resource)
-    end
+  before(:each) do
+    @resource = Puppet::Type.type(:augeas).new(
+      :name     => "test",
+      :root     => my_fixture_dir,
+      :provider => :augeas
+    )
+    @provider = provider_class.new(@resource)
+  end
 
+  after(:each) do
+    @provider.close_augeas
+  end
+
+  describe "command parsing" do
     it "should break apart a single line into three tokens and clean up the context" do
-      @resource.stubs(:[]).returns("/context")
+      @resource[:context] = "/context"
       tokens = @provider.parse_commands("set Jar/Jar Binks")
       tokens.size.should == 1
       tokens[0].size.should == 3
@@ -21,7 +30,6 @@
     end
 
     it "should break apart a multiple line into six tokens" do
-      @resource.stubs(:[]).returns("")
       tokens = @provider.parse_commands("set /Jar/Jar Binks\nrm anakin")
       tokens.size.should == 2
       tokens[0].size.should == 3
@@ -34,7 +42,6 @@
     end
 
     it "should strip whitespace and ignore blank lines" do
-      @resource.stubs(:[]).returns("")
       tokens = @provider.parse_commands("  set /Jar/Jar Binks \t\n  \n\n  rm anakin ")
       tokens.size.should == 2
       tokens[0].size.should == 3
@@ -47,7 +54,7 @@
     end
 
     it "should handle arrays" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       commands = ["set /Jar/Jar Binks", "rm anakin"]
       tokens = @provider.parse_commands(commands)
       tokens.size.should == 2
@@ -72,7 +79,7 @@
     #end
 
     it "should accept spaces in the value and single ticks" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       tokens = @provider.parse_commands("set JarJar 'Binks is my copilot'")
       tokens.size.should == 1
       tokens[0].size.should == 3
@@ -82,7 +89,7 @@
     end
 
     it "should accept spaces in the value and double ticks" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       tokens = @provider.parse_commands('set /JarJar "Binks is my copilot"')
       tokens.size.should == 1
       tokens[0].size.should == 3
@@ -92,7 +99,7 @@
     end
 
     it "should accept mixed ticks" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       tokens = @provider.parse_commands('set JarJar "Some \'Test\'"')
       tokens.size.should == 1
       tokens[0].size.should == 3
@@ -102,59 +109,59 @@
     end
 
     it "should handle predicates with literals" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       tokens = @provider.parse_commands("rm */*[module='pam_console.so']")
       tokens.should == [["rm", "/foo/*/*[module='pam_console.so']"]]
     end
 
     it "should handle whitespace in predicates" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       tokens = @provider.parse_commands("ins 42 before /files/etc/hosts/*/ipaddr[ . = '127.0.0.1' ]")
       tokens.should == [["ins", "42", "before","/files/etc/hosts/*/ipaddr[ . = '127.0.0.1' ]"]]
     end
 
     it "should handle multiple predicates" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       tokens = @provider.parse_commands("clear pam.d/*/*[module = 'system-auth'][type = 'account']")
       tokens.should == [["clear", "/foo/pam.d/*/*[module = 'system-auth'][type = 'account']"]]
     end
 
     it "should handle nested predicates" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       args = ["clear", "/foo/pam.d/*/*[module[ ../type = 'type] = 'system-auth'][type[last()] = 'account']"]
       tokens = @provider.parse_commands(args.join(" "))
       tokens.should == [ args ]
     end
 
     it "should handle escaped doublequotes in doublequoted string" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       tokens = @provider.parse_commands("set /foo \"''\\\"''\"")
       tokens.should == [[ "set", "/foo", "''\\\"''" ]]
     end
 
     it "should allow escaped spaces and brackets in paths" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       args = [ "set", "/white\\ space/\\[section", "value" ]
       tokens = @provider.parse_commands(args.join(" \t "))
       tokens.should == [ args ]
     end
 
     it "should allow single quoted escaped spaces in paths" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       args = [ "set", "'/white\\ space/key'", "value" ]
       tokens = @provider.parse_commands(args.join(" \t "))
       tokens.should == [[ "set", "/white\\ space/key", "value" ]]
     end
 
     it "should allow double quoted escaped spaces in paths" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       args = [ "set", '"/white\\ space/key"', "value" ]
       tokens = @provider.parse_commands(args.join(" \t "))
       tokens.should == [[ "set", "/white\\ space/key", "value" ]]
     end
 
     it "should remove trailing slashes" do
-      @resource.stubs(:[]).returns("/foo/")
+      @resource[:context] = "/foo/"
       tokens = @provider.parse_commands("set foo/ bar")
       tokens.should == [[ "set", "/foo/foo", "bar" ]]
     end
@@ -162,9 +169,9 @@
 
   describe "get filters" do
     before do
-      augeas_stub = stub("augeas", :get => "value")
-      @provider = provider_class.new
-      @provider.aug= augeas_stub
+      augeas = stub("augeas", :get => "value")
+      augeas.stubs("close")
+      @provider.aug = augeas
     end
 
     it "should return false for a = nonmatch" do
@@ -190,10 +197,10 @@
 
   describe "match filters" do
     before do
-      resource = stub("resource", :[] => "")
-      augeas_stub = stub("augeas", :match => ["set", "of", "values"])
-      @provider = provider_class.new(resource)
-      @provider.aug= augeas_stub
+      augeas = stub("augeas", :match => ["set", "of", "values"])
+      augeas.stubs("close")
+      @provider = provider_class.new(@resource)
+      @provider.aug = augeas
     end
 
     it "should return true for size match" do
@@ -248,114 +255,76 @@
   end
 
   describe "need to run" do
+    before(:each) do
+      @augeas = stub("augeas")
+      @augeas.stubs("close")
+      @provider.aug = @augeas
+
+      # These tests pretend to be an earlier version so the provider doesn't
+      # attempt to make the change in the need_to_run? method
+      @provider.stubs(:get_augeas_version).returns("0.3.5")
+    end
+
     it "should handle no filters" do
-      resource = stub("resource")
-      resource.stubs(:[]).returns(false).then.returns("").then.returns("")
-      resource.stubs(:noop?).returns(false)
-      augeas_stub = stub("augeas", :match => ["set", "of", "values"])
-      augeas_stub.stubs("close")
-      provider = provider_class.new(resource)
-      provider.aug= augeas_stub
-      provider.stubs(:get_augeas_version).returns("0.3.5")
-      provider.need_to_run?.should == true
+      @augeas.stubs("match").returns(["set", "of", "values"])
+      @provider.need_to_run?.should == true
     end
 
     it "should return true when a get filter matches" do
-      resource = stub("resource")
-      resource.stubs(:[]).returns(false).then.returns("get path == value").then.returns("")
-      resource.stubs(:noop?).returns(false)
-      provider = provider_class.new(resource)
-      augeas_stub = stub("augeas", :get => "value")
-      augeas_stub.stubs("close")
-      provider.aug= augeas_stub
-      provider.stubs(:get_augeas_version).returns("0.3.5")
-      provider.need_to_run?.should == true
+      @resource[:onlyif] = "get path == value"
+      @augeas.stubs("get").returns("value")
+      @provider.need_to_run?.should == true
     end
 
     it "should return false when a get filter does not match" do
-      resource = stub("resource")
-      resource.stubs(:[]).returns(false).then.returns("get path == another value").then.returns("")
-      provider = provider_class.new(resource)
-      augeas_stub = stub("augeas", :get => "value")
-      augeas_stub.stubs("close")
-      provider.aug= augeas_stub
-      provider.stubs(:get_augeas_version).returns("0.3.5")
-      provider.need_to_run?.should == false
+      @resource[:onlyif] = "get path == another value"
+      @augeas.stubs("get").returns("value")
+      @provider.need_to_run?.should == false
     end
 
     it "should return true when a match filter matches" do
-      resource = stub("resource")
-      resource.stubs(:[]).returns(false).then.returns("match path size == 3").then.returns("")
-      resource.stubs(:noop?).returns(false)
-      provider = provider_class.new(resource)
-      augeas_stub = stub("augeas", :match => ["set", "of", "values"])
-      augeas_stub.stubs("close")
-      provider.aug= augeas_stub
-      provider.stubs(:get_augeas_version).returns("0.3.5")
-      provider.need_to_run?.should == true
+      @resource[:onlyif] = "match path size == 3"
+      @augeas.stubs("match").returns(["set", "of", "values"])
+      @provider.need_to_run?.should == true
     end
 
     it "should return false when a match filter does not match" do
-      resource = stub("resource")
-      resource.stubs(:[]).returns(false).then.returns("match path size == 2").then.returns("")
-      provider = provider_class.new(resource)
-      augeas_stub = stub("augeas", :match => ["set", "of", "values"])
-      augeas_stub.stubs("close")
-      provider.aug= augeas_stub
-      provider.stubs(:get_augeas_version).returns("0.3.5")
-      provider.need_to_run?.should == false
+      @resource[:onlyif] = "match path size == 2"
+      @augeas.stubs("match").returns(["set", "of", "values"])
+      @provider.need_to_run?.should == false
     end
 
-    #This is a copy of the last one, with setting the force to true
+    # Now setting force to true
     it "setting force should not change the above logic" do
-      resource = stub("resource")
-      resource.stubs(:[]).returns(true).then.returns("match path size == 2").then.returns("")
-      provider = provider_class.new(resource)
-      augeas_stub = stub("augeas", :match => ["set", "of", "values"])
-      augeas_stub.stubs("close")
-      provider.aug= augeas_stub
-      provider.stubs(:get_augeas_version).returns("0.3.5")
-      provider.need_to_run?.should == false
+      @resource[:force] = true
+      @resource[:onlyif] = "match path size == 2"
+      @augeas.stubs("match").returns(["set", "of", "values"])
+      @provider.need_to_run?.should == false
     end
 
     #Ticket 5211 testing
     it "should return true when a size != the provided value" do
-      resource = stub("resource")
-      resource.stubs(:[]).returns(false).then.returns("match path size != 17").then.returns("")
-      resource.stubs(:noop?).returns(false)
-      provider = provider_class.new(resource)
-      augeas_stub = stub("augeas", :match => ["set", "of", "values"])
-      augeas_stub.stubs("close")
-      provider.aug= augeas_stub
-      provider.stubs(:get_augeas_version).returns("0.3.5")
-      provider.need_to_run?.should == true
+      @resource[:onlyif] = "match path size != 17"
+      @augeas.stubs("match").returns(["set", "of", "values"])
+      @provider.need_to_run?.should == true
     end
 
     #Ticket 5211 testing
     it "should return false when a size doeas equal the provided value" do
-      resource = stub("resource")
-      resource.stubs(:[]).returns(false).then.returns("match path size != 3").then.returns("")
-      provider = provider_class.new(resource)
-      augeas_stub = stub("augeas", :match => ["set", "of", "values"])
-      augeas_stub.stubs("close")
-      provider.aug= augeas_stub
-      provider.stubs(:get_augeas_version).returns("0.3.5")
-      provider.need_to_run?.should == false
+      @resource[:onlyif] = "match path size != 3"
+      @augeas.stubs("match").returns(["set", "of", "values"])
+      @provider.need_to_run?.should == false
     end
 
     # Ticket 2728 (diff files)
-    describe "and Puppet[:show_diff] is set", :if => Puppet.features.augeas? do
-      before do
+    describe "and Puppet[:show_diff] is set" do
+      before(:each) do
         Puppet[:show_diff] = true
 
-        @resource = Puppet::Type.type(:augeas).new(:name => "test")
-        @provider = provider_class.new(@resource)
-        @augeas_stub = stub("augeas")
-        @provider.aug = @augeas_stub
-
-        @augeas_stub.stubs("get").with("/augeas/version").returns("0.7.2")
-        @augeas_stub.stubs(:set).returns(true)
-        @augeas_stub.stubs(:save).returns(true)
+        @resource[:root] = ""
+        @provider.stubs(:get_augeas_version).returns("0.7.2")
+        @augeas.stubs(:set).returns(true)
+        @augeas.stubs(:save).returns(true)
       end
 
       it "should call diff when a file is shown to have been changed" do
@@ -364,10 +333,10 @@
         @resource[:context] = "/files"
         @resource[:changes] = ["set #{file}/foo bar"]
 
-        @augeas_stub.stubs(:match).with("/augeas/events/saved").returns(["/augeas/events/saved"])
-        @augeas_stub.stubs(:get).with("/augeas/events/saved").returns(["/files#{file}"])
-        @augeas_stub.expects(:set).with("/augeas/save", "newfile")
-        @augeas_stub.expects(:close).never()
+        @augeas.stubs(:match).with("/augeas/events/saved").returns(["/augeas/events/saved"])
+        @augeas.stubs(:get).with("/augeas/events/saved").returns("/files#{file}")
+        @augeas.expects(:set).with("/augeas/save", "newfile")
+        @augeas.expects(:close).never()
 
         @provider.expects("diff").with("#{file}", "#{file}.augnew").returns("")
         @provider.should be_need_to_run
@@ -380,11 +349,11 @@
         @resource[:context] = "/files"
         @resource[:changes] = ["set #{file1}/foo bar", "set #{file2}/baz biz"]
 
-        @augeas_stub.stubs(:match).with("/augeas/events/saved").returns(["/augeas/events/saved[1]", "/augeas/events/saved[2]"])
-        @augeas_stub.stubs(:get).with("/augeas/events/saved[1]").returns(["/files#{file1}"])
-        @augeas_stub.stubs(:get).with("/augeas/events/saved[2]").returns(["/files#{file2}"])
-        @augeas_stub.expects(:set).with("/augeas/save", "newfile")
-        @augeas_stub.expects(:close).never()
+        @augeas.stubs(:match).with("/augeas/events/saved").returns(["/augeas/events/saved[1]", "/augeas/events/saved[2]"])
+        @augeas.stubs(:get).with("/augeas/events/saved[1]").returns("/files#{file1}")
+        @augeas.stubs(:get).with("/augeas/events/saved[2]").returns("/files#{file2}")
+        @augeas.expects(:set).with("/augeas/save", "newfile")
+        @augeas.expects(:close).never()
 
         @provider.expects(:diff).with("#{file1}", "#{file1}.augnew").returns("")
         @provider.expects(:diff).with("#{file2}", "#{file2}.augnew").returns("")
@@ -400,10 +369,10 @@
           @resource[:changes] = ["set #{file}/foo bar"]
           @resource[:root] = root
 
-          @augeas_stub.stubs(:match).with("/augeas/events/saved").returns(["/augeas/events/saved"])
-          @augeas_stub.stubs(:get).with("/augeas/events/saved").returns(["/files#{file}"])
-          @augeas_stub.expects(:set).with("/augeas/save", "newfile")
-          @augeas_stub.expects(:close).never()
+          @augeas.stubs(:match).with("/augeas/events/saved").returns(["/augeas/events/saved"])
+          @augeas.stubs(:get).with("/augeas/events/saved").returns("/files#{file}")
+          @augeas.expects(:set).with("/augeas/save", "newfile")
+          @augeas.expects(:close).never()
 
           @provider.expects(:diff).with("#{root}#{file}", "#{root}#{file}.augnew").returns("")
           @provider.should be_need_to_run
@@ -416,10 +385,10 @@
         @resource[:context] = "/files"
         @resource[:changes] = ["set #{file}/foo bar"]
 
-        @augeas_stub.stubs(:match).with("/augeas/events/saved").returns([])
-        @augeas_stub.expects(:set).with("/augeas/save", "newfile")
-        @augeas_stub.expects(:get).with("/augeas/events/saved").never()
-        @augeas_stub.expects(:close)
+        @augeas.stubs(:match).with("/augeas/events/saved").returns([])
+        @augeas.expects(:set).with("/augeas/save", "newfile")
+        @augeas.expects(:get).with("/augeas/events/saved").never()
+        @augeas.expects(:close)
 
         @provider.expects(:diff).never()
         @provider.should_not be_need_to_run
@@ -432,10 +401,10 @@
         @resource[:context] = "/files"
         @resource[:changes] = ["set #{file}/foo bar"]
 
-        @augeas_stub.stubs(:match).with("/augeas/events/saved").returns(["/augeas/events/saved"])
-        @augeas_stub.stubs(:get).with("/augeas/events/saved").returns(["/files#{file}"])
-        @augeas_stub.expects(:set).with("/augeas/save", "newfile")
-        @augeas_stub.expects(:close)
+        @augeas.stubs(:match).with("/augeas/events/saved").returns(["/augeas/events/saved"])
+        @augeas.stubs(:get).with("/augeas/events/saved").returns("/files#{file}")
+        @augeas.expects(:set).with("/augeas/save", "newfile")
+        @augeas.expects(:close)
 
         File.expects(:delete).with(file + ".augnew")
 
@@ -449,9 +418,9 @@
         @resource[:context] = "/files"
         @resource[:changes] = ["set #{file}/foo bar"]
 
-        @augeas_stub.stubs(:save).returns(false)
-        @augeas_stub.stubs(:match).with("/augeas/events/saved").returns([])
-        @augeas_stub.expects(:close)
+        @augeas.stubs(:save).returns(false)
+        @augeas.stubs(:match).with("/augeas/events/saved").returns([])
+        @augeas.expects(:close)
 
         @provider.expects(:diff).never()
         lambda { @provider.need_to_run? }.should raise_error
@@ -460,20 +429,18 @@
   end
 
   describe "augeas execution integration" do
-
     before do
-      @resource = stub("resource")
-      @provider = provider_class.new(@resource)
       @augeas = stub("augeas")
-      @provider.aug= @augeas
+      @augeas.stubs("close")
+      @augeas.stubs(:match).with("/augeas/events/saved").returns([])
+
+      @provider.aug = @augeas
       @provider.stubs(:get_augeas_version).returns("0.3.5")
-      @augeas.stubs(:match).with("/augeas/events/saved")
     end
 
     it "should handle set commands" do
-      command = "set JarJar Binks"
-      context = "/some/path/"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "set JarJar Binks"
+      @resource[:context] = "/some/path/"
       @augeas.expects(:set).with("/some/path/JarJar", "Binks").returns(true)
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -481,9 +448,7 @@
     end
 
     it "should handle rm commands" do
-      command = "rm /Jar/Jar"
-      context = ""
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "rm /Jar/Jar"
       @augeas.expects(:rm).with("/Jar/Jar")
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -491,9 +456,7 @@
     end
 
     it "should handle remove commands" do
-      command = "remove /Jar/Jar"
-      context = ""
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "remove /Jar/Jar"
       @augeas.expects(:rm).with("/Jar/Jar")
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -501,20 +464,17 @@
     end
 
     it "should handle clear commands" do
-      command = "clear Jar/Jar"
-      context = "/foo/"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "clear Jar/Jar"
+      @resource[:context] = "/foo/"
       @augeas.expects(:clear).with("/foo/Jar/Jar").returns(true)
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
       @provider.execute_changes.should == :executed
     end
 
-
     it "should handle ins commands with before" do
-      command = "ins Binks before Jar/Jar"
-      context = "/foo"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "ins Binks before Jar/Jar"
+      @resource[:context] = "/foo"
       @augeas.expects(:insert).with("/foo/Jar/Jar", "Binks", true)
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -522,9 +482,8 @@
     end
 
     it "should handle ins commands with after" do
-      command = "ins Binks after /Jar/Jar"
-      context = "/foo"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "ins Binks after /Jar/Jar"
+      @resource[:context] = "/foo"
       @augeas.expects(:insert).with("/Jar/Jar", "Binks", false)
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -532,9 +491,7 @@
     end
 
     it "should handle ins with no context" do
-      command = "ins Binks after /Jar/Jar"
-      context = "" # this is the default
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "ins Binks after /Jar/Jar"
       @augeas.expects(:insert).with("/Jar/Jar", "Binks", false)
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -542,9 +499,8 @@
     end
 
     it "should handle multiple commands" do
-      command = ["ins Binks after /Jar/Jar", "clear Jar/Jar"]
-      context = "/foo/"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = ["ins Binks after /Jar/Jar", "clear Jar/Jar"]
+      @resource[:context] = "/foo/"
       @augeas.expects(:insert).with("/Jar/Jar", "Binks", false)
       @augeas.expects(:clear).with("/foo/Jar/Jar").returns(true)
       @augeas.expects(:save).returns(true)
@@ -553,9 +509,8 @@
     end
 
     it "should handle defvar commands" do
-      command = "defvar myjar Jar/Jar"
-      context = "/foo/"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "defvar myjar Jar/Jar"
+      @resource[:context] = "/foo/"
       @augeas.expects(:defvar).with("myjar", "/foo/Jar/Jar").returns(true)
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -563,9 +518,8 @@
     end
 
     it "should pass through augeas variables without context" do
-      command = ["defvar myjar Jar/Jar","set $myjar/Binks 1"]
-      context = "/foo/"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = ["defvar myjar Jar/Jar","set $myjar/Binks 1"]
+      @resource[:context] = "/foo/"
       @augeas.expects(:defvar).with("myjar", "/foo/Jar/Jar").returns(true)
       # this is the important bit, shouldn't be /foo/$myjar/Binks
       @augeas.expects(:set).with("$myjar/Binks", "1").returns(true)
@@ -575,9 +529,8 @@
     end
 
     it "should handle defnode commands" do
-      command = "defnode newjar Jar/Jar[last()+1] Binks"
-      context = "/foo/"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "defnode newjar Jar/Jar[last()+1] Binks"
+      @resource[:context] = "/foo/"
       @augeas.expects(:defnode).with("newjar", "/foo/Jar/Jar[last()+1]", "Binks").returns(true)
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -585,9 +538,8 @@
     end
 
     it "should handle mv commands" do
-      command = "mv Jar/Jar Binks"
-      context = "/foo/"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = "mv Jar/Jar Binks"
+      @resource[:context] = "/foo/"
       @augeas.expects(:mv).with("/foo/Jar/Jar", "/foo/Binks").returns(true)
       @augeas.expects(:save).returns(true)
       @augeas.expects(:close)
@@ -595,9 +547,8 @@
     end
 
     it "should handle setm commands" do
-      command = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","setm test Jar/Jar Binks"]
-      context = "/foo/"
-      @resource.expects(:[]).times(2).returns(command).then.returns(context)
+      @resource[:changes] = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","setm test Jar/Jar Binks"]
+      @resource[:context] = "/foo/"
       @augeas.expects(:set).with("/foo/test[1]/Jar/Jar", "Foo").returns(true)
       @augeas.expects(:set).with("/foo/test[2]/Jar/Jar", "Bar").returns(true)
       @augeas.expects(:setm).with("/foo/test", "Jar/Jar", "Binks").returns(true)
@@ -606,4 +557,89 @@
       @provider.execute_changes.should == :executed
     end
   end
+
+  describe "save failure reporting" do
+    before do
+      @augeas = stub("augeas")
+      @augeas.stubs("close")
+      @provider.aug = @augeas
+    end
+
+    it "should find errors and output to debug" do
+      @augeas.expects(:match).with("/augeas//error[. = 'put_failed']").returns(["/augeas/files/foo/error"])
+      @augeas.expects(:match).with("/augeas/files/foo/error/*").returns(["/augeas/files/foo/error/path", "/augeas/files/foo/error/message"])
+      @augeas.expects(:get).with("/augeas/files/foo/error/path").returns("/foo")
+      @augeas.expects(:get).with("/augeas/files/foo/error/message").returns("Failed to...")
+      @provider.expects(:debug).times(4)
+      @provider.print_put_errors
+    end
+  end
+
+  # Run initialisation tests of the real Augeas library to test our open_augeas
+  # method.  This relies on Augeas and ruby-augeas on the host to be
+  # functioning.
+  describe "augeas lib initialisation", :if => Puppet.features.augeas? do
+    # Expect lenses for fstab and hosts
+    it "should have loaded standard files by default" do
+      aug = @provider.open_augeas
+      aug.should_not == nil
+      aug.match("/files/etc/fstab").should == ["/files/etc/fstab"]
+      aug.match("/files/etc/hosts").should == ["/files/etc/hosts"]
+      aug.match("/files/etc/test").should == []
+    end
+
+    # Only the file specified should be loaded
+    it "should load one file if incl/lens used" do
+      @resource[:incl] = "/etc/hosts"
+      @resource[:lens] = "Hosts.lns"
+
+      aug = @provider.open_augeas
+      aug.should_not == nil
+      aug.match("/files/etc/fstab").should == []
+      aug.match("/files/etc/hosts").should == ["/files/etc/hosts"]
+      aug.match("/files/etc/test").should == []
+    end
+
+    it "should also load lenses from load_path" do
+      @resource[:load_path] = my_fixture_dir
+
+      aug = @provider.open_augeas
+      aug.should_not == nil
+      aug.match("/files/etc/fstab").should == ["/files/etc/fstab"]
+      aug.match("/files/etc/hosts").should == ["/files/etc/hosts"]
+      aug.match("/files/etc/test").should == ["/files/etc/test"]
+    end
+
+    # Optimisations added for Augeas 0.8.2 or higher is available, see #7285
+    describe ">= 0.8.2 optimisations", :if => Puppet.features.augeas? && Puppet::Util::Package.versioncmp(Facter.value(:augeasversion), "0.8.2") >= 0 do
+      it "should only load one file if relevant context given" do
+        @resource[:context] = "/files/etc/fstab"
+
+        aug = @provider.open_augeas
+        aug.should_not == nil
+        aug.match("/files/etc/fstab").should == ["/files/etc/fstab"]
+        aug.match("/files/etc/hosts").should == []
+      end
+
+      it "should only load one lens from load_path if context given" do
+        @resource[:context] = "/files/etc/test"
+        @resource[:load_path] = my_fixture_dir
+
+        aug = @provider.open_augeas
+        aug.should_not == nil
+        aug.match("/files/etc/fstab").should == []
+        aug.match("/files/etc/hosts").should == []
+        aug.match("/files/etc/test").should == ["/files/etc/test"]
+      end
+
+      it "should load standard files if context isn't specific" do
+        @resource[:context] = "/files/etc"
+
+        aug = @provider.open_augeas
+        aug.should_not == nil
+        aug.match("/files/etc/fstab").should == ["/files/etc/fstab"]
+        aug.match("/files/etc/hosts").should == ["/files/etc/hosts"]
+      end
+    end
+  end
 end
diff --git a/spec/unit/provider/package/macports_spec.rb b/spec/unit/provider/package/macports_spec.rb
index 8e08242..362d239 100755
--- a/spec/unit/provider/package/macports_spec.rb
+++ b/spec/unit/provider/package/macports_spec.rb
@@ -30,7 +30,7 @@
     it { should be_versionable }
   end
 
-  describe "when listing all instances", :'fails_on_ruby_1.9.2' => true do
+  describe "when listing all instances" do
     it "should call port -q installed" do
       provider_class.expects(:port).with("-q", :installed).returns("")
       provider_class.instances
@@ -45,6 +45,12 @@
       provider_class.expects(:port).returns("foo @1.234.5_2")
       provider_class.instances.size.should == 0
     end
+
+    it "should ignore variants" do
+      provider_class.parse_installed_query_line("bar @1.0beta2_38_1+x11+java (active)").
+        should == {:provider=>:macports, :revision=>"1", :name=>"bar", :ensure=>"1.0beta2_38"}
+    end
+
   end
 
   describe "when installing" do
@@ -78,43 +84,54 @@
       "1.2.3 2"
     end
     let :infoargs do
-      ["-q", :info, "--line", "--version", "--revision",  resource_name]
+      ["/opt/local/bin/port", "-q", :info, "--line", "--version", "--revision",  resource_name]
+    end
+
+    before :each do
+      provider.stubs(:command).with(:port).returns("/opt/local/bin/port")
     end
 
     it "should return nil when the package cannot be found" do
       resource[:name] = resource_name
-      provider.expects(:port).returns("")
+      provider.expects(:execute).with(infoargs, {:combine=>false}).returns("")
       provider.latest.should == nil
     end
 
     it "should return the current version if the installed port has the same revision" do
       current_hash[:revision] = "2"
-      provider.expects(:port).with(*infoargs).returns(new_info_line)
+      provider.expects(:execute).with(infoargs, {:combine=>false}).returns(new_info_line)
       provider.expects(:query).returns(current_hash)
       provider.latest.should == current_hash[:ensure]
     end
 
     it "should return the new version_revision if the installed port has a lower revision" do
       current_hash[:revision] = "1"
-      provider.expects(:port).with(*infoargs).returns(new_info_line)
+      provider.expects(:execute).with(infoargs, {:combine=>false}).returns(new_info_line)
       provider.expects(:query).returns(current_hash)
       provider.latest.should == "1.2.3_2"
     end
+
+    it "should return the newest version if the port is not installed" do
+      resource[:name] = resource_name
+      provider.expects(:execute).with(infoargs, {:combine=>false}).returns(new_info_line)
+      provider.expects(:execute).with(["/opt/local/bin/port", "-q", :installed, resource[:name]], {:combine=>false}).returns("")
+      provider.latest.should == "1.2.3_2"
+    end
   end
 
   describe "when updating a port" do
-    it "should execute port upgrade if the port is installed" do
+    it "should execute port install if the port is installed" do
       resource[:name] = resource_name
       resource[:ensure] = :present
-      provider.expects(:query).returns(current_hash)
-      provider.expects(:port).with("-q", :upgrade, resource_name)
+      provider.stubs(:query).returns(current_hash)
+      provider.expects(:port).with("-q", :install, resource_name)
       provider.update
     end
 
-    it "should execute port install if the port is not installed", :'fails_on_ruby_1.9.2' => true do
+    it "should execute port install if the port is not installed" do
       resource[:name] = resource_name
       resource[:ensure] = :present
-      provider.expects(:query).returns("")
+      provider.stubs(:query).returns("")
       provider.expects(:port).with("-q", :install, resource_name)
       provider.update
     end
diff --git a/spec/unit/provider/package/pacman_spec.rb b/spec/unit/provider/package/pacman_spec.rb
index 6791726..9c1a566 100644
--- a/spec/unit/provider/package/pacman_spec.rb
+++ b/spec/unit/provider/package/pacman_spec.rb
@@ -6,9 +6,7 @@
 describe provider do
   before do
     provider.stubs(:command).with(:pacman).returns('/usr/bin/pacman')
-    @resource = stub 'resource'
-    @resource.stubs(:[]).returns("package")
-    @resource.stubs(:name).returns("name")
+    @resource = Puppet::Type.type(:package).new(:name => 'package')
     @provider = provider.new(@resource)
   end
 
@@ -46,7 +44,7 @@
       provider.
         expects(:execute).
         with { |args|
-          args[3,4] == ["-Sy", @resource[0]]
+          args[3,4] == ["-Sy", @resource[:name]]
         }.
         returns("")
 
@@ -59,6 +57,79 @@
 
       lambda { @provider.install }.should raise_exception(Puppet::ExecutionFailure)
     end
+
+    context "when :source is specified" do
+      before :each do
+        @install = sequence("install")
+      end
+
+      context "recognizable by pacman" do
+        %w{
+          /some/package/file
+          http://some.package.in/the/air
+          ftp://some.package.in/the/air
+        }.each do |source|
+          it "should install #{source} directly" do
+            @resource[:source] = source
+
+            provider.expects(:execute).
+              with(all_of(includes("-Sy"), includes("--noprogressbar"))).
+              in_sequence(@install).
+              returns("")
+
+            provider.expects(:execute).
+              with(all_of(includes("-U"), includes(source))).
+              in_sequence(@install).
+              returns("")
+
+            @provider.install
+          end
+        end
+      end
+
+      context "as a file:// URL" do
+        before do
+          @package_file = "file:///some/package/file"
+          @actual_file_path = "/some/package/file"
+          @resource[:source] = @package_file
+        end
+
+        it "should install from the path segment of the URL" do
+          provider.expects(:execute).
+            with(all_of(includes("-Sy"), includes("--noprogressbar"),
+                        includes("--noconfirm"))).
+            in_sequence(@install).
+            returns("")
+
+          provider.expects(:execute).
+            with(all_of(includes("-U"), includes(@actual_file_path))).
+            in_sequence(@install).
+            returns("")
+
+          @provider.install
+        end
+      end
+
+      context "as a puppet URL" do
+        before do
+          @resource[:source] = "puppet://server/whatever"
+        end
+
+        it "should fail" do
+          lambda { @provider.install }.should raise_error(Puppet::Error)
+        end
+      end
+
+      context "as a malformed URL" do
+        before do
+          @resource[:source] = "blah://"
+        end
+
+        it "should fail" do
+          lambda { @provider.install }.should raise_error(Puppet::Error)
+        end
+      end
+    end
   end
 
   describe "when updating" do
@@ -95,7 +166,7 @@
       provider.
         expects(:execute).
         with { |args|
-          args[3,4] == ["-R", @resource[0]]
+          args[3,4] == ["-R", @resource[:name]]
         }.
         returns("")
 
@@ -107,7 +178,7 @@
     it "should query pacman" do
       provider.
         expects(:execute).
-        with(["/usr/bin/pacman", "-Qi", @resource[0]])
+        with(["/usr/bin/pacman", "-Qi", @resource[:name]])
       @provider.query
     end
 
@@ -149,7 +220,7 @@
       @provider.query.should == {
         :ensure => :purged,
         :status => 'missing',
-        :name => @resource[0],
+        :name => @resource[:name],
         :error => 'ok',
       }
     end
@@ -194,32 +265,30 @@
 
   describe "when determining the latest version" do
     it "should refresh package list" do
-      refreshed = states('refreshed').starts_as('unrefreshed')
+      get_latest_version = sequence("get_latest_version")
       provider.
         expects(:execute).
-        when(refreshed.is('unrefreshed')).
-        with(['/usr/bin/pacman', '-Sy']).
-        then(refreshed.is('refreshed'))
+        in_sequence(get_latest_version).
+        with(['/usr/bin/pacman', '-Sy'])
 
       provider.
         stubs(:execute).
-        when(refreshed.is('refreshed')).
+        in_sequence(get_latest_version).
         returns("")
 
       @provider.latest
     end
 
     it "should get query pacman for the latest version" do
-      refreshed = states('refreshed').starts_as('unrefreshed')
+      get_latest_version = sequence("get_latest_version")
       provider.
         stubs(:execute).
-        when(refreshed.is('unrefreshed')).
-        then(refreshed.is('refreshed'))
+        in_sequence(get_latest_version)
 
       provider.
         expects(:execute).
-        when(refreshed.is('refreshed')).
-        with(['/usr/bin/pacman', '-Sp', '--print-format', '%v', @resource[0]]).
+        in_sequence(get_latest_version).
+        with(['/usr/bin/pacman', '-Sp', '--print-format', '%v', @resource[:name]]).
         returns("")
 
       @provider.latest
diff --git a/spec/unit/provider/package/pkgin_spec.rb b/spec/unit/provider/package/pkgin_spec.rb
new file mode 100644
index 0000000..c62ab68
--- /dev/null
+++ b/spec/unit/provider/package/pkgin_spec.rb
@@ -0,0 +1,176 @@
+require "spec_helper"
+
+provider_class = Puppet::Type.type(:package).provider(:pkgin)
+
+describe provider_class do
+  let(:resource) { Puppet::Type.type(:package).new(:name => "vim") }
+  subject        { provider_class.new(resource) }
+
+  describe "Puppet provider interface" do
+    it "can return the list of all packages" do
+      provider_class.should respond_to(:instances)
+    end
+  end
+
+  describe "#install" do
+    before { resource[:ensure] = :absent }
+
+    it "uses pkgin install to install" do
+      subject.expects(:pkgin).with("-y", :install, "vim")
+      subject.install
+    end
+  end
+
+  describe "#uninstall" do
+    before { resource[:ensure] = :present }
+
+    it "uses pkgin remove to uninstall" do
+      subject.expects(:pkgin).with("-y", :remove, "vim")
+      subject.uninstall
+    end
+  end
+
+  describe "#instances" do
+    let(:pkgin_ls_output) do
+      "zlib-1.2.3           General purpose data compression library\nzziplib-0.13.59      Library for ZIP archive handling\n"
+    end
+
+    before do
+      provider_class.stubs(:pkgin).with(:list).returns(pkgin_ls_output)
+    end
+
+    it "returns an array of providers for each package" do
+      instances = provider_class.instances
+      instances.should have(2).items
+      instances.each do |instance|
+        instance.should be_a(provider_class)
+      end
+    end
+
+    it "populates each provider with an installed package" do
+      zlib_provider, zziplib_provider = provider_class.instances
+      zlib_provider.get(:name).should == "zlib"
+      zlib_provider.get(:ensure).should == :present
+      zziplib_provider.get(:name).should == "zziplib"
+      zziplib_provider.get(:ensure).should == :present
+    end
+  end
+
+  describe "#query" do
+    before do
+      provider_class.stubs(:pkgin).with(:search, "vim").returns(pkgin_search_output)
+    end
+
+    context "when the package is installed" do
+      let(:pkgin_search_output) do
+        "vim-7.2.446 =        Vim editor (vi clone) without GUI\nvim-share-7.2.446 =  Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n"
+      end
+
+      it "returns a hash stating the package is present" do
+        result = subject.query
+        result[:ensure].should == :present
+        result[:name].should == "vim"
+        result[:provider].should == :pkgin
+      end
+    end
+
+    context "when the package is out of date" do
+      let(:pkgin_search_output) do
+        "vim-7.2.446 <        Vim editor (vi clone) without GUI\nvim-share-7.2.446 =  Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n"
+      end
+
+      it "returns a hash stating the package is present" do
+        result = subject.query
+        result[:ensure].should == :present
+        result[:name].should == "vim"
+        result[:provider].should == :pkgin
+      end
+    end
+
+    context "when the package is ahead of date" do
+      let(:pkgin_search_output) do
+        "vim-7.2.446 >        Vim editor (vi clone) without GUI\nvim-share-7.2.446 =  Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n"
+      end
+
+      it "returns a hash stating the package is present" do
+        result = subject.query
+        result[:ensure].should == :present
+        result[:name].should == "vim"
+        result[:provider].should == :pkgin
+      end
+    end
+
+    context "when the package is not installed" do
+      let(:pkgin_search_output) do
+        "vim-7.2.446          Vim editor (vi clone) without GUI\nvim-share-7.2.446 =  Data files for the vim editor (vi clone)\n\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n"
+      end
+
+      it "returns a hash stating the package is present" do
+        result = subject.query
+        result[:ensure].should == :absent
+        result[:name].should == "vim"
+        result[:provider].should == :pkgin
+      end
+    end
+
+    context "when the package cannot be found" do
+      let(:pkgin_search_output) do
+        "\n=: package is installed and up-to-date\n<: package is installed but newer version is available\n>: installed package has a greater version than available package\n"
+      end
+
+      it "returns nil" do
+        subject.query.should be_nil
+      end
+    end
+  end
+
+  describe "#parse_pkgin_line" do
+    context "with an installed package" do
+      let(:package) { "vim-7.2.446 =        Vim editor (vi clone) without GUI" }
+
+      it "extracts the name and status" do
+        hash = provider_class.parse_pkgin_line(package)
+        hash[:name].should == "vim"
+        hash[:ensure].should == :present
+        hash[:provider].should == :pkgin
+      end
+    end
+
+    context "with an installed package with a hyphen in the name" do
+      let(:package) { "ruby18-puppet-0.25.5nb1 = Configuration management framework written in Ruby" }
+
+      it "extracts the name and status" do
+        hash = provider_class.parse_pkgin_line(package)
+        hash[:name].should == "ruby18-puppet"
+        hash[:ensure].should == :present
+        hash[:provider].should == :pkgin
+      end
+    end
+
+    context "with a package not yet installed" do
+      let(:package) { "vim-7.2.446          Vim editor (vi clone) without GUI" }
+
+      it "extracts the name and status" do
+        hash = provider_class.parse_pkgin_line(package)
+        hash[:name].should == "vim"
+        hash[:ensure].should == :absent
+        hash[:provider].should == :pkgin
+      end
+
+      it "extracts the name and an overridden status" do
+        hash = provider_class.parse_pkgin_line(package, :present)
+        hash[:name].should == "vim"
+        hash[:ensure].should == :present
+        hash[:provider].should == :pkgin
+      end
+    end
+
+    context "with an invalid package" do
+      let(:package) { "" }
+
+      it "returns nil" do
+        provider_class.parse_pkgin_line(package).should be_nil
+      end
+    end
+  end
+end
diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb
index 601c240..5148ac0 100755
--- a/spec/unit/provider/package/yum_spec.rb
+++ b/spec/unit/provider/package/yum_spec.rb
@@ -30,16 +30,19 @@
       @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :install, 'mypackage')
       @provider.install
     end
+
     it 'should use :install to update' do
       @provider.expects(:install)
       @provider.update
     end
+
     it 'should be able to set version' do
       @resource.stubs(:should).with(:ensure).returns '1.2'
       @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :install, 'mypackage-1.2')
       @provider.stubs(:query).returns :ensure => '1.2'
       @provider.install
     end
+
     it 'should be able to downgrade' do
       @resource.stubs(:should).with(:ensure).returns '1.0'
       @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :downgrade, 'mypackage-1.0')
@@ -53,6 +56,7 @@
       @provider.expects(:yum).with('-y', :erase, 'mypackage')
       @provider.purge
     end
+
     it 'should use rpm to uninstall' do
       @provider.expects(:rpm).with('-e', 'mypackage-1-1.i386')
       @provider.uninstall
@@ -62,5 +66,45 @@
   it 'should be versionable' do
     provider.should be_versionable
   end
-end
 
+  describe '#latest' do
+    describe 'when latest_info is nil' do
+      before :each do
+        @provider.stubs(:latest_info).returns(nil)
+      end
+
+      it 'raises if ensure is absent and latest_info is nil' do
+        @provider.stubs(:properties).returns({:ensure => :absent})
+
+        expect { @provider.latest }.to raise_error(
+          Puppet::DevError,
+          'Tried to get latest on a missing package'
+        )
+      end
+
+      it 'returns the ensure value if the package is not already installed' do
+        @provider.stubs(:properties).returns({:ensure => '3.4.5'})
+
+        @provider.latest.should == '3.4.5'
+      end
+    end
+
+    describe 'when latest_info is populated' do
+      before :each do
+        @provider.stubs(:latest_info).returns({
+          :name     => 'mypackage',
+          :epoch    => '1',
+          :version  => '2.3.4',
+          :release  => '5',
+          :arch     => 'i686',
+          :provider => :yum,
+          :ensure   => '2.3.4-5'
+        })
+      end
+
+      it 'includes the epoch in the version string' do
+        @provider.latest.should == '1:2.3.4-5'
+      end
+    end
+  end
+end
diff --git a/spec/unit/provider/service/debian_spec.rb b/spec/unit/provider/service/debian_spec.rb
index 4e3d30d..f858568 100755
--- a/spec/unit/provider/service/debian_spec.rb
+++ b/spec/unit/provider/service/debian_spec.rb
@@ -88,6 +88,21 @@
       @provider.enabled?.should == :true
     end
 
+    context "when invoke-rc.d exits with 105 status" do
+      it "links count is 4" do
+        @provider.stubs(:system)
+        $CHILD_STATUS.stubs(:exitstatus).returns(105)
+        @provider.stubs(:get_start_link_count).returns(4)
+        @provider.enabled?.should == :true
+      end
+      it "links count is less than 4" do
+        @provider.stubs(:system)
+        $CHILD_STATUS.stubs(:exitstatus).returns(105)
+        @provider.stubs(:get_start_link_count).returns(3)
+        @provider.enabled?.should == :false
+      end
+    end
+
     # pick a range of non-[104.106] numbers, strings and booleans to test with.
     [-100, -1, 0, 1, 100, "foo", "", :true, :false].each do |exitstatus|
       it "should return false when invoke-rc.d exits with #{exitstatus} status" do
diff --git a/spec/unit/rails_spec.rb b/spec/unit/rails_spec.rb
index fe7fd8e..60062db 100755
--- a/spec/unit/rails_spec.rb
+++ b/spec/unit/rails_spec.rb
@@ -88,169 +88,100 @@
   end
 end
 
-describe Puppet::Rails, "when initializing a mysql connection", :if => Puppet.features.rails? do
-  it "should provide the adapter, log_level, and host, port, username, password, database, and reconnect arguments" do
-    Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql")
-    Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
-    Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
-    Puppet.settings.stubs(:value).with(:dbport).returns("")
-    Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
-    Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
-    Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 45).to_s)
-    Puppet.settings.stubs(:value).with(:dbname).returns("testname")
-    Puppet.settings.stubs(:value).with(:dbsocket).returns("")
-
-    Puppet::Rails.database_arguments.should == {
-      :adapter => "mysql",
-      :log_level => "testlevel",
-      :host => "testserver",
-      :username => "testuser",
-      :password => "testpassword",
-      :pool => pool_size,
-      :database => "testname",
-      :reconnect => true
-    }
-  end
-
-  it "should provide the adapter, log_level, and host, port, username, password, database, socket, connections, and reconnect arguments" do
-    Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql")
-    Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
-    Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
-    Puppet.settings.stubs(:value).with(:dbport).returns("9999")
-    Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
-    Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
-    Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 12).to_s)
-    Puppet.settings.stubs(:value).with(:dbname).returns("testname")
-    Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket")
-
-    Puppet::Rails.database_arguments.should == {
-      :adapter => "mysql",
-      :log_level => "testlevel",
-      :host => "testserver",
-      :port => "9999",
-      :username => "testuser",
-      :password => "testpassword",
-      :pool => pool_size,
-      :database => "testname",
-      :socket => "testsocket",
-      :reconnect => true
-    }
-  end
-
-  it "should provide the adapter, log_level, and host, port, username, password, database, socket, and connections arguments" do
-    Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql")
-    Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
-    Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
-    Puppet.settings.stubs(:value).with(:dbport).returns("9999")
-    Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
-    Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
-    Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 23).to_s)
-    Puppet.settings.stubs(:value).with(:dbname).returns("testname")
-    Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket")
-
-    Puppet::Rails.database_arguments.should == {
-      :adapter => "mysql",
-      :log_level => "testlevel",
-      :host => "testserver",
-      :port => "9999",
-      :username => "testuser",
-      :password => "testpassword",
-      :pool => pool_size,
-      :database => "testname",
-      :socket => "testsocket",
-      :reconnect => true
-    }
-  end
-
-  it "should not provide the pool if dbconnections is 0, '0', or ''" do
-    Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql")
-    Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
-    Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
-    Puppet.settings.stubs(:value).with(:dbport).returns("9999")
-    Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
-    Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
-    Puppet.settings.stubs(:value).with(:dbname).returns("testname")
-    Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket")
-
-    Puppet.settings.stubs(:value).with(:dbconnections).returns(0)
-    Puppet::Rails.database_arguments.should_not be_include(:pool)
-
-    Puppet.settings.stubs(:value).with(:dbconnections).returns('0')
-    Puppet::Rails.database_arguments.should_not be_include(:pool)
-
-    Puppet.settings.stubs(:value).with(:dbconnections).returns('')
-    Puppet::Rails.database_arguments.should_not be_include(:pool)
-  end
-end
-
-describe Puppet::Rails, "when initializing a postgresql connection", :if => Puppet.features.rails? do
-  it "should provide the adapter, log_level, and host, port, username, password, connections, and database arguments" do
-    Puppet.settings.stubs(:value).with(:dbadapter).returns("postgresql")
-    Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
-    Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
-    Puppet.settings.stubs(:value).with(:dbport).returns("9999")
-    Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
-    Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
-    Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 200).to_s)
-    Puppet.settings.stubs(:value).with(:dbname).returns("testname")
-    Puppet.settings.stubs(:value).with(:dbsocket).returns("")
-
-    Puppet::Rails.database_arguments.should == {
-      :adapter => "postgresql",
-      :log_level => "testlevel",
-      :host => "testserver",
-      :port => "9999",
-      :username => "testuser",
-      :password => "testpassword",
-      :pool => pool_size,
-      :database => "testname",
-      :reconnect => true
-    }
-  end
+['mysql','mysql2','postgresql'].each do |dbadapter|
+  describe Puppet::Rails, "when initializing a #{dbadapter} connection", :if => Puppet.features.rails? do
+    it "should provide the adapter, log_level, and host, port, username, password, database, and reconnect arguments" do
+      Puppet.settings.stubs(:value).with(:dbadapter).returns(dbadapter)
+      Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
+      Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
+      Puppet.settings.stubs(:value).with(:dbport).returns("")
+      Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
+      Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
+      Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 45).to_s)
+      Puppet.settings.stubs(:value).with(:dbname).returns("testname")
+      Puppet.settings.stubs(:value).with(:dbsocket).returns("")
+
+      Puppet::Rails.database_arguments.should == {
+        :adapter => dbadapter,
+        :log_level => "testlevel",
+        :host => "testserver",
+        :username => "testuser",
+        :password => "testpassword",
+        :pool => pool_size,
+        :database => "testname",
+        :reconnect => true
+      }
+    end
 
-  it "should provide the adapter, log_level, and host, port, username, password, database, connections, and socket arguments" do
-    Puppet.settings.stubs(:value).with(:dbadapter).returns("postgresql")
-    Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
-    Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
-    Puppet.settings.stubs(:value).with(:dbport).returns("9999")
-    Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
-    Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
-    Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 122).to_s)
-    Puppet.settings.stubs(:value).with(:dbname).returns("testname")
-    Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket")
+    it "should provide the adapter, log_level, and host, port, username, password, database, socket, connections, and reconnect arguments" do
+      Puppet.settings.stubs(:value).with(:dbadapter).returns(dbadapter)
+      Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
+      Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
+      Puppet.settings.stubs(:value).with(:dbport).returns("9999")
+      Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
+      Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
+      Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 12).to_s)
+      Puppet.settings.stubs(:value).with(:dbname).returns("testname")
+      Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket")
+
+      Puppet::Rails.database_arguments.should == {
+        :adapter => dbadapter,
+        :log_level => "testlevel",
+        :host => "testserver",
+        :port => "9999",
+        :username => "testuser",
+        :password => "testpassword",
+        :pool => pool_size,
+        :database => "testname",
+        :socket => "testsocket",
+        :reconnect => true
+      }
+    end
 
-    Puppet::Rails.database_arguments.should == {
-      :adapter => "postgresql",
-      :log_level => "testlevel",
-      :host => "testserver",
-      :port => "9999",
-      :username => "testuser",
-      :password => "testpassword",
-      :pool => pool_size,
-      :database => "testname",
-      :socket => "testsocket",
-      :reconnect => true
-    }
-  end
+    it "should provide the adapter, log_level, and host, port, username, password, database, socket, and connections arguments" do
+      Puppet.settings.stubs(:value).with(:dbadapter).returns(dbadapter)
+      Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
+      Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
+      Puppet.settings.stubs(:value).with(:dbport).returns("9999")
+      Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
+      Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
+      Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 23).to_s)
+      Puppet.settings.stubs(:value).with(:dbname).returns("testname")
+      Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket")
+
+      Puppet::Rails.database_arguments.should == {
+        :adapter => dbadapter,
+        :log_level => "testlevel",
+        :host => "testserver",
+        :port => "9999",
+        :username => "testuser",
+        :password => "testpassword",
+        :pool => pool_size,
+        :database => "testname",
+        :socket => "testsocket",
+        :reconnect => true
+      }
+    end
 
-  it "should not provide the pool if dbconnections is 0, '0', or ''" do
-    Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql")
-    Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
-    Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
-    Puppet.settings.stubs(:value).with(:dbport).returns("9999")
-    Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
-    Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
-    Puppet.settings.stubs(:value).with(:dbname).returns("testname")
-    Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket")
+    it "should not provide the pool if dbconnections is 0, '0', or ''" do
+      Puppet.settings.stubs(:value).with(:dbadapter).returns(dbadapter)
+      Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
+      Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
+      Puppet.settings.stubs(:value).with(:dbport).returns("9999")
+      Puppet.settings.stubs(:value).with(:dbuser).returns("testuser")
+      Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword")
+      Puppet.settings.stubs(:value).with(:dbname).returns("testname")
+      Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket")
 
-    Puppet.settings.stubs(:value).with(:dbconnections).returns(0)
-    Puppet::Rails.database_arguments.should_not be_include(:pool)
+      Puppet.settings.stubs(:value).with(:dbconnections).returns(0)
+      Puppet::Rails.database_arguments.should_not be_include(:pool)
 
-    Puppet.settings.stubs(:value).with(:dbconnections).returns('0')
-    Puppet::Rails.database_arguments.should_not be_include(:pool)
+      Puppet.settings.stubs(:value).with(:dbconnections).returns('0')
+      Puppet::Rails.database_arguments.should_not be_include(:pool)
 
-    Puppet.settings.stubs(:value).with(:dbconnections).returns('')
-    Puppet::Rails.database_arguments.should_not be_include(:pool)
+      Puppet.settings.stubs(:value).with(:dbconnections).returns('')
+      Puppet::Rails.database_arguments.should_not be_include(:pool)
+    end
   end
 end
 
@@ -292,7 +223,7 @@
   end
 
   it "should not provide the pool if dbconnections is 0, '0', or ''" do
-    Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql")
+    Puppet.settings.stubs(:value).with(:dbadapter).returns("oracle_enhanced")
     Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel")
     Puppet.settings.stubs(:value).with(:dbserver).returns("testserver")
     Puppet.settings.stubs(:value).with(:dbport).returns("9999")
diff --git a/spec/unit/reports/store_spec.rb b/spec/unit/reports/store_spec.rb
index 73a7e35..5b752c4 100755
--- a/spec/unit/reports/store_spec.rb
+++ b/spec/unit/reports/store_spec.rb
@@ -3,6 +3,9 @@
 
 require 'puppet/reports'
 require 'time'
+require 'pathname'
+require 'tempfile'
+require 'fileutils'
 
 processor = Puppet::Reports.report(:store)
 
@@ -10,7 +13,7 @@
   describe "#process" do
     include PuppetSpec::Files
     before :each do
-      Puppet[:reportdir] = tmpdir('reports') << '/reports' 
+      Puppet[:reportdir] = File.join(tmpdir('reports'), 'reports')
       @report = YAML.load_file(File.join(PuppetSpec::FIXTURE_DIR, 'yaml/report2.6.x.yaml')).extend processor
     end
 
@@ -26,5 +29,20 @@
 
       File.read(File.join(Puppet[:reportdir], @report.host, "201101061200.yaml")).should == @report.to_yaml
     end
+
+    it "should write to the report directory in the correct sequence" do
+      # By doing things in this sequence we should protect against race
+      # conditions
+      Time.stubs(:now).returns(Time.parse("2011-01-06 12:00:00 UTC"))
+      writeseq = sequence("write")
+      file = mock "file"
+      Tempfile.expects(:new).in_sequence(writeseq).returns(file)
+      file.expects(:chmod).in_sequence(writeseq).with(0640)
+      file.expects(:print).with(@report.to_yaml).in_sequence(writeseq)
+      file.expects(:close).in_sequence(writeseq)
+      file.stubs(:path).returns(File.join(Dir.tmpdir, "foo123"))
+      FileUtils.expects(:mv).in_sequence(writeseq).with(File.join(Dir.tmpdir, "foo123"), File.join(Puppet[:reportdir], @report.host, "201101061200.yaml"))
+      @report.process
+    end
   end
 end
diff --git a/spec/unit/resource/catalog_spec.rb b/spec/unit/resource/catalog_spec.rb
index 7406e29..580e1ea 100755
--- a/spec/unit/resource/catalog_spec.rb
+++ b/spec/unit/resource/catalog_spec.rb
@@ -123,165 +123,6 @@
     end
   end
 
-  describe "when extracting transobjects" do
-
-    def mkscope
-      @node = Puppet::Node.new("mynode")
-      @compiler = Puppet::Parser::Compiler.new(@node)
-
-      # XXX This is ridiculous.
-      @compiler.send(:evaluate_main)
-      @scope = @compiler.topscope
-    end
-
-    def mkresource(type, name)
-      Puppet::Parser::Resource.new(type, name, :source => @source, :scope => @scope)
-    end
-
-    it "should fail if no 'main' stage can be found" do
-      lambda { Puppet::Resource::Catalog.new("mynode").extract }.should raise_error(Puppet::DevError)
-    end
-
-    it "should warn if any non-main stages are present" do
-      config = Puppet::Resource::Catalog.new("mynode")
-
-      @scope = mkscope
-      @source = mock 'source'
-
-      main = mkresource("stage", "main")
-      config.add_resource(main)
-
-      other = mkresource("stage", "other")
-      config.add_resource(other)
-
-      Puppet.expects(:warning)
-
-      config.extract
-    end
-
-    it "should always create a TransBucket for the 'main' stage" do
-      config = Puppet::Resource::Catalog.new("mynode")
-
-      @scope = mkscope
-      @source = mock 'source'
-
-      main = mkresource("stage", "main")
-      config.add_resource(main)
-
-      result = config.extract
-      result.type.should == "Stage"
-      result.name.should == "main"
-    end
-
-    # Now try it with a more complicated graph -- a three tier graph, each tier
-    it "should transform arbitrarily deep graphs into isomorphic trees" do
-      config = Puppet::Resource::Catalog.new("mynode")
-
-      @scope = mkscope
-      @scope.stubs(:tags).returns([])
-      @source = mock 'source'
-
-      # Create our scopes.
-      top = mkresource "stage", "main"
-
-      config.add_resource top
-      topbucket = []
-      topbucket.expects(:classes=).with([])
-      top.expects(:to_trans).returns(topbucket)
-      topres = mkresource "file", "/top"
-      topres.expects(:to_trans).returns(:topres)
-      config.add_edge top, topres
-
-      middle = mkresource "class", "middle"
-      middle.expects(:to_trans).returns([])
-      config.add_edge top, middle
-      midres = mkresource "file", "/mid"
-      midres.expects(:to_trans).returns(:midres)
-      config.add_edge middle, midres
-
-      bottom = mkresource "class", "bottom"
-      bottom.expects(:to_trans).returns([])
-      config.add_edge middle, bottom
-      botres = mkresource "file", "/bot"
-      botres.expects(:to_trans).returns(:botres)
-      config.add_edge bottom, botres
-
-      toparray = config.extract
-
-      # This is annoying; it should look like:
-      #   [[[:botres], :midres], :topres]
-      # but we can't guarantee sort order.
-      toparray.include?(:topres).should be_true
-
-      midarray = toparray.find { |t| t.is_a?(Array) }
-      midarray.include?(:midres).should be_true
-      botarray = midarray.find { |t| t.is_a?(Array) }
-      botarray.include?(:botres).should be_true
-    end
-  end
-
-  describe " when converting to a Puppet::Resource catalog" do
-    before do
-      @original = Puppet::Resource::Catalog.new("mynode")
-      @original.tag(*%w{one two three})
-      @original.add_class *%w{four five six}
-
-      @top            = Puppet::TransObject.new 'top', "class"
-      @topobject      = Puppet::TransObject.new '/topobject', "file"
-      @middle         = Puppet::TransObject.new 'middle', "class"
-      @middleobject   = Puppet::TransObject.new '/middleobject', "file"
-      @bottom         = Puppet::TransObject.new 'bottom', "class"
-      @bottomobject   = Puppet::TransObject.new '/bottomobject', "file"
-
-      @resources = [@top, @topobject, @middle, @middleobject, @bottom, @bottomobject]
-
-      @original.add_resource(*@resources)
-
-      @original.add_edge(@top, @topobject)
-      @original.add_edge(@top, @middle)
-      @original.add_edge(@middle, @middleobject)
-      @original.add_edge(@middle, @bottom)
-      @original.add_edge(@bottom, @bottomobject)
-
-      @catalog = @original.to_resource
-    end
-
-    it "should copy over the version" do
-      @original.version = "foo"
-      @original.to_resource.version.should == "foo"
-    end
-
-    it "should convert parser resources to plain resources" do
-      resource = Puppet::Parser::Resource.new(:file, "foo", :scope => stub("scope", :environment => nil, :namespaces => nil), :source => stub("source"))
-      catalog = Puppet::Resource::Catalog.new("whev")
-      catalog.add_resource(resource)
-      new = catalog.to_resource
-      new.resource(:file, "foo").class.should == Puppet::Resource
-    end
-
-    it "should add all resources as Puppet::Resource instances" do
-      @resources.each { |resource| @catalog.resource(resource.ref).should be_instance_of(Puppet::Resource) }
-    end
-
-    it "should copy the tag list to the new catalog" do
-      @catalog.tags.sort.should == @original.tags.sort
-    end
-
-    it "should copy the class list to the new catalog" do
-      @catalog.classes.should == @original.classes
-    end
-
-    it "should duplicate the original edges" do
-      @original.edges.each do |edge|
-        @catalog.edge?(@catalog.resource(edge.source.ref), @catalog.resource(edge.target.ref)).should be_true
-      end
-    end
-
-    it "should set itself as the catalog for each converted resource" do
-      @catalog.vertices.each { |v| v.catalog.object_id.should equal(@catalog.object_id) }
-    end
-  end
-
   describe "when converting to a RAL catalog" do
     before do
       @original = Puppet::Resource::Catalog.new("mynode")
@@ -332,7 +173,7 @@ def mkresource(type, name)
 
     # This tests #931.
     it "should not lose track of resources whose names vary" do
-      changer = Puppet::TransObject.new 'changer', 'test'
+      changer = Puppet::Resource.new :file, @basepath+'/test/', :parameters => {:ensure => :directory}
 
       config = Puppet::Resource::Catalog.new('test')
       config.add_resource(changer)
@@ -340,16 +181,9 @@ def mkresource(type, name)
 
       config.add_edge(@top, changer)
 
-      resource = stub 'resource', :name => "changer2", :title => "changer2", :ref => "Test[changer2]", :catalog= => nil, :remove => nil
-
-      #changer is going to get duplicated as part of a fix for aliases 1094
-      changer.expects(:dup).returns(changer)
-      changer.expects(:to_ral).returns(resource)
-
-      newconfig = nil
-
-      proc { @catalog = config.to_ral }.should_not raise_error
-      @catalog.resource("Test[changer2]").should equal(resource)
+      catalog = config.to_ral
+      catalog.resource("File[#{@basepath}/test/]").should equal(changer)
+      catalog.resource("File[#{@basepath}/test]").should equal(changer)
     end
 
     after do
@@ -367,12 +201,12 @@ def mkresource(type, name)
       @r1 = stub_everything 'r1', :ref => "File[/a]"
       @r1.stubs(:respond_to?).with(:ref).returns(true)
       @r1.stubs(:dup).returns(@r1)
-      @r1.stubs(:is_a?).returns(Puppet::Resource).returns(true)
+      @r1.stubs(:is_a?).with(Puppet::Resource).returns(true)
 
       @r2 = stub_everything 'r2', :ref => "File[/b]"
       @r2.stubs(:respond_to?).with(:ref).returns(true)
       @r2.stubs(:dup).returns(@r2)
-      @r2.stubs(:is_a?).returns(Puppet::Resource).returns(true)
+      @r2.stubs(:is_a?).with(Puppet::Resource).returns(true)
 
       @resources = [@r1,@r2]
 
diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb
index 352f767..416fbac 100755
--- a/spec/unit/resource/type_spec.rb
+++ b/spec/unit/resource/type_spec.rb
@@ -238,9 +238,10 @@ def double_convert
 
   describe "when setting its parameters in the scope" do
     before do
-      @scope = Puppet::Parser::Scope.new(:compiler => stub("compiler", :environment => Puppet::Node::Environment.new), :source => stub("source"))
+      @scope = Puppet::Parser::Scope.new
       @resource = Puppet::Parser::Resource.new(:foo, "bar", :scope => @scope)
-      @type = Puppet::Resource::Type.new(:hostclass, "foo")
+      @type = Puppet::Resource::Type.new(:definition, "foo")
+      @resource.environment.known_resource_types.add @type
     end
 
     ['module_name', 'name', 'title'].each do |variable|
@@ -249,20 +250,20 @@ def double_convert
         var = Puppet::Parser::AST::Variable.new({'value' => variable})
         @type.set_arguments :foo => var
         @type.set_resource_parameters(@resource, @scope)
-        @scope.lookupvar('foo').should == 'bar'
+        @scope['foo'].should == 'bar'
       end
     end
 
     # this test is to clarify a crazy edge case
     # if you specify these special names as params, the resource
     # will override the special variables
-    it "resource should override defaults" do
+    it "should allow the resource to override defaults" do
       @type.set_arguments :name => nil
       @resource[:name] = 'foobar'
       var = Puppet::Parser::AST::Variable.new({'value' => 'name'})
       @type.set_arguments :foo => var
       @type.set_resource_parameters(@resource, @scope)
-      @scope.lookupvar('foo').should == 'foobar'
+      @scope['foo'].should == 'foobar'
     end
 
     it "should set each of the resource's parameters as variables in the scope" do
@@ -272,8 +273,8 @@ def double_convert
 
       @type.set_resource_parameters(@resource, @scope)
 
-      @scope.lookupvar("foo").should == "bar"
-      @scope.lookupvar("boo").should == "baz"
+      @scope['foo'].should == "bar"
+      @scope['boo'].should == "baz"
     end
 
     it "should set the variables as strings" do
@@ -282,7 +283,7 @@ def double_convert
 
       @type.set_resource_parameters(@resource, @scope)
 
-      @scope.lookupvar("foo").should == "bar"
+      @scope['foo'].should == "bar"
     end
 
     it "should fail if any of the resource's parameters are not valid attributes" do
@@ -293,13 +294,13 @@ def double_convert
     end
 
     it "should evaluate and set its default values as variables for parameters not provided by the resource" do
-      @type.set_arguments :foo => stub("value", :safeevaluate => "something")
+      @type.set_arguments :foo => Puppet::Parser::AST::String.new(:value => "something")
       @type.set_resource_parameters(@resource, @scope)
-      @scope.lookupvar("foo").should == "something"
+      @scope['foo'].should == "something"
     end
 
     it "should set all default values as parameters in the resource" do
-      @type.set_arguments :foo => stub("value", :safeevaluate => "something")
+      @type.set_arguments :foo => Puppet::Parser::AST::String.new(:value => "something")
 
       @type.set_resource_parameters(@resource, @scope)
 
@@ -308,7 +309,6 @@ def double_convert
 
     it "should fail if the resource does not provide a value for a required argument" do
       @type.set_arguments :foo => nil
-      @resource.expects(:to_hash).returns({})
 
       lambda { @type.set_resource_parameters(@resource, @scope) }.should raise_error(Puppet::ParseError)
     end
@@ -316,13 +316,13 @@ def double_convert
     it "should set the resource's title as a variable if not otherwise provided" do
       @type.set_resource_parameters(@resource, @scope)
 
-      @scope.lookupvar("title").should == "bar"
+      @scope['title'].should == "bar"
     end
 
     it "should set the resource's name as a variable if not otherwise provided" do
       @type.set_resource_parameters(@resource, @scope)
 
-      @scope.lookupvar("name").should == "bar"
+      @scope['name'].should == "bar"
     end
 
     it "should set its module name in the scope if available" do
@@ -330,7 +330,7 @@ def double_convert
 
       @type.set_resource_parameters(@resource, @scope)
 
-      @scope.lookupvar("module_name").should == "mymod"
+      @scope["module_name"].should == "mymod"
     end
 
     it "should set its caller module name in the scope if available" do
@@ -338,21 +338,20 @@ def double_convert
 
       @type.set_resource_parameters(@resource, @scope)
 
-      @scope.lookupvar("caller_module_name").should == "mycaller"
+      @scope["caller_module_name"].should == "mycaller"
     end
   end
 
   describe "when describing and managing parent classes" do
     before do
-      @code = Puppet::Resource::TypeCollection.new("env")
+      @krt = Puppet::Node::Environment.new.known_resource_types
       @parent = Puppet::Resource::Type.new(:hostclass, "bar")
-      @code.add @parent
+      @krt.add @parent
 
       @child = Puppet::Resource::Type.new(:hostclass, "foo", :parent => "bar")
-      @code.add @child
+      @krt.add @child
 
-      @env   = stub "environment", :known_resource_types => @code
-      @scope = stub "scope", :environment => @env, :namespaces => [""]
+      @scope = Puppet::Parser::Scope.new
     end
 
     it "should be able to define a parent" do
@@ -365,16 +364,16 @@ def double_convert
 
     it "should be able to find parent nodes" do
       parent = Puppet::Resource::Type.new(:node, "bar")
-      @code.add parent
+      @krt.add parent
       child = Puppet::Resource::Type.new(:node, "foo", :parent => "bar")
-      @code.add child
+      @krt.add child
 
       child.parent_type(@scope).should equal(parent)
     end
 
     it "should cache a reference to the parent type" do
-      @code.stubs(:hostclass).with("foo::bar").returns nil
-      @code.expects(:hostclass).with("bar").once.returns @parent
+      @krt.stubs(:hostclass).with("foo::bar").returns nil
+      @krt.expects(:hostclass).with("bar").once.returns @parent
       @child.parent_type(@scope)
       @child.parent_type
     end
@@ -386,7 +385,7 @@ def double_convert
 
     it "should be considered the child of a parent's parent" do
       @grandchild = Puppet::Resource::Type.new(:hostclass, "baz", :parent => "foo")
-      @code.add @grandchild
+      @krt.add @grandchild
 
       @child.parent_type(@scope)
       @grandchild.parent_type(@scope)
@@ -396,7 +395,7 @@ def double_convert
 
     it "should correctly state when it is not another type's child" do
       @notchild = Puppet::Resource::Type.new(:hostclass, "baz")
-      @code.add @notchild
+      @krt.add @notchild
 
       @notchild.should_not be_child_of(@parent)
     end
@@ -406,14 +405,13 @@ def double_convert
     before do
       @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode"))
       @scope = Puppet::Parser::Scope.new :compiler => @compiler
-      @resource = Puppet::Parser::Resource.new(:foo, "yay", :scope => @scope)
+      @resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope)
 
       # This is so the internal resource lookup works, yo.
       @compiler.catalog.add_resource @resource
 
-      @known_resource_types = stub 'known_resource_types'
-      @resource.stubs(:known_resource_types).returns @known_resource_types
       @type = Puppet::Resource::Type.new(:hostclass, "foo")
+      @resource.environment.known_resource_types.add @type
     end
 
     it "should add hostclass names to the classes list" do
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index 7c2c6ac..7bbcaf9 100755
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -111,10 +111,6 @@
       to raise_error ArgumentError, /Puppet::Resource.new does not take a hash/
   end
 
-  it "should be able to produce a backward-compatible reference array" do
-    Puppet::Resource.new("foobar", "/f").to_trans_ref.should == %w{Foobar /f}
-  end
-
   it "should be taggable" do
     Puppet::Resource.ancestors.should be_include(Puppet::Util::Tagging)
   end
@@ -272,6 +268,67 @@
     Puppet::Resource.new("file", "/foo").should_not == Puppet::Resource.new("file", "/f")
   end
 
+  describe "when setting default parameters" do
+    before do
+      @scope = Puppet::Parser::Scope.new
+    end
+
+    it "should fail when asked to set default values and it is not a parser resource" do
+      Puppet::Node::Environment.new.known_resource_types.add(
+        Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "default")})
+      )
+      resource = Puppet::Resource.new("default_param", "name")
+      lambda { resource.set_default_parameters(@scope) }.should raise_error(Puppet::DevError)
+    end
+
+    it "should evaluate and set any default values when no value is provided" do
+      Puppet::Node::Environment.new.known_resource_types.add(
+        Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")})
+      )
+      resource = Puppet::Parser::Resource.new("default_param", "name", :scope => Puppet::Parser::Scope.new)
+      resource.set_default_parameters(@scope)
+      resource["a"].should == "a_default_value"
+    end
+
+    it "should skip attributes with no default value" do
+      Puppet::Node::Environment.new.known_resource_types.add(
+        Puppet::Resource::Type.new(:definition, "no_default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")})
+      )
+      resource = Puppet::Parser::Resource.new("no_default_param", "name", :scope => Puppet::Parser::Scope.new)
+      lambda { resource.set_default_parameters(@scope) }.should_not raise_error
+    end
+
+    it "should return the list of default parameters set" do
+      Puppet::Node::Environment.new.known_resource_types.add(
+        Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")})
+      )
+      resource = Puppet::Parser::Resource.new("default_param", "name", :scope => Puppet::Parser::Scope.new)
+      resource.set_default_parameters(@scope).should == [:a]
+    end
+  end
+
+  describe "when validating all required parameters are present" do
+    it "should be able to validate that all required parameters are present" do
+      Puppet::Node::Environment.new.known_resource_types.add(
+        Puppet::Resource::Type.new(:definition, "required_param", :arguments => {"a" => nil})
+      )
+      lambda { Puppet::Resource.new("required_param", "name").validate_complete }.should raise_error(Puppet::ParseError)
+    end
+
+    it "should not fail when all required parameters are present" do
+      Puppet::Node::Environment.new.known_resource_types.add(
+        Puppet::Resource::Type.new(:definition, "no_required_param")
+      )
+      resource = Puppet::Resource.new("no_required_param", "name")
+      resource["a"] = "meh"
+      lambda { resource.validate_complete }.should_not raise_error
+    end
+
+    it "should not validate against builtin types" do
+      lambda { Puppet::Resource.new("file", "/bar").validate_complete }.should_not raise_error
+    end
+  end
+
   describe "when referring to a resource with name canonicalization" do
     it "should canonicalize its own name" do
       res = Puppet::Resource.new("file", "/path/")
@@ -523,93 +580,6 @@
     end
   end
 
-  describe "when converting to a TransObject" do
-    describe "and the resource is not an instance of a builtin type" do
-      before do
-        @resource = Puppet::Resource.new("foo", "bar")
-      end
-
-      it "should return a simple TransBucket if it is not an instance of a builtin type" do
-        bucket = @resource.to_trans
-        bucket.should be_instance_of(Puppet::TransBucket)
-        bucket.type.should == @resource.type
-        bucket.name.should == @resource.title
-      end
-
-      it "should return a simple TransBucket if it is a stage" do
-        @resource = Puppet::Resource.new("stage", "bar")
-        bucket = @resource.to_trans
-        bucket.should be_instance_of(Puppet::TransBucket)
-        bucket.type.should == @resource.type
-        bucket.name.should == @resource.title
-      end
-
-      it "should copy over the resource's file" do
-        @resource.file = "/foo/bar"
-        @resource.to_trans.file.should == "/foo/bar"
-      end
-
-      it "should copy over the resource's line" do
-        @resource.line = 50
-        @resource.to_trans.line.should == 50
-      end
-    end
-
-    describe "and the resource is an instance of a builtin type" do
-      before do
-        @resource = Puppet::Resource.new("file", "bar")
-      end
-
-      it "should return a TransObject if it is an instance of a builtin resource type" do
-        trans = @resource.to_trans
-        trans.should be_instance_of(Puppet::TransObject)
-        trans.type.should == "file"
-        trans.name.should == @resource.title
-      end
-
-      it "should copy over the resource's file" do
-        @resource.file = "/foo/bar"
-        @resource.to_trans.file.should == "/foo/bar"
-      end
-
-      it "should copy over the resource's line" do
-        @resource.line = 50
-        @resource.to_trans.line.should == 50
-      end
-
-      # Only TransObjects support tags, annoyingly
-      it "should copy over the resource's tags" do
-        @resource.tag "foo"
-        @resource.to_trans.tags.should == @resource.tags
-      end
-
-      it "should copy the resource's parameters into the transobject and convert the parameter name to a string" do
-        @resource[:foo] = "bar"
-        @resource.to_trans["foo"].should == "bar"
-      end
-
-      it "should be able to copy arrays of values" do
-        @resource[:foo] = %w{yay fee}
-        @resource.to_trans["foo"].should == %w{yay fee}
-      end
-
-      it "should reduce single-value arrays to just a value" do
-        @resource[:foo] = %w{yay}
-        @resource.to_trans["foo"].should == "yay"
-      end
-
-      it "should convert resource references into the backward-compatible form" do
-        @resource[:foo] = Puppet::Resource.new(:file, "/f")
-        @resource.to_trans["foo"].should == %w{File /f}
-      end
-
-      it "should convert resource references into the backward-compatible form even when within arrays" do
-        @resource[:foo] = ["a", Puppet::Resource.new(:file, "/f")]
-        @resource.to_trans["foo"].should == ["a", %w{File /f}]
-      end
-    end
-  end
-
   describe "when converting to pson", :if => Puppet.features.pson? do
     def pson_output_should
       @resource.class.expects(:pson_create).with { |hash| yield hash }
diff --git a/spec/unit/ssl/host_spec.rb b/spec/unit/ssl/host_spec.rb
index dd64343..3f94407 100755
--- a/spec/unit/ssl/host_spec.rb
+++ b/spec/unit/ssl/host_spec.rb
@@ -182,57 +182,48 @@
   it "should cache the localhost instance" do
     host = stub 'host', :certificate => "eh", :key => 'foo'
     Puppet::SSL::Host.expects(:new).once.returns host
-
     Puppet::SSL::Host.localhost.should == Puppet::SSL::Host.localhost
   end
 
   it "should be able to verify its certificate matches its key" do
-    Puppet::SSL::Host.new("foo").should respond_to(:certificate_matches_key?)
+    Puppet::SSL::Host.new("foo").should respond_to(:validate_certificate_with_key)
   end
 
   it "should consider the certificate invalid if it cannot find a key" do
     host = Puppet::SSL::Host.new("foo")
+    certificate = mock('cert', :fingerprint => 'DEADBEEF')
+    host.expects(:certificate).twice.returns certificate
     host.expects(:key).returns nil
-
-    host.should_not be_certificate_matches_key
+    lambda { host.validate_certificate_with_key }.should raise_error(Puppet::Error, "No private key with which to validate certificate with fingerprint: DEADBEEF")
   end
 
   it "should consider the certificate invalid if it cannot find a certificate" do
     host = Puppet::SSL::Host.new("foo")
-    host.expects(:key).returns mock("key")
+    host.expects(:key).never
     host.expects(:certificate).returns nil
-
-    host.should_not be_certificate_matches_key
+    lambda { host.validate_certificate_with_key }.should raise_error(Puppet::Error, "No certificate to validate.")
   end
 
   it "should consider the certificate invalid if the SSL certificate's key verification fails" do
     host = Puppet::SSL::Host.new("foo")
-
     key = mock 'key', :content => "private_key"
     sslcert = mock 'sslcert'
-    certificate = mock 'cert', :content => sslcert
-
+    certificate = mock 'cert', {:content => sslcert, :fingerprint => 'DEADBEEF'}
     host.stubs(:key).returns key
     host.stubs(:certificate).returns certificate
-
     sslcert.expects(:check_private_key).with("private_key").returns false
-
-    host.should_not be_certificate_matches_key
+    lambda { host.validate_certificate_with_key }.should raise_error(Puppet::Error, /DEADBEEF/)
   end
 
   it "should consider the certificate valid if the SSL certificate's key verification succeeds" do
     host = Puppet::SSL::Host.new("foo")
-
     key = mock 'key', :content => "private_key"
     sslcert = mock 'sslcert'
     certificate = mock 'cert', :content => sslcert
-
     host.stubs(:key).returns key
     host.stubs(:certificate).returns certificate
-
     sslcert.expects(:check_private_key).with("private_key").returns true
-
-    host.should be_certificate_matches_key
+    lambda{ host.validate_certificate_with_key }.should_not raise_error
   end
 
   describe "when specifying the CA location" do
@@ -511,15 +502,13 @@
     before do
       @realcert = mock 'certificate'
       @cert = stub 'cert', :content => @realcert
-
       @host.stubs(:key).returns mock("key")
-      @host.stubs(:certificate_matches_key?).returns true
+      @host.stubs(:validate_certificate_with_key)
     end
 
     it "should find the CA certificate if it does not have a certificate" do
       Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert")
       Puppet::SSL::Certificate.indirection.stubs(:find).with("myname").returns @cert
-
       @host.certificate
     end
 
@@ -541,34 +530,22 @@
     it "should find the key if it does not have one" do
       Puppet::SSL::Certificate.indirection.stubs(:find)
       @host.expects(:key).returns mock("key")
-
       @host.certificate
     end
 
     it "should generate the key if one cannot be found" do
       Puppet::SSL::Certificate.indirection.stubs(:find)
-
       @host.expects(:key).returns nil
       @host.expects(:generate_key)
-
       @host.certificate
     end
 
     it "should find the certificate in the Certificate class and return the Puppet certificate instance" do
       Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert")
       Puppet::SSL::Certificate.indirection.expects(:find).with("myname").returns @cert
-
       @host.certificate.should equal(@cert)
     end
 
-    it "should fail if the found certificate does not match the private key" do
-      @host.expects(:certificate_matches_key?).returns false
-
-      Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert
-
-      lambda { @host.certificate }.should raise_error(Puppet::Error)
-    end
-
     it "should return any previously found certificate" do
       Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert")
       Puppet::SSL::Certificate.indirection.expects(:find).with("myname").returns(@cert).once
diff --git a/spec/unit/transaction/report_spec.rb b/spec/unit/transaction/report_spec.rb
index fe5c2e2..2e69b35 100755
--- a/spec/unit/transaction/report_spec.rb
+++ b/spec/unit/transaction/report_spec.rb
@@ -29,7 +29,7 @@
   end
 
   it "should take a 'configuration_version' as an argument" do
-    Puppet::Transaction::Report.new("inspect", "some configuration version").configuration_version.should == "some configuration version"
+    Puppet::Transaction::Report.new("inspect", "some configuration version", "some environment").configuration_version.should == "some configuration version"
   end
 
   it "should be able to set configuration_version" do
@@ -38,6 +38,16 @@
     report.configuration_version.should == "some version"
   end
 
+  it "should take 'environment' as an argument" do
+    Puppet::Transaction::Report.new("inspect", "some configuration version", "some environment").environment.should == "some environment"
+  end
+
+  it "should be able to set environment" do
+    report = Puppet::Transaction::Report.new("inspect")
+    report.environment = "some environment"
+    report.environment.should == "some environment"
+  end
+
   it "should not include whits" do
     Puppet::FileBucket::File.indirection.stubs(:save)
 
@@ -179,6 +189,11 @@ def add_statuses(count, type = :file)
           @report.finalize_report
           metric(:resources, state.to_s).should == 3
         end
+
+        it "should provide 0 for states not in status" do
+          @report.finalize_report
+          metric(:resources, state.to_s).should == 0
+        end
       end
 
       it "should mark the report as 'failed' if there are failing resources" do
@@ -274,13 +289,14 @@ def add_statuses(count, type = :file)
       resource = Puppet::Type.type(:notify).new(:name => "testing")
       catalog = Puppet::Resource::Catalog.new
       catalog.add_resource resource
+      catalog.version = 1234567
       trans = catalog.apply
 
       @report = trans.report
       @report.finalize_report
     end
 
-    %w{changes time resources events}.each do |main|
+    %w{changes time resources events version}.each do |main|
       it "should include the key #{main} in the raw summary hash" do
         @report.raw_summary.should be_key main
       end
@@ -291,6 +307,28 @@ def add_statuses(count, type = :file)
       @report.raw_summary["time"]["last_run"].should == 1289390424
     end
 
+    it "should include all resource statuses" do
+      resources_report = @report.raw_summary["resources"]
+      Puppet::Resource::Status::STATES.each do |state|
+        resources_report.should be_include(state.to_s)
+      end
+    end
+
+    %w{total failure success}.each do |r|
+      it "should include event #{r}" do
+        events_report = @report.raw_summary["events"]
+        events_report.should be_include(r)
+      end
+    end
+
+    it "should include config version" do
+      @report.raw_summary["version"]["config"].should == 1234567
+    end
+
+    it "should include puppet version" do
+      @report.raw_summary["version"]["puppet"].should == Puppet.version
+    end
+
     %w{Changes Total Resources Time Events}.each do |main|
       it "should include information on #{main} in the textual summary" do
         @report.summary.should be_include(main)
diff --git a/spec/unit/transportable_spec.rb b/spec/unit/transportable_spec.rb
deleted file mode 100755
index e69de29..0000000
diff --git a/spec/unit/type/file/content_spec.rb b/spec/unit/type/file/content_spec.rb
index 108acc0..d27fe5b 100755
--- a/spec/unit/type/file/content_spec.rb
+++ b/spec/unit/type/file/content_spec.rb
@@ -2,6 +2,8 @@
 require 'spec_helper'
 require 'puppet/network/http_pool'
 
+require 'puppet/network/resolver'
+
 content = Puppet::Type.type(:file).attrclass(:content)
 describe content do
   include PuppetSpec::Files
@@ -332,7 +334,7 @@
         @response.stubs(:read_body).multiple_yields(*(["source file content\n"]*10000))
 
         @conn = stub_everything 'connection'
-        @conn.stubs(:request_get).yields(@response)
+        @conn.stubs(:request_get).yields @response
         Puppet::Network::HttpPool.stubs(:http_instance).returns @conn
 
         @content = @resource.newattr(:content)
diff --git a/spec/unit/type/file/source_spec.rb b/spec/unit/type/file/source_spec.rb
index f776457..50e3679 100755
--- a/spec/unit/type/file/source_spec.rb
+++ b/spec/unit/type/file/source_spec.rb
@@ -156,8 +156,10 @@
       @resource = Puppet::Type.type(:file).new :path => @foobar
 
       @source = source.new(:resource => @resource)
-      @metadata = stub 'metadata', :owner => 100, :group => 200, :mode => 123, :checksum => "{md5}asdfasdf", :ftype => "file"
+      @metadata = stub 'metadata', :owner => 100, :group => 200, :mode => 123, :checksum => "{md5}asdfasdf", :ftype => "file", :source => @foobar
       @source.stubs(:metadata).returns @metadata
+
+      Puppet.features.stubs(:root?).returns true
     end
 
     it "should fail if there is no metadata" do
@@ -184,11 +186,10 @@
     describe "and the source is a file" do
       before do
         @metadata.stubs(:ftype).returns "file"
+        Puppet.features.stubs(:microsoft_windows?).returns false
       end
 
       it "should copy the metadata's owner, group, checksum, and mode to the resource if they are not set on the resource" do
-        Puppet.features.expects(:root?).returns true
-
         @source.copy_source_values
 
         @resource[:owner].must == 100
@@ -221,6 +222,30 @@
           @resource[:owner].should be_nil
         end
       end
+
+      describe "on Windows" do
+        before :each do
+          Puppet.features.stubs(:microsoft_windows?).returns true
+        end
+
+        it "should not copy owner and group from remote sources" do
+          @source.stubs(:local?).returns false
+
+          @source.copy_source_values
+
+          @resource[:owner].must be_nil
+          @resource[:group].must be_nil
+        end
+
+        it "should copy owner and group from local sources" do
+          @source.stubs(:local?).returns true
+
+          @source.copy_source_values
+
+          @resource[:owner].must == 100
+          @resource[:group].must == 200
+        end
+      end
     end
 
     describe "and the source is a link" do
diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb
index cf278b4..caedf4d 100755
--- a/spec/unit/type/file_spec.rb
+++ b/spec/unit/type/file_spec.rb
@@ -500,8 +500,9 @@
     end
 
     it "should not copy values to the child which were set by the source" do
-      file[:source] = File.expand_path(__FILE__)
-      metadata = stub 'metadata', :owner => "root", :group => "root", :mode => 0755, :ftype => "file", :checksum => "{md5}whatever"
+      source = File.expand_path(__FILE__)
+      file[:source] = source
+      metadata = stub 'metadata', :owner => "root", :group => "root", :mode => 0755, :ftype => "file", :checksum => "{md5}whatever", :source => source
       file.parameter(:source).stubs(:metadata).returns metadata
 
       file.parameter(:source).copy_source_values
@@ -1253,6 +1254,36 @@
   end
 
   describe "when autorequiring" do
+    describe "target" do
+      it "should require file resource when specified with the target property" do
+        file = described_class.new(:path => File.expand_path("/foo"), :ensure => :directory)
+        link = described_class.new(:path => File.expand_path("/bar"), :ensure => :symlink, :target => File.expand_path("/foo"))
+        catalog.add_resource file
+        catalog.add_resource link
+        reqs = link.autorequire
+        reqs.size.must == 1
+        reqs[0].source.must == file
+        reqs[0].target.must == link
+      end
+
+      it "should require file resource when specified with the ensure property" do
+        file = described_class.new(:path => File.expand_path("/foo"), :ensure => :directory)
+        link = described_class.new(:path => File.expand_path("/bar"), :ensure => File.expand_path("/foo"))
+        catalog.add_resource file
+        catalog.add_resource link
+        reqs = link.autorequire
+        reqs.size.must == 1
+        reqs[0].source.must == file
+        reqs[0].target.must == link
+      end
+
+      it "should not require target if target is not managed" do
+        link = described_class.new(:path => File.expand_path('/foo'), :ensure => :symlink, :target => '/bar')
+        catalog.add_resource link
+        link.autorequire.size.should == 0
+      end
+    end
+
     describe "directories" do
       it "should autorequire its parent directory" do
         dir = described_class.new(:path => File.dirname(path))
diff --git a/spec/unit/type/schedule_spec.rb b/spec/unit/type/schedule_spec.rb
index b302d95..d407057 100755
--- a/spec/unit/type/schedule_spec.rb
+++ b/spec/unit/type/schedule_spec.rb
@@ -82,17 +82,17 @@ def min(method, count)
 
     it "should match when the start time is before the current time and the end time is after the current time" do
       @schedule[:range] = "10:59:50 - 11:00:10"
-      @schedule.should be_match
+      @schedule.must be_match
     end
 
     it "should not match when the start time is after the current time" do
       @schedule[:range] = "11:00:05 - 11:00:10"
-      @schedule.should_not be_match
+      @schedule.must_not be_match
     end
 
     it "should not match when the end time is previous to the current time" do
       @schedule[:range] = "10:59:50 - 10:59:55"
-      @schedule.should be_match
+      @schedule.must_not be_match
     end
 
     it "should throw an error if the upper limit is less than the lower limit" do
@@ -103,17 +103,17 @@ def min(method, count)
 
     it "should not match the current time fails between an array of ranges" do
       @schedule[:range] = ["4-6", "20-23"]
-      @schedule.should_not be_match
+      @schedule.must_not be_match
     end
 
     it "should match the lower array of ranges" do
       @schedule[:range] = ["9-11", "14-16"]
-      @schedule.should be_match
+      @schedule.must be_match
     end
 
     it "should match the upper array of ranges" do
       @schedule[:range] = ["4-6", "11-12"]
-      @schedule.should be_match
+      @schedule.must be_match
     end
   end
 
diff --git a/spec/unit/type_spec.rb b/spec/unit/type_spec.rb
index 3b5f0cb..397ef39 100755
--- a/spec/unit/type_spec.rb
+++ b/spec/unit/type_spec.rb
@@ -261,13 +261,6 @@
   end
 
   describe "when initializing" do
-    describe "and passed a TransObject" do
-      it "should fail" do
-        trans = Puppet::TransObject.new("/foo", :mount)
-        lambda { Puppet::Type.type(:mount).new(trans) }.should raise_error(Puppet::DevError)
-      end
-    end
-
     describe "and passed a Puppet::Resource instance" do
       it "should set its title to the title of the resource if the resource type is equal to the current type" do
         resource = Puppet::Resource.new(:mount, "/foo", :parameters => {:name => "/other"})
@@ -501,6 +494,32 @@
     end
   end
 
+  describe "#to_resource" do
+    it "should return a Puppet::Resource that includes properties, parameters and tags" do
+      type_resource = Puppet::Type.type(:mount).new(
+        :ensure   => :present,
+        :name     => "foo",
+        :fstype   => "bar",
+        :remounts => true
+      )
+      type_resource.tags = %w{bar baz}
+
+      # If it's not a property it's a parameter
+      type_resource.parameters[:remounts].should_not be_a(Puppet::Property)
+      type_resource.parameters[:fstype].is_a?(Puppet::Property).should be_true
+
+      type_resource.property(:ensure).expects(:retrieve).returns :present
+      type_resource.property(:fstype).expects(:retrieve).returns 15
+
+      resource = type_resource.to_resource
+
+      resource.should be_a Puppet::Resource
+      resource[:fstype].should   == 15
+      resource[:remounts].should == :true
+      resource.tags.should       =~ %w{foo bar baz mount}
+    end
+  end
+
   describe ".title_patterns" do
     describe "when there's one namevar" do
       before do
@@ -588,6 +607,35 @@
       resource.should_not be_suitable
     end
   end
+
+  describe "::ensurable?" do
+    before :each do
+      class TestEnsurableType < Puppet::Type
+        def exists?; end
+        def create; end
+        def destroy; end
+      end
+    end
+
+    it "is true if the class has exists?, create, and destroy methods defined" do
+      TestEnsurableType.should be_ensurable
+    end
+
+    it "is false if exists? is not defined" do
+      TestEnsurableType.class_eval { remove_method(:exists?) }
+      TestEnsurableType.should_not be_ensurable
+    end
+
+    it "is false if create is not defined" do
+      TestEnsurableType.class_eval { remove_method(:create) }
+      TestEnsurableType.should_not be_ensurable
+    end
+
+    it "is false if destroy is not defined" do
+      TestEnsurableType.class_eval { remove_method(:destroy) }
+      TestEnsurableType.should_not be_ensurable
+    end
+  end
 end
 
 describe Puppet::Type::RelationshipMetaparam do
diff --git a/spec/unit/util/anonymous_filelock_spec.rb b/spec/unit/util/anonymous_filelock_spec.rb
new file mode 100644
index 0000000..784ac0f
--- /dev/null
+++ b/spec/unit/util/anonymous_filelock_spec.rb
@@ -0,0 +1,78 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/anonymous_filelock'
+
+describe Puppet::Util::AnonymousFilelock do
+  require 'puppet_spec/files'
+  include PuppetSpec::Files
+
+  before(:each) do
+    @lockfile = tmpfile("lock")
+    @lock = Puppet::Util::AnonymousFilelock.new(@lockfile)
+  end
+
+  it "should be anonymous" do
+    @lock.should be_anonymous
+  end
+
+  describe "#lock" do
+    it "should return false if already locked" do
+      @lock.stubs(:locked?).returns(true)
+      @lock.lock.should be_false
+    end
+
+    it "should return true if it successfully locked" do
+      @lock.lock.should be_true
+    end
+
+    it "should create a lock file" do
+      @lock.lock
+
+      File.should be_exists(@lockfile)
+    end
+
+    it "should create a lock file containing a message" do
+      @lock.lock("message")
+
+      File.read(@lockfile).should == "message"
+    end
+  end
+
+  describe "#unlock" do
+    it "should return true when unlocking" do
+      @lock.lock
+      @lock.unlock.should be_true
+    end
+
+    it "should return false when not locked" do
+      @lock.unlock.should be_false
+    end
+
+    it "should clear the lock file" do
+      File.open(@lockfile, 'w') { |fd| fd.print("locked") }
+      @lock.unlock
+      File.should_not be_exists(@lockfile)
+    end
+  end
+
+  it "should be locked when locked" do
+    @lock.lock
+    @lock.should be_locked
+  end
+
+  it "should not be locked when not locked" do
+    @lock.should_not be_locked
+  end
+
+  it "should not be locked when unlocked" do
+    @lock.lock
+    @lock.unlock
+    @lock.should_not be_locked
+  end
+
+  it "should return the lock message" do
+    @lock.lock("lock message")
+    @lock.message.should == "lock message"
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/instrumentation/data_spec.rb b/spec/unit/util/instrumentation/data_spec.rb
new file mode 100755
index 0000000..c2465f6
--- /dev/null
+++ b/spec/unit/util/instrumentation/data_spec.rb
@@ -0,0 +1,44 @@
+#!/usr/bin/env rspec
+
+require 'spec_helper'
+require 'matchers/json'
+require 'puppet/util/instrumentation'
+require 'puppet/util/instrumentation/data'
+
+describe Puppet::Util::Instrumentation::Data do
+  Puppet::Util::Instrumentation::Data
+
+  before(:each) do
+    @listener = stub 'listener', :name => "name"
+    Puppet::Util::Instrumentation.stubs(:[]).with("name").returns(@listener)
+  end
+
+  it "should indirect instrumentation_data" do
+    Puppet::Util::Instrumentation::Data.indirection.name.should == :instrumentation_data
+  end
+
+  it "should lookup the corresponding listener" do
+    Puppet::Util::Instrumentation.expects(:[]).with("name").returns(@listener)
+    Puppet::Util::Instrumentation::Data.new("name")
+  end
+
+  it "should error if the listener can not be found" do
+    Puppet::Util::Instrumentation.expects(:[]).with("name").returns(nil)
+    expect { Puppet::Util::Instrumentation::Data.new("name") }.to raise_error
+  end
+
+  it "should return pson data" do
+    data = Puppet::Util::Instrumentation::Data.new("name")
+    @listener.stubs(:data).returns({ :this_is_data  => "here also" })
+    data.should set_json_attribute('name').to("name")
+    data.should set_json_attribute('this_is_data').to("here also")
+  end
+
+  it "should not error if the underlying listener doesn't have data" do
+    lambda { Puppet::Util::Instrumentation::Data.new("name").to_pson }.should_not raise_error
+  end
+
+  it "should return a hash containing data when unserializing from pson" do
+    Puppet::Util::Instrumentation::Data.from_pson({:name => "name"}).should == {:name => "name"}
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/instrumentation/indirection_probe_spec.rb b/spec/unit/util/instrumentation/indirection_probe_spec.rb
new file mode 100644
index 0000000..654825c
--- /dev/null
+++ b/spec/unit/util/instrumentation/indirection_probe_spec.rb
@@ -0,0 +1,19 @@
+#!/usr/bin/env rspec
+
+require 'spec_helper'
+require 'matchers/json'
+require 'puppet/util/instrumentation'
+require 'puppet/util/instrumentation/indirection_probe'
+
+describe Puppet::Util::Instrumentation::IndirectionProbe do
+  Puppet::Util::Instrumentation::IndirectionProbe
+
+  it "should indirect instrumentation_probe" do
+    Puppet::Util::Instrumentation::IndirectionProbe.indirection.name.should == :instrumentation_probe
+  end
+
+  it "should return pson data" do
+    probe = Puppet::Util::Instrumentation::IndirectionProbe.new("probe")
+    probe.should set_json_attribute('name').to("probe")
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/instrumentation/instrumentable_spec.rb b/spec/unit/util/instrumentation/instrumentable_spec.rb
new file mode 100755
index 0000000..dd2ad30
--- /dev/null
+++ b/spec/unit/util/instrumentation/instrumentable_spec.rb
@@ -0,0 +1,186 @@
+#!/usr/bin/env rspec
+
+require 'spec_helper'
+
+require 'puppet/util/instrumentation'
+require 'puppet/util/instrumentation/instrumentable'
+
+describe Puppet::Util::Instrumentation::Instrumentable::Probe do
+
+  before(:each) do
+    Puppet::Util::Instrumentation.stubs(:start)
+    Puppet::Util::Instrumentation.stubs(:stop)
+
+    class ProbeTest
+      def mymethod(arg1, arg2, arg3)
+        :it_worked
+      end
+    end
+  end
+
+  after(:each) do
+    if ProbeTest.method_defined?(:instrumented_mymethod)
+      ProbeTest.class_eval {
+        remove_method(:mymethod)
+        alias_method(:mymethod, :instrumented_mymethod)
+      }
+    end
+    Puppet::Util::Instrumentation::Instrumentable.clear_probes
+  end
+
+  describe "when enabling a probe" do
+    it "should raise an error if the probe is already enabled" do
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      probe.enable
+      lambda { probe.enable }.should raise_error
+    end
+
+    it "should rename the original method name" do
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      probe.enable
+      ProbeTest.new.should respond_to(:instrumented_mymethod)
+    end
+
+    it "should create a new method of the original name" do
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      probe.enable
+      ProbeTest.new.should respond_to(:mymethod)
+    end
+  end
+
+  describe "when disabling a probe" do
+    it "should raise an error if the probe is already enabled" do
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      lambda { probe.disable }.should raise_error
+    end
+
+    it "should rename the original method name" do
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      probe.enable
+      probe.disable
+
+      Puppet::Util::Instrumentation.expects(:start).never
+      Puppet::Util::Instrumentation.expects(:stop).never
+      ProbeTest.new.mymethod(1,2,3).should == :it_worked
+    end
+
+    it "should remove the created method" do
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      probe.enable
+      probe.disable
+      ProbeTest.new.should_not respond_to(:instrumented_mymethod)
+    end
+  end
+
+  describe "when a probe is called" do
+    it "should call the original method" do
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      probe.enable
+      test = ProbeTest.new
+      test.expects(:instrumented_mymethod).with(1,2,3)
+      test.mymethod(1,2,3)
+    end
+
+    it "should start the instrumentation" do
+      Puppet::Util::Instrumentation.expects(:start)
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      probe.enable
+      test = ProbeTest.new
+      test.mymethod(1,2,3)
+    end
+
+    it "should stop the instrumentation" do
+      Puppet::Util::Instrumentation.expects(:stop)
+      probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+      probe.enable
+      test = ProbeTest.new
+      test.mymethod(1,2,3)
+    end
+
+    describe "and the original method raises an exception" do
+      it "should propagate the exception" do
+        probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+        probe.enable
+        test = ProbeTest.new
+        test.expects(:instrumented_mymethod).with(1,2,3).raises
+        lambda { test.mymethod(1,2,3) }.should raise_error
+      end
+
+      it "should stop the instrumentation" do
+        Puppet::Util::Instrumentation.expects(:stop)
+        probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest)
+        probe.enable
+        test = ProbeTest.new
+        test.expects(:instrumented_mymethod).with(1,2,3).raises
+        lambda { test.mymethod(1,2,3) }.should raise_error
+      end
+    end
+
+    describe "with a static label" do
+      it "should send the label to the instrumentation layer" do
+        probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest, :label => :mylabel)
+        probe.enable
+        test = ProbeTest.new
+        Puppet::Util::Instrumentation.expects(:start).with { |label,data| label == :mylabel }.returns(42)
+        Puppet::Util::Instrumentation.expects(:stop).with(:mylabel, 42, {})
+        test.mymethod(1,2,3)
+      end
+    end
+
+    describe "with a dynamic label" do
+      it "should send the evaluated label to the instrumentation layer" do
+        probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest, :label => Proc.new { |parent,args| "dynamic#{args[0]}" } )
+        probe.enable
+        test = ProbeTest.new
+        Puppet::Util::Instrumentation.expects(:start).with { |label,data| label == "dynamic1" }.returns(42)
+        Puppet::Util::Instrumentation.expects(:stop).with("dynamic1",42,{})
+        test.mymethod(1,2,3)
+      end
+    end
+
+    describe "with static data" do
+      it "should send the data to the instrumentation layer" do
+        probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest, :data => { :static_data => "nothing" })
+        probe.enable
+        test = ProbeTest.new
+        Puppet::Util::Instrumentation.expects(:start).with { |label,data| data == { :static_data => "nothing" }}
+        test.mymethod(1,2,3)
+      end
+    end
+
+    describe "with dynamic data" do
+      it "should send the evaluated label to the instrumentation layer" do
+        probe = Puppet::Util::Instrumentation::Instrumentable::Probe.new(:mymethod, ProbeTest, :data => Proc.new { |parent, args| { :key => args[0] }  } )
+        probe.enable
+        test = ProbeTest.new
+        Puppet::Util::Instrumentation.expects(:start).with { |label,data| data == { :key => 1 } }
+        Puppet::Util::Instrumentation.expects(:stop)
+        test.mymethod(1,2,3)
+      end
+    end
+  end
+end
+
+describe Puppet::Util::Instrumentation::Instrumentable do
+  before(:each) do
+    class ProbeTest2
+      extend Puppet::Util::Instrumentation::Instrumentable
+      probe :mymethod
+      def mymethod(arg1,arg2,arg3)
+      end
+    end
+  end
+
+  after do
+    Puppet::Util::Instrumentation::Instrumentable.clear_probes
+  end
+
+  it "should allow probe definition" do
+    Puppet::Util::Instrumentation::Instrumentable.probe_names.should be_include("ProbeTest2.mymethod")
+  end
+
+  it "should be able to enable all probes" do
+    Puppet::Util::Instrumentation::Instrumentable.enable_probes
+    ProbeTest2.new.should respond_to(:instrumented_mymethod)
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/instrumentation/listener_spec.rb b/spec/unit/util/instrumentation/listener_spec.rb
new file mode 100755
index 0000000..bc49d26
--- /dev/null
+++ b/spec/unit/util/instrumentation/listener_spec.rb
@@ -0,0 +1,100 @@
+#!/usr/bin/env rspec
+
+require 'spec_helper'
+require 'matchers/json'
+
+require 'puppet/util/instrumentation'
+require 'puppet/util/instrumentation/listener'
+
+describe Puppet::Util::Instrumentation::Listener do
+
+  Listener = Puppet::Util::Instrumentation::Listener
+
+  before(:each) do
+    @delegate = stub 'listener', :notify => nil, :name => 'listener'
+    @listener = Listener.new(@delegate)
+    @listener.enabled = true
+  end
+
+  it "should indirect instrumentation_listener" do
+    Listener.indirection.name.should == :instrumentation_listener
+  end
+
+  it "should raise an error if delegate doesn't support notify" do
+    lambda { Listener.new(Object.new) }.should raise_error
+  end
+
+  it "should not be enabled by default" do
+    Listener.new(@delegate).should_not be_enabled
+  end
+
+  it "should delegate notification" do
+    @delegate.expects(:notify).with(:event, :start, {})
+    listener = Listener.new(@delegate)
+    listener.notify(:event, :start, {})
+  end
+
+  it "should not listen is not enabled" do
+    @listener.enabled = false
+    @listener.should_not be_listen_to(:label)
+  end
+
+  it "should listen to all label if created without pattern" do
+    @listener.should be_listen_to(:improbable_label)
+  end
+
+  it "should listen to specific string pattern" do
+    listener = Listener.new(@delegate, "specific")
+    listener.enabled = true
+    listener.should be_listen_to(:specific)
+  end
+
+  it "should not listen to non-matching string pattern" do
+    listener = Listener.new(@delegate, "specific")
+    listener.enabled = true
+    listener.should_not be_listen_to(:unspecific)
+  end
+
+  it "should listen to specific regex pattern" do
+    listener = Listener.new(@delegate, /spe.*/)
+    listener.enabled = true
+    listener.should be_listen_to(:specific_pattern)
+  end
+
+  it "should not listen to non matching regex pattern" do
+    listener = Listener.new(@delegate, /^match.*/)
+    listener.enabled = true
+    listener.should_not be_listen_to(:not_matching)
+  end
+
+  it "should delegate its name to the underlying listener" do
+    @delegate.expects(:name).returns("myname")
+    @listener.name.should == "myname"
+  end
+
+  it "should delegate data fetching to the underlying listener" do
+    @delegate.expects(:data).returns(:data)
+    @listener.data.should == {:data => :data }
+  end
+
+  describe "when serializing to pson" do
+    it "should return a pson object containing pattern, name and status" do
+      @listener.should set_json_attribute('enabled').to(true)
+      @listener.should set_json_attribute('name').to("listener")
+    end
+  end
+
+  describe "when deserializing from pson" do
+    it "should lookup the archetype listener from the instrumentation layer" do
+      Puppet::Util::Instrumentation.expects(:[]).with("listener").returns(@listener)
+      Puppet::Util::Instrumentation::Listener.from_pson({"name" => "listener"})
+    end
+
+    it "should create a new listener shell instance delegating to the archetypal listener" do
+      Puppet::Util::Instrumentation.expects(:[]).with("listener").returns(@listener)
+      @listener.stubs(:listener).returns(@delegate)
+      Puppet::Util::Instrumentation::Listener.expects(:new).with(@delegate, nil, true)
+      Puppet::Util::Instrumentation::Listener.from_pson({"name" => "listener", "enabled" => true})
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/instrumentation/listeners/log_spec.rb b/spec/unit/util/instrumentation/listeners/log_spec.rb
new file mode 100755
index 0000000..8359625
--- /dev/null
+++ b/spec/unit/util/instrumentation/listeners/log_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+require 'puppet/util/instrumentation'
+
+Puppet::Util::Instrumentation.init
+log = Puppet::Util::Instrumentation.listener(:log)
+
+describe log do
+  before(:each) do
+    @log = log.new
+  end
+
+  it "should have a notify method" do
+    @log.should respond_to(:notify)
+  end
+
+  it "should have a data method" do
+    @log.should respond_to(:data)
+  end
+
+  it "should keep data for stop event" do
+    @log.notify(:test, :stop, { :started => Time.at(123456789), :finished => Time.at(123456790)})
+    @log.data.should == {:test=>["test took 1.0"]}
+  end
+
+  it "should not keep data for start event" do
+    @log.notify(:test, :start, { :started => Time.at(123456789)})
+    @log.data.should be_empty
+  end
+
+  it "should not keep more than 20 events per label" do
+    25.times { @log.notify(:test, :stop, { :started => Time.at(123456789), :finished => Time.at(123456790)}) }
+    @log.data[:test].size.should == 20
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/instrumentation/listeners/performance_spec.rb b/spec/unit/util/instrumentation/listeners/performance_spec.rb
new file mode 100755
index 0000000..4cecbe3
--- /dev/null
+++ b/spec/unit/util/instrumentation/listeners/performance_spec.rb
@@ -0,0 +1,36 @@
+require 'spec_helper'
+require 'puppet/util/instrumentation'
+
+Puppet::Util::Instrumentation.init
+performance = Puppet::Util::Instrumentation.listener(:performance)
+
+describe performance do
+  before(:each) do
+    @performance = performance.new
+  end
+
+  it "should have a notify method" do
+    @performance.should respond_to(:notify)
+  end
+
+  it "should have a data method" do
+    @performance.should respond_to(:data)
+  end
+
+  it "should keep data for stop event" do
+    @performance.notify(:test, :stop, { :started => Time.at(123456789), :finished => Time.at(123456790)})
+    @performance.data.should == {:test=>{:average=>1.0, :count=>1, :min=>1.0, :max=>1.0, :sum=>1.0}}
+  end
+
+  it "should accumulate performance statistics" do
+    @performance.notify(:test, :stop, { :started => Time.at(123456789), :finished => Time.at(123456790)})
+    @performance.notify(:test, :stop, { :started => Time.at(123456789), :finished => Time.at(123456791)})
+
+    @performance.data.should == {:test=>{:average=>1.5, :count=>2, :min=>1.0, :max=>2.0, :sum=>3.0}}
+  end
+
+  it "should not keep data for start event" do
+    @performance.notify(:test, :start, { :started => Time.at(123456789)})
+    @performance.data.should be_empty
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/instrumentation/listeners/process_name_spec.rb b/spec/unit/util/instrumentation/listeners/process_name_spec.rb
new file mode 100755
index 0000000..5212572
--- /dev/null
+++ b/spec/unit/util/instrumentation/listeners/process_name_spec.rb
@@ -0,0 +1,201 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+require 'puppet/util/instrumentation'
+
+Puppet::Util::Instrumentation.init
+process_name = Puppet::Util::Instrumentation.listener(:process_name)
+
+describe process_name do
+  before(:each) do
+    @process_name = process_name.new
+  end
+
+  it "should have a notify method" do
+    @process_name.should respond_to(:notify)
+  end
+
+  it "should not have a data method" do
+    @process_name.should_not respond_to(:data)
+  end
+
+  describe "when managing thread activity" do
+    before(:each) do
+      @process_name.stubs(:setproctitle)
+      @process_name.stubs(:base).returns("base")
+    end
+
+    it "should be able to append activity" do
+      thread1 = stub 'thread1'
+      @process_name.push_activity(:thread1,"activity1")
+      @process_name.push_activity(:thread1,"activity2")
+
+      @process_name.reason[:thread1].should == ["activity1", "activity2"]
+    end
+
+    it "should be able to remove activity" do
+      @process_name.push_activity(:thread1,"activity1")
+      @process_name.push_activity(:thread1,"activity1")
+      @process_name.pop_activity(:thread1)
+
+      @process_name.reason[:thread1].should == ["activity1"]
+    end
+
+    it "should maintain activity thread by thread" do
+      @process_name.push_activity(:thread1,"activity1")
+      @process_name.push_activity(:thread2,"activity2")
+
+      @process_name.reason[:thread1].should == ["activity1"]
+      @process_name.reason[:thread2].should == ["activity2"]
+    end
+
+    it "should set process title" do
+      @process_name.expects(:setproctitle)
+
+      @process_name.push_activity("thread1","activity1")
+    end
+  end
+
+  describe "when computing the current process name" do
+    before(:each) do
+      @process_name.stubs(:setproctitle)
+      @process_name.stubs(:base).returns("base")
+    end
+
+    it "should include every running thread activity" do
+      thread1 = stub 'thread1', :inspect => "\#<Thread:0xdeadbeef run>", :hash => 1
+      thread2 = stub 'thread2', :inspect => "\#<Thread:0x12344321 run>", :hash => 0
+
+      @process_name.push_activity(thread1,"Compiling node1.domain.com")
+      @process_name.push_activity(thread2,"Compiling node4.domain.com")
+      @process_name.push_activity(thread1,"Parsing file site.pp")
+      @process_name.push_activity(thread2,"Parsing file node.pp")
+
+      @process_name.process_name.should =~ /12344321 Compiling node4.domain.com,Parsing file node.pp/
+      @process_name.process_name.should =~ /deadbeef Compiling node1.domain.com,Parsing file site.pp/
+    end
+  end
+
+  describe "when finding base process name" do
+    {:master => "master", :agent => "agent", :user => "puppet"}.each do |program,base|
+      it "should return #{base} for #{program}" do
+        Puppet.run_mode.stubs(:name).returns(program)
+        @process_name.base.should == base
+      end
+    end
+  end
+
+  describe "when finding a thread id" do
+    it "should return the id from the thread inspect string" do
+      thread = stub 'thread', :inspect => "\#<Thread:0x1234abdc run>"
+      @process_name.thread_id(thread).should == "1234abdc"
+    end
+  end
+
+  describe "when scrolling the instrumentation string" do
+    it "should rotate the string of various step" do
+      @process_name.rotate("this is a rotation", 10).should == "rotation -- this is a "
+    end
+
+    it "should not rotate the string for the 0 offset" do
+      @process_name.rotate("this is a rotation", 0).should == "this is a rotation"
+    end
+  end
+
+  describe "when setting process name" do
+    before(:each) do
+      @process_name.stubs(:process_name).returns("12345 activity")
+      @process_name.stubs(:base).returns("base")
+      @oldname = $0
+    end
+
+    after(:each) do
+      $0 = @oldname
+    end
+
+    it "should do it if the feature is enabled" do
+      @process_name.setproctitle
+
+      $0.should == "base: 12345 activity"
+    end
+  end
+
+  describe "when subscribed" do
+    before(:each) do
+      thread = stub 'thread', :inspect => "\#<Thread:0x1234abdc run>"
+      Thread.stubs(:current).returns(thread)
+    end
+
+    it "should start the scroller" do
+      Thread.expects(:new)
+      @process_name.subscribed
+    end
+  end
+
+  describe "when unsubscribed" do
+    before(:each) do
+      @thread = stub 'scroller', :inspect => "\#<Thread:0x1234abdc run>"
+      Thread.stubs(:new).returns(@thread)
+      Thread.stubs(:kill)
+      @oldname = $0
+      @process_name.subscribed
+    end
+
+    after(:each) do
+      $0 = @oldname
+    end
+
+    it "should stop the scroller" do
+      Thread.expects(:kill).with(@thread)
+      @process_name.unsubscribed
+    end
+
+    it "should reset the process name" do
+      $0 = "let's see what happens"
+      @process_name.unsubscribed
+      $0.should == @oldname
+    end
+  end
+
+  describe "when setting a probe" do
+    before(:each) do
+      thread = stub 'thread', :inspect => "\#<Thread:0x1234abdc run>"
+      Thread.stubs(:current).returns(thread)
+      Thread.stubs(:new)
+      @process_name.active = true
+    end
+
+    it "should push current thread activity and execute the block" do
+      @process_name.notify(:instrumentation, :start, {})
+      $0.should == "puppet: 1234abdc instrumentation"
+      @process_name.notify(:instrumentation, :stop, {})
+    end
+
+    it "should finally pop the activity" do
+      @process_name.notify(:instrumentation, :start, {})
+      @process_name.notify(:instrumentation, :stop, {})
+      $0.should == "puppet: "
+    end
+  end
+
+  describe "when scrolling" do
+    it "should do nothing for shorter process names" do
+      @process_name.expects(:setproctitle).never
+      @process_name.scroll
+    end
+
+    it "should call setproctitle" do
+      @process_name.stubs(:process_name).returns("x" * 60)
+      @process_name.expects(:setproctitle)
+      @process_name.scroll
+    end
+
+    it "should increment rotation offset" do
+      name = "x" * 60
+      @process_name.stubs(:process_name).returns(name)
+      @process_name.expects(:rotate).once.with(name,1).returns("")
+      @process_name.expects(:rotate).once.with(name,2).returns("")
+      @process_name.scroll
+      @process_name.scroll
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/instrumentation_spec.rb b/spec/unit/util/instrumentation_spec.rb
new file mode 100755
index 0000000..0d19ee0
--- /dev/null
+++ b/spec/unit/util/instrumentation_spec.rb
@@ -0,0 +1,181 @@
+#!/usr/bin/env rspec
+
+require 'spec_helper'
+
+require 'puppet/util/instrumentation'
+
+describe Puppet::Util::Instrumentation do
+
+  Instrumentation = Puppet::Util::Instrumentation
+
+  after(:each) do
+    Instrumentation.clear
+  end
+
+  it "should instance-load instrumentation listeners" do
+    Instrumentation.instance_loader(:listener).should be_instance_of(Puppet::Util::Autoload)
+  end
+
+  it "should have a method for registering instrumentation listeners" do
+    Instrumentation.should respond_to(:new_listener)
+  end
+
+  it "should have a method for retrieving instrumentation listener by name" do
+    Instrumentation.should respond_to(:listener)
+  end
+
+  describe "when registering listeners" do
+    it "should evaluate the supplied block as code for a class" do
+      Instrumentation.expects(:genclass).returns(Class.new { def notify(label, event, data) ; end })
+      Instrumentation.new_listener(:testing, :label_pattern => :for_this_label, :event => :all) { }
+    end
+
+    it "should subscribe a new listener instance" do
+      Instrumentation.expects(:genclass).returns(Class.new { def notify(label, event, data) ; end })
+      Instrumentation.new_listener(:testing, :label_pattern => :for_this_label, :event => :all) { }
+      Instrumentation.listeners.size.should == 1
+      Instrumentation.listeners[0].pattern.should == "for_this_label"
+    end
+
+    it "should be possible to access listeners by name" do
+      Instrumentation.expects(:genclass).returns(Class.new { def notify(label, event, data) ; end })
+      Instrumentation.new_listener(:testing, :label_pattern => :for_this_label, :event => :all) { }
+      Instrumentation["testing"].should_not be_nil
+    end
+
+    it "should be possible to store a new listener by name" do
+      listener = stub 'listener'
+      Instrumentation["testing"] = listener
+      Instrumentation["testing"].should == listener
+    end
+
+    it "should fail if listener is already subscribed" do
+      listener = stub 'listener', :notify => nil, :name => "mylistener"
+      Instrumentation.subscribe(listener, :for_this_label, :all)
+      expect { Instrumentation.subscribe(listener, :for_this_label, :all) }.to raise_error
+    end
+
+    it 'should call #unsubscribed' do
+      listener = stub 'listener', :notify => nil, :name => "mylistener"
+
+      listener.expects(:subscribed)
+
+      Instrumentation.subscribe(listener, :for_this_label, :all)
+    end
+  end
+
+  describe "when unsubscribing listener" do
+    it "should remove it from the listeners" do
+      listener = stub 'listener', :notify => nil, :name => "mylistener"
+      Instrumentation.subscribe(listener, :for_this_label, :all)
+      Instrumentation.unsubscribe(listener)
+      Instrumentation.listeners.size.should == 0
+    end
+
+    it "should warn if the listener wasn't subscribed" do
+      listener = stub 'listener', :notify => nil, :name => "mylistener"
+      Puppet.expects(:warning)
+      Instrumentation.unsubscribe(listener)
+    end
+
+    it 'should call #unsubscribed' do
+      listener = stub 'listener', :notify => nil, :name => "mylistener"
+      Instrumentation.subscribe(listener, :for_this_label, :all)
+
+      listener.expects(:unsubscribed)
+
+      Instrumentation.unsubscribe(listener)
+    end
+  end
+
+  describe "when firing events" do
+    it "should be able to find all listeners matching a label" do
+      listener = stub 'listener', :notify => nil, :name => "mylistener"
+      Instrumentation.subscribe(listener, :for_this_label, :all)
+      Instrumentation.listeners[0].enabled = true
+
+      count = 0
+      Instrumentation.each_listener(:for_this_label) { |l| count += 1 }
+      count.should == 1
+    end
+
+    it "should fire events to matching listeners" do
+      listener = stub 'listener', :notify => nil, :name => "mylistener"
+      Instrumentation.subscribe(listener, :for_this_label, :all)
+      Instrumentation.listeners[0].enabled = true
+
+      listener.expects(:notify).with(:for_this_label, :start, {})
+
+      Instrumentation.publish(:for_this_label, :start, {})
+    end
+
+    it "should not fire events to non-matching listeners" do
+      listener1 = stub 'listener1', :notify => nil, :name => "mylistener1"
+      listener2 = stub 'listener2', :notify => nil, :name => "mylistener2"
+      Instrumentation.subscribe(listener1, :for_this_label, :all)
+      Instrumentation.listeners[0].enabled = true
+      Instrumentation.subscribe(listener2, :for_this_other_label, :all)
+      Instrumentation.listeners[1].enabled = true
+
+      listener1.expects(:notify).never
+      listener2.expects(:notify).with(:for_this_other_label, :start, {})
+
+      Instrumentation.publish(:for_this_other_label, :start, {})
+    end
+  end
+
+  describe "when instrumenting code" do
+    before(:each) do
+      Instrumentation.stubs(:publish)
+    end
+    describe "with a block" do
+      it "should execute it" do
+        executed = false
+        Instrumentation.instrument(:event) do
+          executed = true
+        end
+        executed.should be_true
+      end
+
+      it "should publish an event before execution" do
+        Instrumentation.expects(:publish).with { |label,event,data| label == :event && event == :start }
+        Instrumentation.instrument(:event) {}
+      end
+
+      it "should publish an event after execution" do
+        Instrumentation.expects(:publish).with { |label,event,data| label == :event && event == :stop }
+        Instrumentation.instrument(:event) {}
+      end
+
+      it "should publish the event even when block raised an exception" do
+        Instrumentation.expects(:publish).with { |label,event,data| label == :event }
+        lambda { Instrumentation.instrument(:event) { raise "not working" } }.should raise_error
+      end
+
+      it "should retain start end finish time of the event" do
+        Instrumentation.expects(:publish).with { |label,event,data| data.include?(:started) and data.include?(:finished) }
+        Instrumentation.instrument(:event) {}
+      end
+    end
+
+    describe "without a block" do
+      it "should raise an error if stop is called with no matching start" do
+        lambda{ Instrumentation.stop(:event) }.should raise_error
+      end
+
+      it "should publish an event on stop" do
+        Instrumentation.expects(:publish).with { |label,event,data| event == :start }
+        Instrumentation.expects(:publish).with { |label,event,data| event == :stop and data.include?(:started) and data.include?(:finished) }
+        data = {}
+        Instrumentation.start(:event, data)
+        Instrumentation.stop(:event, 1, data)
+      end
+
+      it "should return a different id per event" do
+        data = {}
+        Instrumentation.start(:event, data).should == 1
+        Instrumentation.start(:event, data).should == 2
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/pidlock_spec.rb b/spec/unit/util/pidlock_spec.rb
new file mode 100644
index 0000000..37f3ca4
--- /dev/null
+++ b/spec/unit/util/pidlock_spec.rb
@@ -0,0 +1,182 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/pidlock'
+
+describe Puppet::Util::Pidlock do
+  require 'puppet_spec/files'
+  include PuppetSpec::Files
+
+  before(:each) do
+    @lockfile = tmpfile("lock")
+    @lock = Puppet::Util::Pidlock.new(@lockfile)
+  end
+
+  it "should not be anonymous" do
+    @lock.should_not be_anonymous
+  end
+
+  describe "#lock" do
+    it "should not be locked at start" do
+      @lock.should_not be_locked
+    end
+
+    it "should not be mine at start" do
+      @lock.should_not be_mine
+    end
+
+    it "should become locked" do
+      @lock.lock
+      @lock.should be_locked
+    end
+
+    it "should become mine" do
+      @lock.lock
+      @lock.should be_mine
+    end
+
+    it "should be possible to lock multiple times" do
+      @lock.lock
+      lambda { @lock.lock }.should_not raise_error
+    end
+
+    it "should return true when locking" do
+      @lock.lock.should be_true
+    end
+
+    it "should return true if locked by me" do
+      @lock.lock
+      @lock.lock.should be_true
+    end
+
+    it "should return false if locked by someone else" do
+      Process.stubs(:kill)
+      File.open(@lockfile, "w") { |fd| fd.print('0') }
+
+      @lock.lock.should be_false
+    end
+
+    it "should create a lock file" do
+      @lock.lock
+      File.should be_exists(@lockfile)
+    end
+
+    it "should create a lock file containing our pid" do
+      @lock.lock
+      File.read(@lockfile).to_i.should == Process.pid.to_i
+    end
+  end
+
+  describe "#unlock" do
+    it "should not be locked anymore" do
+      @lock.lock
+      @lock.unlock
+      @lock.should_not be_locked
+    end
+
+    it "should return false if not locked" do
+      @lock.unlock.should be_false
+    end
+
+    it "should return true if properly unlocked" do
+      @lock.lock
+      @lock.unlock.should be_true
+    end
+
+    it "should get rid of the lock file" do
+      @lock.lock
+      @lock.unlock
+      File.should_not be_exists(@lockfile)
+    end
+  end
+
+  describe "#locked?" do
+    it "should return true if locked" do
+      @lock.lock
+      @lock.should be_locked
+    end
+  end
+
+  describe "with a stale lock" do
+    before(:each) do
+      Process.stubs(:kill).with(0, 6789)
+      Process.stubs(:kill).with(0, 1234).raises(Errno::ESRCH)
+      Process.stubs(:pid).returns(6789)
+      File.open(@lockfile, 'w') { |fd| fd.write("1234") }
+    end
+
+    it "should not be locked" do
+      @lock.should_not be_locked
+    end
+
+    describe "#lock" do
+      it "should clear stale locks" do
+        @lock.locked?
+        File.should_not be_exists(@lockfile)
+      end
+
+      it "should replace with new locks" do
+        @lock.lock
+        File.should be_exists(@lockfile)
+        @lock.lock_pid.should == 6789
+        @lock.should be_mine
+        @lock.should be_locked
+      end
+    end
+
+    describe "#unlock" do
+      it "should not be allowed" do
+        @lock.unlock.should be_false
+      end
+
+      it "should not remove the lock file" do
+        @lock.unlock
+        File.should be_exists(@lockfile)
+      end
+    end
+  end
+
+  describe "with another process lock" do
+    before(:each) do
+      Process.stubs(:kill).with(0, 6789)
+      Process.stubs(:kill).with(0, 1234)
+      Process.stubs(:pid).returns(6789)
+      File.open(@lockfile, 'w') { |fd| fd.write("1234") }
+    end
+
+    it "should be locked" do
+      @lock.should be_locked
+    end
+
+    it "should not be mine" do
+      @lock.should_not be_mine
+    end
+
+    describe "#lock" do
+      it "should not be possible" do
+        @lock.lock.should be_false
+      end
+
+      it "should not overwrite the lock" do
+        @lock.lock
+        @lock.should_not be_mine
+      end
+    end
+
+    describe "#unlock" do
+      it "should not be possible" do
+        @lock.unlock.should be_false
+      end
+
+      it "should not remove the lock file" do
+        @lock.unlock
+        File.should be_exists(@lockfile)
+      end
+
+      it "should still not be our lock" do
+        @lock.unlock
+        @lock.should_not be_mine
+      end
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/unit/util/queue/stomp_spec.rb b/spec/unit/util/queue/stomp_spec.rb
index 6799bec..7730ab7 100755
--- a/spec/unit/util/queue/stomp_spec.rb
+++ b/spec/unit/util/queue/stomp_spec.rb
@@ -13,7 +13,7 @@
   before do
     # So we make sure we never create a real client instance.
     # Otherwise we'll try to connect, and that's bad.
-    Stomp::Client.stubs(:new).returns stub("client")
+    Stomp::Client.stubs(:new).returns stub("client", :publish => true)
   end
 
   it 'should be registered with Puppet::Util::Queue as :stomp type' do
@@ -22,7 +22,7 @@
 
   describe "when initializing" do
     it "should create a Stomp client instance" do
-      Stomp::Client.expects(:new).returns stub("stomp_client")
+      Stomp::Client.expects(:new).returns stub("stomp_client", :publish => true)
       Puppet::Util::Queue::Stomp.new
     end
 
@@ -65,7 +65,7 @@
 
   describe "when publishing a message" do
     before do
-      @client = stub 'client'
+      @client = stub 'client', :publish => true
       Stomp::Client.stubs(:new).returns @client
       @queue = Puppet::Util::Queue::Stomp.new
     end
@@ -84,11 +84,16 @@
       @client.expects(:publish).with { |queue, msg, options| options[:persistent] == true }
       @queue.publish_message('fooqueue', 'Smite!')
     end
+
+    it "should use send when the gem does not support publish" do
+      Stomp::Client.stubs(:new).returns(stub('client', :send => true))
+      Puppet::Util::Queue::Stomp.new.publish_message('fooqueue', 'Smite!')
+    end
   end
 
   describe "when subscribing to a queue" do
     before do
-      @client = stub 'client', :acknowledge => true
+      @client = stub 'client', :acknowledge => true, :publish => true
       Stomp::Client.stubs(:new).returns @client
       @queue = Puppet::Util::Queue::Stomp.new
     end
diff --git a/spec/unit/util/reference_spec.rb b/spec/unit/util/reference_spec.rb
index 219a673..aa16299 100644
--- a/spec/unit/util/reference_spec.rb
+++ b/spec/unit/util/reference_spec.rb
@@ -8,20 +8,30 @@
     Puppet::Util::Reference.newreference :testreference, :doc => "A peer of the type and configuration references, but with no useful information" do
       my_term = "A term"
       my_definition = <<-EOT
-The definition of this term.
-We should be able to handle multi-line definitions.
+        The definition of this term, marked by a colon and a space.
+        We should be able to handle multi-line definitions. Each subsequent
+        line should left-align with the first word character after the colon
+        used as the definition marker.
 
-We should be able to handle multi-paragraph definitions.
+        We should be able to handle multi-paragraph definitions.
+
+        Leading indentation should be stripped from the definition, which allows
+        us to indent the source string for cosmetic purposes.
       EOT
       my_fragment = markdown_definitionlist(my_term, my_definition)
     end
     Puppet::Util::Reference.reference(:testreference).send(:to_markdown, true)
     my_fragment.should == <<-EOT
 A term
-: The definition of this term.
-    We should be able to handle multi-line definitions.
+: The definition of this term, marked by a colon and a space.
+  We should be able to handle multi-line definitions. Each subsequent
+  line should left-align with the first word character after the colon
+  used as the definition marker.
+
+  We should be able to handle multi-paragraph definitions.
 
-    We should be able to handle multi-paragraph definitions.
+  Leading indentation should be stripped from the definition, which allows
+  us to indent the source string for cosmetic purposes.
 
     EOT
   end
diff --git a/spec/unit/util/retryaction_spec.rb b/spec/unit/util/retryaction_spec.rb
new file mode 100644
index 0000000..90f8e8e
--- /dev/null
+++ b/spec/unit/util/retryaction_spec.rb
@@ -0,0 +1,62 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet/util/retryaction'
+
+describe Puppet::Util::RetryAction do
+  let (:exceptions) {{ Puppet::Error => 'Puppet Error Exception' }}
+
+  it 'should retry on any exception if no acceptable exceptions given' do
+    Puppet::Util::RetryAction.expects(:sleep).with( (((2 ** 1) -1) * 0.1) )
+    Puppet::Util::RetryAction.expects(:sleep).with( (((2 ** 2) -1) * 0.1) )
+
+    expect do
+      Puppet::Util::RetryAction.retry_action( :retries => 2 ) do
+        raise ArgumentError, 'Fake Failure'
+      end
+    end.to raise_exception(Puppet::Util::RetryAction::RetryException::RetriesExceeded)
+  end
+
+  it 'should retry on acceptable exceptions' do
+    Puppet::Util::RetryAction.expects(:sleep).with( (((2 ** 1) -1) * 0.1) )
+    Puppet::Util::RetryAction.expects(:sleep).with( (((2 ** 2) -1) * 0.1) )
+
+    expect do
+      Puppet::Util::RetryAction.retry_action( :retries => 2, :retry_exceptions => exceptions) do
+        raise Puppet::Error, 'Fake Failure'
+      end
+    end.to raise_exception(Puppet::Util::RetryAction::RetryException::RetriesExceeded)
+  end
+
+  it 'should not retry on unacceptable exceptions' do
+    Puppet::Util::RetryAction.expects(:sleep).never
+
+    expect do
+      Puppet::Util::RetryAction.retry_action( :retries => 2, :retry_exceptions => exceptions) do
+        raise ArgumentError
+      end
+    end.to raise_exception(ArgumentError)
+  end
+
+  it 'should succeed if nothing is raised' do
+    Puppet::Util::RetryAction.expects(:sleep).never
+
+    Puppet::Util::RetryAction.retry_action( :retries => 2) do
+      true
+    end
+  end
+
+  it 'should succeed if an expected exception is raised retried and succeeds' do
+    should_retry = nil
+    Puppet::Util::RetryAction.expects(:sleep).once
+
+    Puppet::Util::RetryAction.retry_action( :retries => 2, :retry_exceptions => exceptions) do
+      if should_retry
+        true
+      else
+        should_retry = true
+        raise Puppet::Error, 'Fake error'
+      end
+    end
+  end
+end
diff --git a/spec/unit/util/zaml_spec.rb b/spec/unit/util/zaml_spec.rb
index d77cf99..858ae60 100755
--- a/spec/unit/util/zaml_spec.rb
+++ b/spec/unit/util/zaml_spec.rb
@@ -1,4 +1,16 @@
 #!/usr/bin/env rspec
+# encoding: UTF-8
+#
+# The above encoding line is a magic comment to set the default source encoding
+# of this file for the Ruby interpreter.  It must be on the first or second
+# line of the file if an interpreter is in use.  In Ruby 1.9 and later, the
+# source encoding determines the encoding of String and Regexp objects created
+# from this source file.  This explicit encoding is important becuase otherwise
+# Ruby will pick an encoding based on LANG or LC_CTYPE environment variables.
+# These may be different from site to site so it's important for us to
+# establish a consistent behavior.  For more information on M17n please see:
+# http://links.puppetlabs.com/understanding_m17n
+
 require 'spec_helper'
 
 require 'puppet/util/monkey_patches'
@@ -60,3 +72,28 @@
     x2[2].should equal(x2)
   end
 end
+
+# Note, many of these tests will pass on Ruby 1.8 but fail on 1.9 if the patch
+# fix is not applied to Puppet or there's a regression.  These version
+# dependant failures are intentional since the string encoding behavior changed
+# significantly in 1.9.
+describe "UTF-8 encoded String#to_yaml (Bug #11246)" do
+  # JJM All of these snowmen are different representations of the same
+  # UTF-8 encoded string.
+  let(:snowman)         { 'Snowman: [☃]' }
+  let(:snowman_escaped) { "Snowman: [\xE2\x98\x83]" }
+
+  describe "UTF-8 String Literal" do
+    subject { snowman }
+
+    it "should serialize to YAML" do
+      subject.to_yaml
+    end
+    it "should serialize and deserialize to the same thing" do
+      YAML.load(subject.to_yaml).should == subject
+    end
+    it "should serialize and deserialize to a String compatible with a UTF-8 encoded Regexp" do
+      YAML.load(subject.to_yaml).should =~ /☃/u
+    end
+  end
+end
diff --git a/test/language/ast/variable.rb b/test/language/ast/variable.rb
deleted file mode 100755
index 4bd3818..0000000
--- a/test/language/ast/variable.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env ruby
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppettest/parsertesting'
-
-class TestVariable < Test::Unit::TestCase
-  include PuppetTest
-  include PuppetTest::ParserTesting
-  AST = Puppet::Parser::AST
-
-  def setup
-    super
-    @scope = mkscope
-    @name = "myvar"
-    @var = AST::Variable.new(:value => @name)
-  end
-
-  def test_evaluate
-    assert_equal(:undef, @var.evaluate(@scope), "did not return :undef on unset var")
-    @scope.setvar(@name, "something")
-    assert_equal("something", @var.evaluate(@scope), "incorrect variable value")
-  end
-end
-
diff --git a/test/language/functions.rb b/test/language/functions.rb
index b571da2..2810b12 100755
--- a/test/language/functions.rb
+++ b/test/language/functions.rb
@@ -147,17 +147,17 @@ def test_multipletemplates
 
     # Test that our use of an undefined instance variable does not throw
     # an exception, but only safely continues.
-    scope.setvar("one", "One")
+    scope['one'] = "One"
     assert_nothing_raised do
       ast.evaluate(scope)
     end
 
     # Ensure that we got the output we expected from that evaluation.
-    assert_equal("template One\ntemplate \n", scope.lookupvar("output"), "Undefined template variables do not raise exceptions")
+    assert_equal("template One\ntemplate \n", scope['output'], "Undefined template variables do not raise exceptions")
 
     # Now, fill in the last variable and make sure the whole thing
     # evaluates correctly.
-    scope.setvar("two", "Two")
+    scope['two'] = "Two"
     scope.unsetvar("output")
     assert_nothing_raised do
       ast.evaluate(scope)
@@ -165,7 +165,7 @@ def test_multipletemplates
 
 
       assert_equal(
-        "template One\ntemplate Two\n", scope.lookupvar("output"),
+        "template One\ntemplate Two\n", scope['output'],
 
       "Templates were not handled correctly")
   end
@@ -198,7 +198,7 @@ def test_singletemplates
       ast.evaluate(scope)
     end
 
-    scope.setvar("yay", "this is yay")
+    scope['yay'] = "this is yay"
 
     assert_nothing_raised do
       ast.evaluate(scope)
@@ -206,7 +206,7 @@ def test_singletemplates
 
 
       assert_equal(
-        "template this is yay\n", scope.lookupvar("output"),
+        "template this is yay\n", scope['output'],
 
       "Templates were not handled correctly")
 
@@ -242,14 +242,14 @@ def test_legacyvariables
     end
 
     # Verify that we evaluate and return their value correctly.
-    scope.setvar("deprecated", "deprecated value")
+    scope["deprecated"] = "deprecated value"
     assert_nothing_raised do
       ast.evaluate(scope)
     end
 
 
       assert_equal(
-        "template deprecated value\n", scope.lookupvar("output"),
+        "template deprecated value\n", scope['output'],
 
           "Deprecated template variables were not handled correctly")
   end
@@ -304,7 +304,7 @@ def test_tempatefunction_cannot_see_scopes
     ast = varobj("output", func)
 
     scope = mkscope
-    scope.setvar("myvar", "this is yayness")
+    scope['myvar'] = "this is yayness"
     assert_raise(Puppet::ParseError) do
       ast.evaluate(scope)
     end
@@ -380,15 +380,15 @@ def test_template_defined_vars
       false => "false",
     }.each do |string, value|
       scope = mkscope
-      scope.setvar("yayness", string)
-      assert_equal(string, scope.lookupvar("yayness"))
+      scope['yayness'] = string
+      assert_equal(scope['yayness'], string, "did not correctly evaluate '#{string}'")
 
       assert_nothing_raised("An empty string was not a valid variable value") do
         ast.evaluate(scope)
       end
 
       assert_equal(
-        "template #{value}\n", scope.lookupvar("output"),
+        "template #{value}\n", scope['output'],
         "#{string.inspect} did not get evaluated correctly")
     end
   end
diff --git a/test/language/scope.rb b/test/language/scope.rb
index ccc3596..c80178e 100755
--- a/test/language/scope.rb
+++ b/test/language/scope.rb
@@ -40,24 +40,24 @@ def test_variables
     scopes = {:top => topscope, :mid => midscope, :bot => botscope}
 
     # Set a variable in the top and make sure all three can get it
-    topscope.setvar("first", "topval")
+    topscope['first'] = 'topval'
     scopes.each do |name, scope|
-      assert_equal("topval", scope.lookupvar("first"), "Could not find var in #{name}")
+      assert_equal("topval", scope['first'], "Could not find var in #{name}")
     end
 
     # Now set a var in the midscope and make sure the mid and bottom can see it but not the top
-    midscope.setvar("second", "midval")
-    assert_equal(:undefined, scopes[:top].lookupvar("second"), "Found child var in top scope")
+    midscope['second'] = "midval"
+    assert_nil(scopes[:top]['second'], "Found child var in top scope")
     [:mid, :bot].each do |name|
-      assert_equal("midval", scopes[name].lookupvar("second"), "Could not find var in #{name}")
+      assert_equal("midval", scopes[name]['second'], "Could not find var in #{name}")
     end
 
     # And set something in the bottom, and make sure we only find it there.
-    botscope.setvar("third", "botval")
+    botscope['third'] = "botval"
     [:top, :mid].each do |name|
-      assert_equal(:undefined, scopes[name].lookupvar("third"), "Found child var in top scope")
+      assert_nil(scopes[name]['third'], "Found child var in top scope")
     end
-    assert_equal("botval", scopes[:bot].lookupvar("third"), "Could not find var in bottom scope")
+    assert_equal("botval", scopes[:bot]['third'], "Could not find var in bottom scope")
 
 
     # Test that the scopes convert to hash structures correctly.
@@ -84,7 +84,7 @@ def test_variables
 
     # Finally, check the ability to shadow symbols by adding a shadow to
     # bottomscope, then checking that we see the right stuff.
-    botscope.setvar("first", "shadowval")
+    botscope['first'] = "shadowval"
 
       assert_equal(
         {"third" => "botval", "first" => "shadowval"},
@@ -105,16 +105,16 @@ def test_declarative
     sub = mkscope(:parent => top)
 
     assert_nothing_raised {
-      top.setvar("test","value")
+      top['test'] = "value"
     }
     assert_raise(Puppet::ParseError) {
-      top.setvar("test","other")
+      top['test'] = 'other'
     }
     assert_nothing_raised {
-      sub.setvar("test","later")
+      top['other'] = 'later'
     }
     assert_raise(Puppet::ParseError) {
-      top.setvar("test","yeehaw")
+      top['other'] = 'yeehaw'
     }
   end
 
@@ -259,8 +259,8 @@ def test_namespaces
   def test_lookupvar_with_undef
     scope = mkscope
 
-    scope.setvar("testing", :undef)
-    assert_equal(:undef, scope.lookupvar("testing"), "undef was not returned as :undef")
+    scope['testing'] = :undef
+    assert_equal(:undef, scope['testing'], "undef was not returned as :undef")
   end
 end
 
diff --git a/test/language/snippets.rb b/test/language/snippets.rb
index f34e368..75d86ca 100755
--- a/test/language/snippets.rb
+++ b/test/language/snippets.rb
@@ -74,21 +74,11 @@ def ast2scope(ast)
     scope
   end
 
-  def scope2objs(scope)
-    objs = scope.to_trans
-  end
-
   def snippet2scope(snippet)
     ast = snippet2ast(snippet)
     scope = ast2scope(ast)
   end
 
-  def snippet2objs(snippet)
-    ast = snippet2ast(snippet)
-    scope = ast2scope(ast)
-    objs = scope2objs(scope)
-  end
-
   def properties(type)
     properties = type.validproperties
   end
diff --git a/test/language/transportable.rb b/test/language/transportable.rb
deleted file mode 100755
index d8b5c10..0000000
--- a/test/language/transportable.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
-
-require 'puppet'
-require 'puppet/transportable'
-require 'puppettest'
-require 'puppettest/parsertesting'
-require 'yaml'
-
-class TestTransportable < Test::Unit::TestCase
-  include PuppetTest::ParserTesting
-
-  def test_yamldumpobject
-    obj = mk_transobject
-    obj.to_yaml_properties
-    str = nil
-    assert_nothing_raised {
-      str = YAML.dump(obj)
-    }
-
-    newobj = nil
-    assert_nothing_raised {
-      newobj = YAML.load(str)
-    }
-
-    assert(newobj.name, "Object has no name")
-    assert(newobj.type, "Object has no type")
-  end
-
-  def test_yamldumpbucket
-    objects = %w{/etc/passwd /etc /tmp /var /dev}.collect { |d|
-      mk_transobject(d)
-    }
-    bucket = mk_transbucket(*objects)
-    str = nil
-    assert_nothing_raised {
-      str = YAML.dump(bucket)
-    }
-
-    newobj = nil
-    assert_nothing_raised {
-      newobj = YAML.load(str)
-    }
-
-    assert(newobj.name, "Bucket has no name")
-    assert(newobj.type, "Bucket has no type")
-  end
-
-  # Make sure our 'delve' command is working
-  def test_delve
-    top = mk_transtree do |object, depth, width|
-      object.file = :funtest if width % 2 == 1
-    end
-
-    objects = []
-    buckets = []
-    found = []
-
-    count = 0
-    assert_nothing_raised {
-      top.delve do |object|
-        count += 1
-        if object.is_a? Puppet::TransBucket
-          buckets << object
-        else
-          objects << object
-          if object.file == :funtest
-            found << object
-          end
-        end
-      end
-    }
-
-    top.flatten.each do |obj|
-      assert(objects.include?(obj), "Missing obj #{obj.type}[#{obj.name}]")
-    end
-
-
-          assert_equal(
-        found.length,
-      top.flatten.find_all { |o| o.file == :funtest }.length,
-        
-      "Found incorrect number of objects")
-  end
-end
-
diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb
index 6bae80a..4d32f14 100755
--- a/test/lib/puppettest.rb
+++ b/test/lib/puppettest.rb
@@ -154,9 +154,8 @@ def setup
     end
 
 
-      @configpath = File.join(
-        tmpdir,
-
+    @configpath = File.join(
+      tmpdir,
       "configdir" + @@testcount.to_s + "/"
     )
 
@@ -233,11 +232,11 @@ def tstdir
   def tmpdir
     unless @tmpdir
       @tmpdir = case Facter["operatingsystem"].value
-        when "Darwin"; "/private/tmp"
-        when "SunOS"; "/var/tmp"
+        when "Darwin" then "/private/tmp"
+        when "SunOS"  then "/var/tmp"
         else
           "/tmp"
-            end
+      end
 
 
       @tmpdir = File.join(@tmpdir, "puppettesting#{Process.pid}")
diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb
index 411bad3..b76eaff 100644
--- a/test/lib/puppettest/parsertesting.rb
+++ b/test/lib/puppettest/parsertesting.rb
@@ -345,65 +345,6 @@ def assert_creates(manifest, *files)
     Puppet[:manifest] = oldmanifest
   end
 
-  def mk_transobject(file = "/etc/passwd")
-    obj = nil
-    assert_nothing_raised {
-      obj = Puppet::TransObject.new("file", file)
-      obj["owner"] = "root"
-      obj["mode"] = "644"
-    }
-
-    obj
-  end
-
-  def mk_transbucket(*resources)
-    bucket = nil
-    assert_nothing_raised {
-      bucket = Puppet::TransBucket.new
-      bucket.name = "yayname"
-      bucket.type = "yaytype"
-    }
-
-    resources.each { |o| bucket << o }
-
-    bucket
-  end
-
-  # Make a tree of resources, yielding if desired
-  def mk_transtree(depth = 4, width = 2)
-    top = nil
-    assert_nothing_raised {
-      top = Puppet::TransBucket.new
-      top.name = "top"
-      top.type = "bucket"
-    }
-
-    bucket = top
-
-    file = tempfile
-    depth.times do |i|
-      resources = []
-      width.times do |j|
-        path = tempfile + i.to_s
-        obj = Puppet::TransObject.new("file", path)
-        obj["owner"] = "root"
-        obj["mode"] = "644"
-
-        # Yield, if they want
-        yield(obj, i, j) if block_given?
-
-        resources << obj
-      end
-
-      newbucket = mk_transbucket(*resources)
-
-      bucket.push newbucket
-      bucket = newbucket
-    end
-
-    top
-  end
-
   # Take a list of AST resources, evaluate them, and return the results
   def assert_evaluate(children)
     top = nil
diff --git a/test/lib/puppettest/servertest.rb b/test/lib/puppettest/servertest.rb
index 8248300..852c0ec 100644
--- a/test/lib/puppettest/servertest.rb
+++ b/test/lib/puppettest/servertest.rb
@@ -28,46 +28,5 @@ def mktestmanifest
 
     file
   end
-
-  # create a server, forked into the background
-  def mkserver(handlers = nil)
-    Puppet[:name] = "puppetmasterd"
-    # our default handlers
-    unless handlers
-      handlers = {
-        :CA => {}, # so that certs autogenerate
-        :Master => {
-          :Manifest => mktestmanifest,
-          :UseNodes => false
-        },
-      }
-    end
-
-    # then create the actual server
-    server = nil
-    assert_nothing_raised {
-
-            server = Puppet::Network::HTTPServer::WEBrick.new(
-                
-        :Port => @@port,
-        
-        :Handlers => handlers
-      )
-    }
-
-    # fork it
-    spid = fork {
-      trap(:INT) { server.shutdown }
-      server.start
-    }
-
-    # and store its pid for killing
-    @@tmppids << spid
-
-    # give the server a chance to do its thing
-    sleep 1
-    spid
-  end
-
 end
 
diff --git a/test/lib/puppettest/support/utils.rb b/test/lib/puppettest/support/utils.rb
index 4ecc381..10cfa95 100644
--- a/test/lib/puppettest/support/utils.rb
+++ b/test/lib/puppettest/support/utils.rb
@@ -34,15 +34,6 @@ def datadir(*list)
   # explanatory.
   #
 
-  def newobj(type, name, hash)
-    transport = Puppet::TransObject.new(name, "file")
-    transport[:path] = path
-    transport[:ensure] = "file"
-    assert_nothing_raised {
-      file = transport.to_ral
-    }
-  end
-
   # Turn a list of resources, or possibly a catalog and some resources,
   # into a catalog object.
   def resources2catalog(*resources)
diff --git a/test/network/handler/fileserver.rb b/test/network/handler/fileserver.rb
deleted file mode 100755
index b76f8e1..0000000
--- a/test/network/handler/fileserver.rb
+++ /dev/null
@@ -1,1260 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/handler/fileserver'
-
-class TestFileServer < Test::Unit::TestCase
-  include PuppetTest
-
-  def mkmount(path = nil)
-    mount = nil
-    name = "yaytest"
-    base = path || tempfile
-    Dir.mkdir(base) unless FileTest.exists?(base)
-    # Create a test file
-    File.open(File.join(base, "file"), "w") { |f| f.puts "bazoo" }
-    assert_nothing_raised {
-      mount = Puppet::Network::Handler.fileserver::Mount.new(name, base)
-    }
-
-    mount
-  end
-  # make a simple file source
-  def mktestdir
-    testdir = File.join(tmpdir, "remotefilecopytesting")
-    @@tmpfiles << testdir
-
-    # create a tmpfile
-    pattern = "tmpfile"
-    tmpfile = File.join(testdir, pattern)
-    assert_nothing_raised {
-      Dir.mkdir(testdir)
-      File.open(tmpfile, "w") { |f|
-        3.times { f.puts rand(100) }
-      }
-    }
-
-    [testdir, %r{#{pattern}}, tmpfile]
-  end
-
-  # make a bunch of random test files
-  def mktestfiles(testdir)
-    @@tmpfiles << testdir
-    assert_nothing_raised {
-      files = %w{a b c d e}.collect { |l|
-        name = File.join(testdir, "file#{l}")
-        File.open(name, "w") { |f|
-          f.puts rand(100)
-        }
-
-        name
-      }
-
-      return files
-    }
-  end
-
-  def assert_describe(base, file, server)
-    file = File.basename(file)
-    assert_nothing_raised {
-      desc = server.describe(base + file)
-      assert(desc, "Got no description for #{file}")
-      assert(desc != "", "Got no description for #{file}")
-      assert_match(/^\d+/, desc, "Got invalid description #{desc}")
-    }
-  end
-
-  # test for invalid names
-  def test_namefailures
-    server = nil
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    [" ", "=" "+", "&", "#", "*"].each do |char|
-      assert_raise(Puppet::Network::Handler::FileServerError, "'#{char}' did not throw a failure in fileserver module names") {
-        server.mount("/tmp", "invalid#{char}name")
-      }
-    end
-  end
-
-  # verify that listing the root behaves as expected
-  def test_listroot
-    server = nil
-    testdir, pattern, tmpfile = mktestdir
-
-    file = nil
-    checks = Puppet::Network::Handler.fileserver::CHECKPARAMS
-
-    # and make our fileserver
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    # mount the testdir
-    assert_nothing_raised {
-      server.mount(testdir, "test")
-    }
-
-    # and verify different iterations of 'root' return the same value
-    list = nil
-    assert_nothing_raised {
-      list = server.list("/test/", :manage, true, false)
-    }
-
-    assert(list =~ pattern)
-
-    assert_nothing_raised {
-      list = server.list("/test", :manage, true, false)
-    }
-    assert(list =~ pattern)
-
-  end
-
-  # test listing individual files
-  def test_getfilelist
-    server = nil
-    testdir, pattern, tmpfile = mktestdir
-
-    file = nil
-
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    assert_nothing_raised {
-      server.mount(testdir, "test")
-    }
-
-    # get our listing
-    list = nil
-    sfile = "/test/tmpfile"
-    assert_nothing_raised {
-      list = server.list(sfile, :manage, true, false)
-    }
-
-    output = "/\tfile"
-
-    # verify it got listed as a file
-    assert_equal(output, list)
-
-    # verify we got all fields
-    assert(list !~ /\t\t/)
-
-    # verify that we didn't get the directory itself
-    list.split("\n").each { |line|
-      assert(line !~ %r{remotefile})
-    }
-
-    # and then verify that the contents match
-    contents = File.read(tmpfile)
-
-    ret = nil
-    assert_nothing_raised {
-      ret = server.retrieve(sfile)
-    }
-
-    assert_equal(contents, ret)
-  end
-
-  # check that the fileserver is seeing newly created files
-  def test_seenewfiles
-    server = nil
-    testdir, pattern, tmpfile = mktestdir
-
-
-    newfile = File.join(testdir, "newfile")
-
-    # go through the whole schtick again...
-    file = nil
-    checks = Puppet::Network::Handler.fileserver::CHECKPARAMS
-
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    assert_nothing_raised {
-      server.mount(testdir, "test")
-    }
-
-    list = nil
-    sfile = "/test/"
-    assert_nothing_raised {
-      list = server.list(sfile, :manage, true, false)
-    }
-
-    # create the new file
-    File.open(newfile, "w") { |f|
-      3.times { f.puts rand(100) }
-    }
-
-    newlist = nil
-    assert_nothing_raised {
-      newlist = server.list(sfile, :manage, true, false)
-    }
-
-    # verify the list has changed
-    assert(list != newlist)
-
-    # and verify that we are specifically seeing the new file
-    assert(newlist =~ /newfile/)
-  end
-
-  # verify we can mount /, which is what local file servers will
-  # normally do
-  def test_mountroot
-    server = nil
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    assert_nothing_raised {
-      server.mount("/", "root")
-    }
-
-    testdir, pattern, tmpfile = mktestdir
-
-    list = nil
-    assert_nothing_raised {
-      list = server.list("/root/#{testdir}", :manage, true, false)
-    }
-
-    assert(list =~ pattern)
-    assert_nothing_raised {
-      list = server.list("/root#{testdir}", :manage, true, false)
-    }
-
-    assert(list =~ pattern)
-  end
-
-  # verify that we're correctly recursing the right number of levels
-  def test_recursionlevels
-    server = nil
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    # make our deep recursion
-    basedir = File.join(tmpdir, "recurseremotetesting")
-    testdir = "#{basedir}/with/some/sub/directories/for/the/purposes/of/testing"
-    oldfile = File.join(testdir, "oldfile")
-    assert_nothing_raised {
-      system("mkdir -p #{testdir}")
-      File.open(oldfile, "w") { |f|
-        3.times { f.puts rand(100) }
-      }
-      @@tmpfiles << basedir
-    }
-
-    assert_nothing_raised {
-      server.mount(basedir, "test")
-    }
-
-    # get our list
-    list = nil
-    assert_nothing_raised {
-      list = server.list("/test/with", :manage, false, false)
-    }
-
-    # make sure we only got one line, since we're not recursing
-    assert(list !~ /\n/)
-
-    # for each level of recursion, make sure we get the right list
-    [0, 1, 2].each { |num|
-      assert_nothing_raised {
-        list = server.list("/test/with", :manage, num, false)
-      }
-
-      count = 0
-      while list =~ /\n/
-        list.sub!(/\n/, '')
-        count += 1
-      end
-      assert_equal(num, count)
-    }
-  end
-
-  # verify that we're not seeing the dir we ask for; i.e., that our
-  # list is relative to that dir, not it's parent dir
-  def test_listedpath
-    server = nil
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-
-    # create a deep dir
-    basedir = tempfile
-    testdir = "#{basedir}/with/some/sub/directories/for/testing"
-    oldfile = File.join(testdir, "oldfile")
-    assert_nothing_raised {
-      system("mkdir -p #{testdir}")
-      File.open(oldfile, "w") { |f|
-        3.times { f.puts rand(100) }
-      }
-      @@tmpfiles << basedir
-    }
-
-    # mounty mounty
-    assert_nothing_raised {
-      server.mount(basedir, "localhost")
-    }
-
-    list = nil
-    # and then check a few dirs
-    assert_nothing_raised {
-      list = server.list("/localhost/with", :manage, false, false)
-    }
-
-    assert(list !~ /with/)
-
-    assert_nothing_raised {
-      list = server.list("/localhost/with/some/sub", :manage, true, false)
-    }
-
-    assert(list !~ /sub/)
-  end
-
-  # test many dirs, not necessarily very deep
-  def test_widelists
-    server = nil
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    basedir = tempfile
-    dirs = %w{a set of directories}
-    assert_nothing_raised {
-      Dir.mkdir(basedir)
-      dirs.each { |dir|
-        Dir.mkdir(File.join(basedir, dir))
-      }
-      @@tmpfiles << basedir
-    }
-
-    assert_nothing_raised {
-      server.mount(basedir, "localhost")
-    }
-
-    list = nil
-    assert_nothing_raised {
-      list = server.list("/localhost/", :manage, 1, false)
-    }
-    assert_instance_of(String, list, "Server returned %s instead of string")
-    list = list.split("\n")
-
-    assert_equal(dirs.length + 1, list.length)
-  end
-
-  # verify that 'describe' works as advertised
-  def test_describe
-    server = nil
-    testdir = tstdir
-    files = mktestfiles(testdir)
-
-    file = nil
-    checks = Puppet::Network::Handler.fileserver::CHECKPARAMS
-
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    assert_nothing_raised {
-      server.mount(testdir, "test")
-    }
-
-    # get our list
-    list = nil
-    sfile = "/test/"
-    assert_nothing_raised {
-      list = server.list(sfile, :manage, true, false)
-    }
-
-    # and describe each file in the list
-    assert_nothing_raised {
-      list.split("\n").each { |line|
-        file, type = line.split("\t")
-
-        desc = server.describe(sfile + file)
-      }
-    }
-
-    # and then make sure we can describe everything that we know is there
-    files.each { |file|
-      assert_describe(sfile, file, server)
-    }
-
-    # And then describe some files that we know aren't there
-    retval = nil
-    assert_nothing_raised("Describing non-existent files raised an error") {
-      retval = server.describe(sfile + "noexisties")
-    }
-
-    assert_equal("", retval, "Description of non-existent files returned a value")
-
-    # Now try to describe some sources that don't even exist
-    retval = nil
-
-      assert_raise(
-        Puppet::Network::Handler::FileServerError,
-
-      "Describing non-existent mount did not raise an error") {
-      retval = server.describe("/notmounted/noexisties")
-    }
-
-    assert_nil(retval, "Description of non-existent mounts returned a value")
-  end
-
-  def test_describe_does_not_fail_when_mount_does_not_find_file
-    server = Puppet::Network::Handler.fileserver.new(:Local => true, :Config => false)
-
-    assert_nothing_raised("Failed when describing missing plugins") do
-      server.describe "/plugins"
-    end
-  end
-
-  # test that our config file is parsing and working as planned
-  def test_configfile
-    server = nil
-    basedir = File.join(tmpdir, "fileserverconfigfiletesting")
-    @@tmpfiles << basedir
-
-    # make some dirs for mounting
-    Dir.mkdir(basedir)
-    mounts = {}
-    %w{thing thus the-se those}.each { |dir|
-      path = File.join(basedir, dir)
-      Dir.mkdir(path)
-      mounts[dir] = mktestfiles(path)
-
-    }
-
-    # create an example file with each of them
-    conffile = tempfile
-    @@tmpfiles << conffile
-
-    File.open(conffile, "w") { |f|
-      f.print "# a test config file
-
-[thing]
-  path #{basedir}/thing
-  allow 192.168.0.*
-
-[thus]
-  path #{basedir}/thus
-  allow *.madstop.com, *.kanies.com
-  deny *.sub.madstop.com
-
-[the-se]
-  path #{basedir}/the-se
-
-[those]
-  path #{basedir}/those
-
-"
-  }
-
-
-  # create a server with the file
-  assert_nothing_raised {
-
-    server = Puppet::Network::Handler.fileserver.new(
-
-      :Local => false,
-
-      :Config => conffile
-      )
-    }
-
-    list = nil
-    # run through once with no host/ip info, to verify everything is working
-    mounts.each { |mount, files|
-      mount = "/#{mount}/"
-      assert_nothing_raised {
-        list = server.list(mount, :manage, true, false)
-      }
-
-      assert_nothing_raised {
-        list.split("\n").each { |line|
-          file, type = line.split("\t")
-
-          desc = server.describe(mount + file)
-        }
-      }
-
-      files.each { |f|
-        assert_describe(mount, f, server)
-      }
-    }
-
-    # now let's check that things are being correctly forbidden
-    # this is just a map of names and expected results
-    {
-      "thing" => {
-        :deny => [
-          ["hostname.com", "192.168.1.0"],
-          ["hostname.com", "192.158.0.0"]
-        ],
-        :allow => [
-          ["hostname.com", "192.168.0.0"],
-          ["hostname.com", "192.168.0.245"],
-        ]
-      },
-      "thus" => {
-        :deny => [
-          ["hostname.com", "192.168.1.0"],
-          ["name.sub.madstop.com", "192.158.0.0"]
-        ],
-        :allow => [
-          ["luke.kanies.com", "192.168.0.0"],
-          ["luke.madstop.com", "192.168.0.245"],
-        ]
-      }
-    }.each { |mount, hash|
-      mount = "/#{mount}/"
-
-      # run through the map
-      hash.each { |type, ary|
-        ary.each { |sub|
-          host, ip = sub
-
-          case type
-          when :deny
-
-            assert_raise(
-              Puppet::AuthorizationError,
-
-              "Host #{host}, ip #{ip}, allowed #{mount}") {
-                list = server.list(mount, :manage, true, false, host, ip)
-            }
-          when :allow
-            assert_nothing_raised("Host #{host}, ip #{ip}, denied #{mount}") {
-              list = server.list(mount, :manage, true, false, host, ip)
-            }
-          end
-        }
-      }
-    }
-
-  end
-
-  # Test that we smoothly handle invalid config files
-  def test_configfailures
-    # create an example file with each of them
-    conffile = tempfile
-
-    invalidmounts = {
-      "noexist" => "[noexist]
-  path /this/path/does/not/exist
-  allow 192.168.0.*
-"
-}
-
-  invalidconfigs = [
-    "[not valid]
-  path /this/path/does/not/exist
-  allow 192.168.0.*
-",
-"[valid]
-  invalidstatement
-  path /etc
-  allow 192.168.0.*
-",
-"[valid]
-  allow 192.168.0.*
-"
-]
-
-  invalidmounts.each { |mount, text|
-    File.open(conffile, "w") { |f|
-      f.print text
-      }
-
-
-      # create a server with the file
-      server = nil
-      assert_nothing_raised {
-
-        server = Puppet::Network::Handler.fileserver.new(
-
-          :Local => true,
-
-          :Config => conffile
-        )
-      }
-
-
-        assert_raise(
-          Puppet::Network::Handler::FileServerError,
-
-          "Invalid mount was mounted") {
-            server.list(mount, :manage)
-      }
-    }
-
-    invalidconfigs.each_with_index { |text, i|
-      File.open(conffile, "w") { |f|
-        f.print text
-      }
-
-
-      # create a server with the file
-      server = nil
-
-        assert_raise(
-          Puppet::Network::Handler::FileServerError,
-
-          "Invalid config #{i} did not raise error") {
-
-            server = Puppet::Network::Handler.fileserver.new(
-
-              :Local => true,
-
-              :Config => conffile
-        )
-      }
-    }
-  end
-
-  # verify we reread the config file when it changes
-  def test_filereread
-    server = nil
-
-    conffile = tempfile
-    dir = tstdir
-
-    files = mktestfiles(dir)
-    File.open(conffile, "w") { |f|
-      f.print "# a test config file
-
-[thing]
-  path #{dir}
-  allow test1.domain.com
-"
-  }
-
-  # Reset the timeout, so we reload faster
-  Puppet[:filetimeout] = 0.5
-
-  # start our server with a fast timeout
-  assert_nothing_raised {
-
-    server = Puppet::Network::Handler.fileserver.new(
-
-      :Local => false,
-
-      :Config => conffile
-      )
-    }
-
-    list = nil
-    assert_nothing_raised {
-
-      list = server.list(
-        "/thing/", :manage, false, false,
-
-        "test1.domain.com", "127.0.0.1")
-    }
-    assert(list != "", "List returned nothing in rereard test")
-
-    assert_raise(Puppet::AuthorizationError, "List allowed invalid host") {
-      list = server.list("/thing/", :manage, false, false, "test2.domain.com", "127.0.0.1")
-    }
-
-    sleep 1
-    File.open(conffile, "w") { |f|
-      f.print "# a test config file
-
-[thing]
-  path #{dir}
-  allow test2.domain.com
-"
-  }
-
-  assert_raise(Puppet::AuthorizationError, "List allowed invalid host") {
-    list = server.list("/thing/", :manage, false, false, "test1.domain.com", "127.0.0.1")
-    }
-
-    assert_nothing_raised {
-      list = server.list("/thing/", :manage, false, false, "test2.domain.com", "127.0.0.1")
-    }
-
-    assert(list != "", "List returned nothing in rereard test")
-
-    list = nil
-  end
-
-  # Verify that we get converted to the right kind of string
-  def test_mountstring
-    mount = nil
-    name = "yaytest"
-    path = tmpdir
-    assert_nothing_raised {
-      mount = Puppet::Network::Handler.fileserver::Mount.new(name, path)
-    }
-
-    assert_equal("mount[#{name}]", mount.to_s)
-  end
-
-  def test_servinglinks
-    # Disable the checking, so changes propagate immediately.
-    Puppet[:filetimeout] = -5
-    server = nil
-    source = tempfile
-    file = File.join(source, "file")
-    link = File.join(source, "link")
-    Dir.mkdir(source)
-    File.open(file, "w") { |f| f.puts "yay" }
-    File.symlink(file, link)
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    assert_nothing_raised {
-      server.mount(source, "mount")
-    }
-
-    # First describe the link when following
-    results = {}
-    assert_nothing_raised {
-      server.describe("/mount/link", :follow).split("\t").zip(
-        Puppet::Network::Handler.fileserver::CHECKPARAMS
-      ).each { |v,p| results[p] = v }
-    }
-
-    assert_equal("file", results[:type])
-
-    # Then not
-    results = {}
-    assert_nothing_raised {
-      server.describe("/mount/link", :manage).split("\t").zip(
-        Puppet::Network::Handler.fileserver::CHECKPARAMS
-      ).each { |v,p| results[p] = v }
-    }
-
-    assert_equal("link", results[:type])
-
-    results.each { |p,v|
-      assert(v, "#{p} has no value")
-      assert(v != "", "#{p} has no value")
-    }
-  end
-
-  # Test that substitution patterns in the path are exapanded
-  # properly.  Disabled, because it was testing too much of the process
-  # and in a non-portable way.  This is a thorough enough test that it should
-  # be kept, but it should be done in a way that is clearly portable (e.g.,
-  # no md5 sums of file paths).
-  def test_host_specific
-    client1 = "client1.example.com"
-    client2 = "client2.example.com"
-    ip = "127.0.0.1"
-
-    # Setup a directory hierarchy for the tests
-    fsdir = File.join(tmpdir, "host-specific")
-    @@tmpfiles << fsdir
-    hostdir = File.join(fsdir, "host")
-    fqdndir = File.join(fsdir, "fqdn")
-    client1_hostdir = File.join(hostdir, "client1")
-    client2_fqdndir = File.join(fqdndir, client2)
-    contents = {
-      client1_hostdir => "client1\n",
-      client2_fqdndir => client2 + "\n"
-    }
-    [fsdir, hostdir, fqdndir, client1_hostdir, client2_fqdndir].each { |d|  Dir.mkdir(d) }
-
-    [client1_hostdir, client2_fqdndir].each do |d|
-      File.open(File.join(d, "file.txt"), "w") do |f|
-        f.print contents[d]
-      end
-    end
-    conffile = tempfile
-    File.open(conffile, "w") do |f|
-      f.print("
-[host]
-path #{hostdir}/%h
-allow *
-[fqdn]
-path #{fqdndir}/%H
-allow *
-")
-  end
-
-  server = nil
-  assert_nothing_raised {
-
-    server = Puppet::Network::Handler.fileserver.new(
-
-      :Local => true,
-
-      :Config => conffile
-      )
-    }
-
-    # check that list returns the correct thing for the two clients
-    list = nil
-    sfile = "/host/file.txt"
-    assert_nothing_raised {
-      list = server.list(sfile, :manage, true, false, client1, ip)
-    }
-    assert_equal("/\tfile", list)
-    assert_nothing_raised {
-      list = server.list(sfile, :manage, true, false, client2, ip)
-    }
-    assert_equal("", list)
-
-    sfile = "/fqdn/file.txt"
-    assert_nothing_raised {
-      list = server.list(sfile, :manage, true, false, client1, ip)
-    }
-    assert_equal("", list)
-    assert_nothing_raised {
-      list = server.list(sfile, :manage, true, false, client2, ip)
-    }
-    assert_equal("/\tfile", list)
-
-    # check describe
-    sfile = "/host/file.txt"
-    assert_nothing_raised {
-      list = server.describe(sfile, :manage, client1, ip).split("\t")
-    }
-    assert_equal(5, list.size)
-    assert_equal("file", list[1])
-    md5 = Digest::MD5.hexdigest(contents[client1_hostdir])
-    assert_equal("{md5}#{md5}", list[4])
-
-    assert_nothing_raised {
-      list = server.describe(sfile, :manage, client2, ip).split("\t")
-    }
-    assert_equal([], list)
-
-    sfile = "/fqdn/file.txt"
-    assert_nothing_raised {
-      list = server.describe(sfile, :manage, client1, ip).split("\t")
-    }
-    assert_equal([], list)
-
-    assert_nothing_raised {
-      list = server.describe(sfile, :manage, client2, ip).split("\t")
-    }
-    assert_equal(5, list.size)
-    assert_equal("file", list[1])
-    md5 = Digest::MD5.hexdigest(contents[client2_fqdndir])
-    assert_equal("{md5}#{md5}", list[4])
-
-    # Check retrieve
-    sfile = "/host/file.txt"
-    assert_nothing_raised {
-      list = server.retrieve(sfile, :manage, client1, ip).chomp
-    }
-    assert_equal(contents[client1_hostdir].chomp, list)
-
-    assert_nothing_raised {
-      list = server.retrieve(sfile, :manage, client2, ip).chomp
-    }
-    assert_equal("", list)
-
-    sfile = "/fqdn/file.txt"
-    assert_nothing_raised {
-      list = server.retrieve(sfile, :manage, client1, ip).chomp
-    }
-    assert_equal("", list)
-
-    assert_nothing_raised {
-      list = server.retrieve(sfile, :manage, client2, ip).chomp
-    }
-    assert_equal(contents[client2_fqdndir].chomp, list)
-  end
-
-  # Make sure the 'subdir' method in Mount works.
-  def test_mount_subdir
-    mount = nil
-    base = tempfile
-    Dir.mkdir(base)
-    subdir = File.join(base, "subdir")
-    Dir.mkdir(subdir)
-    [base, subdir].each do |d|
-      File.open(File.join(d, "file"), "w") { |f| f.puts "bazoo" }
-    end
-    mount = mkmount(base)
-
-    assert_equal(base, mount.subdir, "Did not default to base path")
-    assert_equal(subdir, mount.subdir("subdir"), "Did not default to base path")
-  end
-
-  # Make sure mounts get correctly marked expandable or not, depending on
-  # the path.
-  def test_expandable
-    name = "yaytest"
-    dir = tempfile
-    Dir.mkdir(dir)
-
-    mount = mkmount
-    assert_nothing_raised {
-      mount.path = dir
-    }
-
-    assert(! mount.expandable?, "Mount incorrectly called expandable")
-
-    assert_nothing_raised {
-      mount.path = "/dir/a%a"
-    }
-    assert(mount.expandable?, "Mount not called expandable")
-
-    # This isn't a valid replacement pattern, so it should throw an error
-    # because the dir doesn't exist
-    assert_raise(Puppet::Network::Handler::FileServerError) {
-      mount.path = "/dir/a%"
-    }
-
-    # Now send it back to a normal path
-    assert_nothing_raised {
-      mount.path = dir
-    }
-    # Make sure it got reverted
-    assert(! mount.expandable?, "Mount incorrectly called expandable")
-
-
-  end
-
-  def test_mount_expand
-    mount = mkmount
-
-    check = proc do |client, pattern, repl|
-      path = "/my/#{pattern}/file"
-      assert_equal("/my/#{repl}/file", mount.expand(path, client))
-    end
-
-    # Do a round of checks with a fake client
-    client = "host.domain.com"
-    {"%h" => "host", # Short name
-    "%H" => client, # Full name
-    "%d" => "domain.com", # domain
-    "%%" => "%", # escape
-    "%o" => "%o" # other
-    }.each do |pat, repl|
-      result = check.call(client, pat, repl)
-    end
-
-    # Now, check that they use Facter info
-    client = nil
-    Facter.stubs(:value).with { |v| v.to_s == "hostname" }.returns("myhost")
-    Facter.stubs(:value).with { |v| v.to_s == "domain" }.returns("mydomain.com")
-
-
-      Facter.stubs(:to_hash).returns(
-        {
-          :ipaddress => "127.0.0.1",
-          :hostname => "myhost",
-          :domain   => "mydomain.com",
-
-    })
-
-
-    {"%h" => "myhost", # Short name
-    "%H" => "myhost.mydomain.com", # Full name
-    "%d" => "mydomain.com", # domain
-    "%%" => "%", # escape
-    "%o" => "%o" # other
-    }.each do |pat, repl|
-      check.call(client, pat, repl)
-    end
-
-  end
-
-  # Test that the fileserver expands the %h and %d things.
-  def test_fileserver_expansion
-    server = nil
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler.fileserver.new(
-
-        :Local => true,
-
-        :Config => false
-      )
-    }
-
-    dir = tempfile
-
-    # When mocks attack, part 2
-    kernel_fact = Facter.value(:kernel)
-
-    ip = '127.0.0.1'
-
-
-      Facter.stubs(:to_hash).returns(
-        {
-          :kernel => kernel_fact,
-          :ipaddress => "127.0.0.1",
-          :hostname => "myhost",
-          :domain   => "mydomain.com",
-
-    })
-
-    Dir.mkdir(dir)
-    host = "myhost.mydomain.com"
-    {
-      "%H" => "myhost.mydomain.com", "%h" => "myhost", "%d" => "mydomain.com"
-    }.each do |pattern, string|
-      file = File.join(dir, string)
-      mount = File.join(dir, pattern)
-      File.open(file, "w") do |f| f.puts "yayness: #{string}" end
-      name = "name"
-      obj = nil
-      assert_nothing_raised {
-        obj = server.mount(mount, name)
-      }
-      obj.allow "*"
-
-      ret = nil
-      assert_nothing_raised do
-        ret = server.list("/name", :manage, false, false, host, ip)
-      end
-
-      assert_equal("/\tfile", ret)
-
-      assert_nothing_raised do
-        ret = server.describe("/name", :manage, host, ip)
-      end
-      assert(ret =~ /\tfile\t/, "Did not get valid a description (#{ret.inspect})")
-
-      assert_nothing_raised do
-        ret = server.retrieve("/name", :manage, host, ip)
-      end
-
-      assert_equal(ret, File.read(file))
-
-      server.umount(name)
-
-      File.unlink(file)
-    end
-  end
-
-  # Test the default modules fileserving
-  def test_modules_default
-    moddir = tempfile
-    Dir.mkdir(moddir)
-    mounts = {}
-    Puppet[:modulepath] = moddir
-
-    mods = %w{green red}.collect do |name|
-      path = File::join(moddir, name, Puppet::Module::FILES)
-      FileUtils::mkdir_p(path)
-      if name == "green"
-        file = File::join(path, "test.txt")
-        File::open(file, "w") { |f| f.print name }
-      end
-
-      Puppet::Module::find(name)
-    end
-
-    conffile = tempfile
-
-    File.open(conffile, "w") { |f| f.puts "# a test config file" }
-
-    # create a server with the file
-    server = nil
-    assert_nothing_raised {
-
-      server = Puppet::Network::Handler::FileServer.new(
-
-        :Local => false ,
-
-        :Config => conffile
-      )
-    }
-
-    mods.each do |mod|
-      mount = "/#{mod.name}/"
-      list = nil
-      assert_nothing_raised {
-        list = server.list(mount, :manage, true, false)
-      }
-      list = list.split("\n")
-      if mod.name == "green"
-        assert_equal(2, list.size)
-        assert_equal("/\tdirectory", list[0])
-        assert_equal("/test.txt\tfile", list[1])
-      else
-        assert_equal(1, list.size)
-        assert_equal("/\tdirectory", list[0])
-      end
-
-      assert_nothing_raised("Host 'allow' denied #{mount}") {
-        server.list(mount, :manage, true, false, 'allow.example.com', "192.168.0.1")
-      }
-    end
-  end
-
-  # Test that configuring deny/allow for modules works
-  def test_modules_config
-    moddir = tempfile
-    Dir.mkdir(moddir)
-    mounts = {}
-    Puppet[:modulepath] = moddir
-
-    path = File::join(moddir, "amod", Puppet::Module::FILES)
-    file = File::join(path, "test.txt")
-    FileUtils::mkdir_p(path)
-    File::open(file, "w") { |f| f.print "Howdy" }
-
-    mod = Puppet::Module::find("amod")
-
-    conffile = tempfile
-    @@tmpfiles << conffile
-
-    File.open(conffile, "w") { |f|
-      f.print "# a test config file
-[modules]
-  path #{basedir}/thing
-  allow 192.168.0.*
-"
-  }
-
-  # create a server with the file
-  server = nil
-  assert_nothing_raised {
-
-    server = Puppet::Network::Handler::FileServer.new(
-
-      :Local => false,
-
-      :Config => conffile
-      )
-    }
-
-    list = nil
-    mount = "/#{mod.name}/"
-    assert_nothing_raised {
-      list = server.list(mount, :manage, true, false)
-    }
-
-    assert_nothing_raised {
-      list.split("\n").each { |line|
-        file, type = line.split("\t")
-        server.describe(mount + file)
-      }
-    }
-
-    assert_describe(mount, file, server)
-
-    # now let's check that things are being correctly forbidden
-
-      assert_raise(
-        Puppet::AuthorizationError,
-
-          "Host 'deny' allowed #{mount}") {
-            server.list(mount, :manage, true, false, 'deny.example.com', "192.168.1.1")
-    }
-    assert_nothing_raised("Host 'allow' denied #{mount}") {
-      server.list(mount, :manage, true, false, 'allow.example.com', "192.168.0.1")
-    }
-  end
-
-  # Make sure we successfully throw errors -- someone ran into this with
-  # 0.22.4.
-  def test_failures
-    # create a server with the file
-    server = nil
-
-    config = tempfile
-    [
-    "[this is invalid]\nallow one.two.com", # invalid name
-    "[valid]\nallow *.testing something.com", # invalid allow
-    "[valid]\nallow one.two.com\ndeny *.testing something.com", # invalid deny
-    ].each do |failer|
-      File.open(config, "w") { |f| f.puts failer }
-      assert_raise(Puppet::Network::Handler::FileServerError, "Did not fail on #{failer.inspect}") {
-
-        server = Puppet::Network::Handler::FileServer.new(
-
-          :Local => false,
-
-          :Config => config
-        )
-      }
-    end
-  end
-
-  def test_can_start_without_configuration
-    Puppet[:fileserverconfig] = tempfile
-    assert_nothing_raised("Could not create fileserver when configuration is absent") do
-      server = Puppet::Network::Handler::FileServer.new(
-        :Local => false
-        )
-    end
-  end
-
-  def test_creates_default_mounts_when_no_configuration_is_available
-    Puppet[:fileserverconfig] = tempfile
-    server = Puppet::Network::Handler::FileServer.new(:Local => false)
-
-    assert(server.mounted?("plugins"), "Did not create default plugins mount when missing configuration file")
-    assert(server.mounted?("modules"), "Did not create default modules mount when missing configuration file")
-  end
-end
-
-
diff --git a/test/network/handler/master.rb b/test/network/handler/master.rb
deleted file mode 100755
index 9326e4b..0000000
--- a/test/network/handler/master.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/handler/master'
-
-class TestMaster < Test::Unit::TestCase
-  include PuppetTest::ServerTest
-
-  def setup
-    super
-    @master = Puppet::Network::Handler.master.new(:Manifest => tempfile)
-
-    @catalog = stub 'catalog', :extract => ""
-    Puppet::Resource::Catalog.indirection.stubs(:find).returns(@catalog)
-  end
-
-  def test_freshness_is_always_now
-    now1 = mock 'now1'
-    Time.stubs(:now).returns(now1)
-
-    now1.expects(:to_i).returns 10
-
-    assert_equal(@master.freshness, 10, "Did not return current time as freshness")
-  end
-
-  def test_hostname_is_used_if_client_is_missing
-    @master.expects(:decode_facts).returns("hostname" => "yay")
-    facts = Puppet::Node::Facts.new("the_facts")
-    Puppet::Node::Facts.indirection.stubs(:save).with(facts)
-    Puppet::Node::Facts.expects(:new).with { |name, facts| name == "yay" }.returns(facts)
-
-    @master.getconfig("facts")
-  end
-
-  def test_facts_are_saved
-    facts = Puppet::Node::Facts.new("the_facts")
-    Puppet::Node::Facts.expects(:new).returns(facts)
-    Puppet::Node::Facts.indirection.expects(:save).with(facts)
-
-    @master.stubs(:decode_facts)
-
-    @master.getconfig("facts", "yaml", "foo.com")
-  end
-
-  def test_catalog_is_used_for_compiling
-    facts = Puppet::Node::Facts.new("the_facts")
-    Puppet::Node::Facts.indirection.stubs(:save).with(facts)
-    Puppet::Node::Facts.stubs(:new).returns(facts)
-
-    @master.stubs(:decode_facts)
-
-    Puppet::Resource::Catalog.indirection.expects(:find).with("foo.com").returns(@catalog)
-
-    @master.getconfig("facts", "yaml", "foo.com")
-  end
-end
-
-class TestMasterFormats < Test::Unit::TestCase
-  def setup
-    @facts = Puppet::Node::Facts.new("the_facts")
-    Puppet::Node::Facts.stubs(:new).returns(@facts)
-    Puppet::Node::Facts.indirection.stubs(:save)
-
-    @master = Puppet::Network::Handler.master.new(:Code => "")
-    @master.stubs(:decode_facts)
-
-    @catalog = stub 'catalog', :extract => ""
-    Puppet::Resource::Catalog.indirection.stubs(:find).returns(@catalog)
-  end
-
-  def test_marshal_can_be_used
-    @catalog.expects(:extract).returns "myextract"
-
-    Marshal.expects(:dump).with("myextract").returns "eh"
-
-    @master.getconfig("facts", "marshal", "foo.com")
-  end
-
-  def test_yaml_can_be_used
-    extract = mock 'extract'
-    @catalog.expects(:extract).returns extract
-
-    extract.expects(:to_yaml).returns "myaml"
-
-    @master.getconfig("facts", "yaml", "foo.com")
-  end
-
-  def test_failure_when_non_yaml_or_marshal_is_used
-    assert_raise(RuntimeError) { @master.getconfig("facts", "blah", "foo.com") }
-  end
-end
diff --git a/test/network/handler/report.rb b/test/network/handler/report.rb
deleted file mode 100755
index d0c2238..0000000
--- a/test/network/handler/report.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/handler/report'
-require 'puppettest/reporttesting'
-
-class TestReportServer < Test::Unit::TestCase
-  include PuppetTest
-  include PuppetTest::Reporttesting
-
-  Report = Puppet::Network::Handler.report
-  Puppet::Util.logmethods(self)
-
-  def mkserver
-    server = nil
-    assert_nothing_raised {
-      server = Puppet::Network::Handler.report.new
-    }
-    server
-  end
-
-  def mkclient(server = nil)
-    server ||= mkserver
-    client = nil
-    assert_nothing_raised {
-      client = Puppet::Network::Client.report.new(:Report => server)
-    }
-
-    client
-  end
-
-  def test_process
-    server = Puppet::Network::Handler.report.new
-
-    # We have to run multiple reports to make sure there's no conflict
-    reports = []
-    $run = []
-    2.times do |i|
-      name = "processtest#{i}"
-      reports << name
-
-      Report.newreport(name) do
-        def process
-          $run << self.report_name
-        end
-      end
-    end
-    Puppet[:reports] = reports.collect { |r| r.to_s }.join(",")
-
-    report = fakereport
-
-    retval = nil
-    assert_nothing_raised {
-      retval = server.send(:process, YAML.dump(report))
-    }
-
-    reports.each do |name|
-      assert($run.include?(name.intern), "Did not run #{name}")
-    end
-
-    # Now make sure our server doesn't die on missing reports
-    Puppet[:reports] = "fakereport"
-    assert_nothing_raised {
-      retval = server.send(:process, YAML.dump(report))
-    }
-  end
-
-  def test_reports
-    Puppet[:reports] = "myreport"
-
-    # Create a server
-    server = Puppet::Network::Handler.report.new
-
-    {"myreport" => ["myreport"],
-      " fake, another, yay " => ["fake", "another", "yay"]
-    }.each do |str, ary|
-      Puppet[:reports] = str
-      assert_equal(ary, server.send(:reports))
-    end
-  end
-end
diff --git a/test/network/handler/runner.rb b/test/network/handler/runner.rb
deleted file mode 100755
index d03fb2c..0000000
--- a/test/network/handler/runner.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/handler/runner'
-
-class TestHandlerRunner < Test::Unit::TestCase
-  include PuppetTest
-
-  def test_it_calls_agent_runner
-    runner = mock 'runner'
-    Puppet::Run.expects(:new).with(:tags => "mytags", :ignoreschedules => true, :background => false).returns runner
-    runner.expects(:run)
-    runner.expects(:status).returns "yay"
-
-
-    assert_equal("yay", Puppet::Network::Handler.runner.new.run("mytags", true, true))
-  end
-end
diff --git a/test/network/xmlrpc/processor.rb b/test/network/xmlrpc/processor.rb
deleted file mode 100755
index 379b34a..0000000
--- a/test/network/xmlrpc/processor.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/xmlrpc/processor'
-require 'mocha'
-
-class TestXMLRPCProcessor < Test::Unit::TestCase
-  include PuppetTest
-  class BaseProcessor
-    def add_handler(interface, handler)
-      @handlers ||= {}
-      @handlers[interface] = handler
-    end
-  end
-
-  # We use a base class just so super() works with add_handler.
-  class Processor < BaseProcessor
-    include Puppet::Network::XMLRPCProcessor
-
-    def set_service_hook(&block)
-      meta_def(:service, &block)
-    end
-  end
-
-  def setup
-    super
-    Puppet::Util::SUIDManager.stubs(:asuser).yields
-    @processor = Processor.new
-  end
-
-  def test_handlers
-    ca = Puppet::Network::Handler.ca
-    @processor.send(:setup_processor)
-    assert(! @processor.handler_loaded?(:ca), "already have ca handler loaded")
-    assert_nothing_raised do
-      @processor.add_handler(ca.interface, ca.new)
-    end
-
-    assert(@processor.handler_loaded?(:puppetca), "ca handler not loaded by symbol")
-    assert(@processor.handler_loaded?("puppetca"), "ca handler not loaded by string")
-  end
-
-  def test_process
-    ca = Puppet::Network::Handler.ca
-    @processor.send(:setup_processor)
-    assert_nothing_raised do
-      @processor.add_handler(ca.interface, ca.new)
-    end
-
-    fakeparser = Class.new do
-      def parseMethodCall(data)
-        data
-      end
-    end
-
-    request = Puppet::Network::ClientRequest.new("fake", "192.168.0.1", false)
-    request.handler = "myhandler"
-    request.method = "mymethod"
-
-    @processor.expects(:parser).returns(fakeparser.new)
-
-    request.expects(:handler=).with("myhandler")
-    request.expects(:method=).with("mymethod")
-
-    @processor.stubs(:verify)
-    @processor.expects(:handle).with(request.call, "params", request.name, request.ip)
-
-    @processor.send(:process, ["myhandler.mymethod", ["params"]], request)
-  end
-
-  def test_setup_processor
-    @processor.expects(:set_service_hook)
-    @processor.send(:setup_processor)
-  end
-end
-
-
diff --git a/test/network/xmlrpc/server.rb b/test/network/xmlrpc/server.rb
deleted file mode 100755
index 0653f00..0000000
--- a/test/network/xmlrpc/server.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/xmlrpc/server'
-require 'mocha'
-
-class TestXMLRPCServer < Test::Unit::TestCase
-  def setup
-    super
-    assert_nothing_raised do
-      @server = Puppet::Network::XMLRPCServer.new
-    end
-  end
-
-  def test_initialize
-    assert(@server.get_service_hook, "no service hook defined")
-
-    assert_nothing_raised("Did not init @loadedhandlers") do
-      assert(! @server.handler_loaded?(:puppetca), "server thinks handlers are loaded")
-    end
-  end
-end
-
-
diff --git a/test/network/xmlrpc/webrick_servlet.rb b/test/network/xmlrpc/webrick_servlet.rb
deleted file mode 100755
index f2faf09..0000000
--- a/test/network/xmlrpc/webrick_servlet.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppettest/support/utils'
-require 'puppet/network/xmlrpc/webrick_servlet'
-require 'mocha'
-
-class TestXMLRPCWEBrickServlet < Test::Unit::TestCase
-  include PuppetTest
-  def test_basics
-    # Make sure we're doing things as our user info, rather than puppet/puppet
-    setme
-    set_mygroup
-    Puppet[:user] = @me
-    Puppet[:group] = @mygroup
-    servlet = nil
-    ca = Puppet::Network::Handler.ca.new
-
-    assert_nothing_raised("Could not create servlet") do
-      servlet = Puppet::Network::XMLRPC::WEBrickServlet.new([ca])
-    end
-
-    assert(servlet.get_service_hook, "service hook was not set up")
-
-
-          assert(
-        servlet.handler_loaded?(:puppetca),
-        
-      "Did not load handler")
-  end
-end
-
-
diff --git a/test/util/pidlock.rb b/test/util/pidlock.rb
deleted file mode 100755
index beaff10..0000000
--- a/test/util/pidlock.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
-
-require 'puppet/util/pidlock'
-require 'fileutils'
-
-# This is *fucked* *up*
-Puppet.debug = false
-
-class TestPuppetUtilPidlock < Test::Unit::TestCase
-  include PuppetTest
-
-  def setup
-    super
-    @workdir = tstdir
-  end
-
-  def teardown
-    super
-    FileUtils.rm_rf(@workdir)
-  end
-
-  def test_00_basic_create
-    l = nil
-    assert_nothing_raised { l = Puppet::Util::Pidlock.new(@workdir + '/nothingmuch') }
-
-    assert_equal Puppet::Util::Pidlock, l.class
-
-    assert_equal @workdir + '/nothingmuch', l.lockfile
-  end
-
-  def test_10_uncontended_lock
-    l = Puppet::Util::Pidlock.new(@workdir + '/test_lock')
-
-    assert !l.locked?
-    assert !l.mine?
-    assert l.lock
-    assert l.locked?
-    assert l.mine?
-    assert !l.anonymous?
-    # It's OK to call lock multiple times
-    assert l.lock
-    assert l.unlock
-    assert !l.locked?
-    assert !l.mine?
-  end
-
-  def test_20_someone_elses_lock
-    childpid = nil
-    l = Puppet::Util::Pidlock.new(@workdir + '/someone_elses_lock')
-
-    # First, we need a PID that's guaranteed to be (a) used, (b) someone
-    # else's, and (c) around for the life of this test.
-    childpid = fork { loop do; sleep 10; end }
-
-    File.open(l.lockfile, 'w') { |fd| fd.write(childpid) }
-
-    assert l.locked?
-    assert !l.mine?
-    assert !l.lock
-    assert l.locked?
-    assert !l.mine?
-    assert !l.unlock
-    assert l.locked?
-    assert !l.mine?
-  ensure
-    Process.kill("KILL", childpid) unless childpid.nil?
-  end
-
-  def test_30_stale_lock
-    # This is a bit hard to guarantee, but we need a PID that is definitely
-    # unused, and will stay so for the the life of this test.  Our best
-    # bet is to create a process, get it's PID, let it die, and *then*
-    # lock on it.
-    childpid = fork { exit }
-
-    # Now we can't continue until we're sure that the PID is dead
-    Process.wait(childpid)
-
-    l = Puppet::Util::Pidlock.new(@workdir + '/stale_lock')
-
-    # locked? should clear the lockfile
-    File.open(l.lockfile, 'w') { |fd| fd.write(childpid) }
-    assert File.exists?(l.lockfile)
-    assert !l.locked?
-    assert !File.exists?(l.lockfile)
-
-    # lock should replace the lockfile with our own
-    File.open(l.lockfile, 'w') { |fd| fd.write(childpid) }
-    assert File.exists?(l.lockfile)
-    assert l.lock
-    assert l.locked?
-    assert l.mine?
-
-    # unlock should fail, and should *not* molest the existing lockfile,
-    # despite it being stale
-    File.open(l.lockfile, 'w') { |fd| fd.write(childpid) }
-    assert File.exists?(l.lockfile)
-    assert !l.unlock
-    assert File.exists?(l.lockfile)
-  end
-
-  def test_40_not_locked_at_all
-    l = Puppet::Util::Pidlock.new(@workdir + '/not_locked')
-
-    assert !l.locked?
-    # We can't unlock if we don't hold the lock
-    assert !l.unlock
-  end
-
-  def test_50_anonymous_lock
-    l = Puppet::Util::Pidlock.new(@workdir + '/anonymous_lock')
-
-    assert !l.locked?
-    assert l.lock(:anonymous => true)
-    assert l.locked?
-    assert l.anonymous?
-    assert !l.mine?
-    assert "", File.read(l.lockfile)
-    assert !l.unlock
-    assert l.locked?
-    assert l.anonymous?
-    assert l.unlock(:anonymous => true)
-    assert !File.exists?(l.lockfile)
-  end
-end
-

    

Reply all
Reply to author
Forward
0 new messages