13 changes: 4 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
.rspec
results
.*.sw[op]
*~
\.\#*
\#*\#
*elc
auto-save-list

pkg/
.DS_Store
metadata.json
coverage/
51 changes: 51 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
2012-05-16 - Jeff McCune <jeff@puppetlabs.com>
* (#14529) Add registry::value defined type (bf44208)

2012-05-16 - Josh Cooper <josh+github@puppetlabs.com>
* Update README.markdown (2e9e45e)

2012-05-16 - Josh Cooper <josh+github@puppetlabs.com>
* Update README.markdown (3904838)

2012-05-15 - Josh Cooper <josh@puppetlabs.com>
* (Maint) Add type documentation (82205ad)

2012-05-15 - Josh Cooper <josh+github@puppetlabs.com>
* Remove note about case-sensitivity, as that is no longer an issue (5440a0e)

2012-05-15 - Jeff McCune <jeff@puppetlabs.com>
* (#14501) Fix autorequire case sensitivity (d5c12f0)

2012-05-15 - Jeff McCune <jeff@puppetlabs.com>
* (maint) Remove RegistryKeyPath#{valuename,default?} methods (29db478)

2012-05-14 - Jeff McCune <jeff@puppetlabs.com>
* Add acceptance tests for registry_value provider (6285f4a)

2012-05-14 - Jeff McCune <jeff@puppetlabs.com>
* Eliminate RegistryPathBas#(default?,valuename) from base class (2234f96)

2012-05-14 - Jeff McCune <jeff@puppetlabs.com>
* Memoize the filter_path method for performance (6139b7d)

2012-05-11 - Jeff McCune <jeff@puppetlabs.com>
* Add Registry_key ensure => absent and purge_values coverage (cfd3789)

2012-05-11 - Jeff McCune <jeff@puppetlabs.com>
* Fix cannot alias error when managing 32 and 64 bit versions of a key (3a2f260)

2012-05-11 - Jeff McCune <jeff@puppetlabs.com>
* Add registry_key creation acceptance test (0e68654)

2012-05-09 - Jeff McCune <jeff@puppetlabs.com>
* Add acceptance tests for the registry type (0a01b11)

2012-05-08 - Jeff McCune <jeff@puppetlabs.com>
* Update type description strings (c69bf2d)

2012-05-05 - Jeff McCune <jeff@puppetlabs.com>
* Separate the implementation of the type and provider (4e06ae5)

2012-05-04 - Jeff McCune <jeff@puppetlabs.com>
* Add watchr script to automatically run tests (d5bce2d)

2012-05-04 - Jeff McCune <jeff@puppetlabs.com>
* Add registry::compliance_example class to test compliance (0aa8a68)

Expand Down
4 changes: 2 additions & 2 deletions Modulefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name 'puppetlabs-registry'
version '0.0.1'
version '0.1.0'
source 'git://github.com/puppetlabs/puppetlabs-registry.git'
author 'puppetlabs'
license 'Apache License, Version 2.0'
Expand All @@ -8,4 +8,4 @@ description 'This module provides a native type and provider to manage keys and
project_page 'http://links.puppetlabs.com/registry-module'

## Add dependencies, if any:
# dependency 'username/name', '>= 1.2.0'
dependency 'puppetlabs/stdlib', '>= 2.3.0'
57 changes: 30 additions & 27 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ Installation
------------

The best way to install this module is with the `puppet module` subcommand or
the `puppet-module` Gem.
the `puppet-module` Gem. On your puppet master, execute the following command,
optionally specifying your puppet master's `modulepath` in which to install the module:

puppet module install puppetlabs-registry
$ puppet module install [--modulepath <path>] puppetlabs-registry

See the section [Installing Modules](http://docs.puppetlabs.com/puppet/2.7/reference/modules_installing.html#installing-modules-1) for more information.

Make sure your `puppet agent` is configured to synchronize plugins using the
setting:
Expand Down Expand Up @@ -47,6 +50,23 @@ The `registry_key` and `registry_value` types are provided by this module.
data => "The Puppet Agent service periodically manages your configuration",
}

The `registry::value` defined resource type provides a convenient way to manage
values and the parent key:

registry::value { 'MyApp Setting1':
key => 'HKLM\Software\Vendor\PuppetLabs',
value => setting1,
data => 'Hello World!'
}

With this single resource declaration both the `registry_key` of
`HKLM\Software\Vendor\PuppetLabs` and the `registry_value` of
`HKLM\Software\Vendor\PuppetLabs\setting` will be managed.

The `registry::value` defined type only managed keys and values in the system
native architecture. That is to say, the 32 bit keys won't be managed by this
defined type on a 64 bit OS.

Purge Values Example
--------------------

Expand Down Expand Up @@ -87,30 +107,6 @@ Notice how Value4, Value5 and Value6 are being removed.
notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value1]/data: data changed '1' to '0'
notice: Finished catalog run in 0.16 seconds

Compliance Example
------------------

In order to use the Registry module with the Compliance feature of Puppet
Enterprise, the `audit` metaparameter should be used with specific
`registry_value` resources. An example of this is provided in the
`registry::compliance_example` class.

To get started:

1. First, add the `registry::compliance_example` class to a node.
2. Then, run `puppet agent --test` on the Windows node to setup a hierarchy of
keys in `HKLM\Software\Vendor\Puppet Labs\Examples\Compliance`
3. Switch the `registry::compliance_example` class into audit mode by setting
a Facter fact: `$env:FACTER_REGISTRY_COMPLIANCE_EXAMPLE_MODE='audit'`.
4. Get the new catalog containing the audit resources using: `puppet agent
--test`.
5. Manually change a registry value inside of `HKLM\Software\Vendor\Puppet
Labs\Examples\Compliance`.
6. Run `puppet inspect` and notice that Puppet has picked up the manual change
and set it to the Puppet Enterprise Console as an inspect report.

![Registry Value Inspect Report](http://links.puppetlabs.com/screen_shot_registry_value_audit_01.png)

License
-------

Expand All @@ -129,4 +125,11 @@ Support
-------

Please log tickets and issues at our [Module Issue
Tracker](http://projects.puppetlabs.com/projects/modules)
Tracker](http://projects.puppetlabs.com/projects/modules).

Known Issues
============

Please refer to the [current list](http://projects.puppetlabs.com/projects/modules/issues?v%5Bcategory_id%5D%5B%5D=309) of known registry issues.

EOF
2 changes: 2 additions & 0 deletions acceptance/lib/systest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Systest
end
4 changes: 4 additions & 0 deletions acceptance/lib/systest/util.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require 'pathname'
require Pathname.new(__FILE__).dirname
module Systest::Util
end
157 changes: 157 additions & 0 deletions acceptance/lib/systest/util/registry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
require 'pathname'
require Pathname.new(__FILE__).dirname
# This module is meant to be mixed into the individual test cases for the
# registry module.
module Systest::Util::Registry
# Given a relative path, returns an absolute path for a test file.
# Basically, this just prepends the a unique temp dir path (specific to the
# current test execution) to your relative path.
def get_test_file_path(host, file_rel_path)
File.join(host_test_tmp_dirs[host.name], file_rel_path)
end

def cur_test_file
@path
end

def cur_test_file_shortname
File.basename(cur_test_file, File.extname(cur_test_file))
end

def tmpdir(host, basename)
host_tmpdir = host.tmpdir(basename)
# we need to make sure that the puppet user can traverse this directory...
chmod(host, "755", host_tmpdir)
host_tmpdir
end

def mkdirs(host, dir_path)
on(host, "mkdir -p #{dir_path}")
end

def chown(host, owner, group, path)
on(host, "chown #{owner}:#{group} #{path}")
end

def chmod(host, mode, path)
on(host, "chmod #{mode} #{path}")
end

def all_hosts
# we need one list of all of the hosts, to assist in managing temp dirs. It's possible
# that the master is also an agent, so this will consolidate them into a unique set
@all_hosts ||= Set[master, *agents]
end

def host_test_tmp_dirs
# now we can create a hash of temp dirs--one per host, and unique to this test--without worrying about
# doing it twice on any individual host
@host_test_tmp_dirs ||= Hash[all_hosts.map do |host| [host.name, tmpdir(host, cur_test_file_shortname)] end ]
end

def master_manifest_dir
@master_manifest_dir ||= "master_manifest"
end

def master_module_dir
@master_module_dir ||= "master_modules"
end

def master_manifest_file
@master_manifest_file ||= "#{master_manifest_dir}/site.pp"
end

def agent_args
@agent_args ||= "--trace --libdir=\"%s\" --pluginsync --no-daemonize --verbose --onetime --test --server #{master}"
end

def agent_lib_dir
@agent_lib_dir ||= "agent_lib"
end

def masters
@masters ||= hosts.select { |host| host['roles'].include? 'master' }
end

def windows_agents
agents.select { |agent| agent['platform'].include?('windows') }
end

def master_options
@master_options ||= "--manifest=\"#{get_test_file_path(master, master_manifest_file)}\" " +
"--modulepath=\"#{get_test_file_path(master, master_module_dir)}\" " +
"--autosign true --pluginsync"
end

def agent_exit_codes
# legal exit codes whenever we run the agent
# we need to allow exit code 2, which means "changes were applied" on the agent
@agent_exit_codes ||= [0, 2]
end

def randomstring(length)
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
str = ""
1.upto(length) { |i| str << chars[rand(chars.size-1)] }
return str
end

# Create a file on the host.
# Parameters:
# [host] the host to create the file on
# [file_path] the path to the file to be created
# [file_content] a string containing the contents to be written to the file
# [options] a hash containing additional behavior options. Currently supported:
# * :mkdirs (default false) if true, attempt to create the parent directories on the remote host before writing
# the file
# * :owner (default 'root') the username of the user that the file should be owned by
# * :group (default 'puppet') the name of the group that the file should be owned by
# * :mode (default '644') the mode (file permissions) that the file should be created with
def create_test_file(host, file_rel_path, file_content, options)

# set default options
options[:mkdirs] ||= false
options[:owner] ||= (host['user'] || "root")
options[:group] ||= (host['group'] || "puppet")
options[:mode] ||= "755"

file_path = get_test_file_path(host, file_rel_path)

mkdirs(host, File.dirname(file_path)) if (options[:mkdirs] == true)
create_remote_file(host, file_path, file_content)
#
# NOTE: we need these chown/chmod calls because the acceptance framework connects to the nodes as "root", but
# puppet 'master' runs as user 'puppet'. Therefore, in order for puppet master to be able to read any files
# that we've created, we have to carefully set their permissions
#
chown(host, options[:owner], options[:group], file_path)
chmod(host, options[:mode], file_path)
end

def setup_master(master_manifest_content="# Intentionally Blank\n")
step "Setup Puppet Master Manifest" do
masters.each do |host|
create_test_file(host, master_manifest_file, master_manifest_content, :mkdirs => true)
end
end
step "Symlink the module(s) into the master modulepath" do
masters.each do |host|
moddir = get_test_file_path(host, master_module_dir)
mkdirs(host, moddir)
on host, "ln -s /opt/puppet-git-repos/stdlib \"#{moddir}/stdlib\"; ln -s /opt/puppet-git-repos/registry \"#{moddir}/registry\""
end
end
end

def clean_up
step "Clean Up" do
masters.each do |host|
on host, "rm -rf \"%s\"" % get_test_file_path(host, '')
end
agents.each do |host|
on host, "rm -rf \"%s\"" % get_test_file_path(host, '')
end
end
end
end

Loading